mirror of
https://github.com/juce-framework/JUCE.git
synced 2026-01-15 00:24:19 +00:00
Changed the way Mac messaging works internally to avoid shutdown problems with plugins. Updated some iPhone code. Fixed a CoreGraphics line drawing problem.
This commit is contained in:
parent
9929d71c27
commit
802f850015
15 changed files with 422 additions and 415 deletions
|
|
@ -16344,6 +16344,7 @@ bool JUCEApplication::initialiseApp (String& commandLine)
|
|||
|
||||
initialiseJuce_GUI();
|
||||
|
||||
#if ! JUCE_IPHONE
|
||||
jassert (appLock == 0); // initialiseApp must only be called once!
|
||||
|
||||
if (! moreThanOneInstanceAllowed())
|
||||
|
|
@ -16361,6 +16362,7 @@ bool JUCEApplication::initialiseApp (String& commandLine)
|
|||
return false;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
// let the app do its setting-up..
|
||||
initialise (commandLineParameters);
|
||||
|
|
@ -16439,9 +16441,9 @@ int JUCEApplication::main (int argc, char* argv[],
|
|||
return juce_IPhoneMain (argc, argv, newApp);
|
||||
#else
|
||||
|
||||
#if JUCE_MAC
|
||||
#if JUCE_MAC
|
||||
const ScopedAutoReleasePool pool;
|
||||
#endif
|
||||
#endif
|
||||
|
||||
String cmd;
|
||||
for (int i = 1; i < argc; ++i)
|
||||
|
|
@ -37105,9 +37107,12 @@ void MessageManager::deliverMessage (void* message)
|
|||
{
|
||||
quitMessageReceived = true;
|
||||
}
|
||||
else if (dynamic_cast <CallbackMessage*> (m) != 0)
|
||||
else
|
||||
{
|
||||
(dynamic_cast <CallbackMessage*> (m))->messageCallback();
|
||||
CallbackMessage* const cm = dynamic_cast <CallbackMessage*> (m);
|
||||
|
||||
if (cm != 0)
|
||||
cm->messageCallback();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -51370,6 +51375,9 @@ public:
|
|||
atom->getText (passwordCharacter),
|
||||
atomX, 0.0f);
|
||||
|
||||
if (indexToFind - indexInText >= g.getNumGlyphs())
|
||||
return atomRight;
|
||||
|
||||
return jmin (atomRight, g.getGlyph (indexToFind - indexInText).getLeft());
|
||||
}
|
||||
|
||||
|
|
@ -51387,7 +51395,7 @@ public:
|
|||
atomX, 0.0f);
|
||||
|
||||
int j;
|
||||
for (j = 0; j < atom->numChars; ++j)
|
||||
for (j = 0; j < g.getNumGlyphs(); ++j)
|
||||
if ((g.getGlyph(j).getLeft() + g.getGlyph(j).getRight()) / 2 > xToFind)
|
||||
break;
|
||||
|
||||
|
|
@ -86573,7 +86581,7 @@ void GlyphArrangement::addGlyphArrangement (const GlyphArrangement& other) throw
|
|||
|
||||
void GlyphArrangement::removeRangeOfGlyphs (int startIndex, const int num) throw()
|
||||
{
|
||||
glyphs.removeRange (startIndex, num);
|
||||
glyphs.removeRange (startIndex, num < 0 ? glyphs.size() : num);
|
||||
}
|
||||
|
||||
void GlyphArrangement::addLineOfText (const Font& font,
|
||||
|
|
@ -86635,22 +86643,13 @@ void GlyphArrangement::addCurtailedLineOfText (const Font& font,
|
|||
|
||||
void GlyphArrangement::appendEllipsis (const Font& font, const float maxXPixels) throw()
|
||||
{
|
||||
//const TypefaceGlyphInfo* const dotGlyph = font.getTypeface()->getGlyph (T('.'));
|
||||
|
||||
if (/*dotGlyph != 0 &&*/ glyphs.size() > 0)
|
||||
if (glyphs.size() > 0)
|
||||
{
|
||||
//PositionedGlyph* glyph = glyphs.getLast();
|
||||
//const float fontHeight = glyph->font.getHeight();
|
||||
//const float fontHorizontalScale = glyph->font.getHorizontalScale();
|
||||
|
||||
Array<int> dotGlyphs;
|
||||
Array<float> dotXs;
|
||||
font.getGlyphPositions (T(".."), dotGlyphs, dotXs);
|
||||
|
||||
const float dx = dotXs[1];
|
||||
//fontHeight * fontHorizontalScale
|
||||
// * (font.getExtraKerningFactor() + dotGlyph->getHorizontalSpacing (T('.')));
|
||||
|
||||
float xOffset = 0.0f, yOffset = 0.0f;
|
||||
|
||||
for (int dotPos = 3; --dotPos >= 0 && glyphs.size() > 0;)
|
||||
|
|
@ -86971,7 +86970,7 @@ void GlyphArrangement::addFittedText (const Font& f,
|
|||
|
||||
if (startIndex < glyphs.size())
|
||||
{
|
||||
glyphs.removeRange (startIndex, glyphs.size());
|
||||
removeRangeOfGlyphs (startIndex, -1);
|
||||
|
||||
if (startIndex - originalStartIndex > 4)
|
||||
{
|
||||
|
|
@ -88108,8 +88107,8 @@ const AffineTransform AffineTransform::rotation (const float angle,
|
|||
const AffineTransform AffineTransform::scaled (const float factorX,
|
||||
const float factorY) const throw()
|
||||
{
|
||||
return followedBy (factorX, 0, 0,
|
||||
0, factorY, 0);
|
||||
return AffineTransform (factorX * mat00, factorX * mat01, factorX * mat02,
|
||||
factorY * mat10, factorY * mat11, factorY * mat12);
|
||||
}
|
||||
|
||||
const AffineTransform AffineTransform::scale (const float factorX,
|
||||
|
|
@ -234768,6 +234767,10 @@ END_JUCE_NAMESPACE
|
|||
|
||||
BEGIN_JUCE_NAMESPACE
|
||||
|
||||
#if JUCE_USE_CDBURNER
|
||||
|
||||
#endif
|
||||
|
||||
#define JUCE_INCLUDED_FILE 1
|
||||
|
||||
// Now include the actual code files..
|
||||
|
|
@ -251372,8 +251375,6 @@ WaitableEvent::~WaitableEvent() throw()
|
|||
bool WaitableEvent::wait (const int timeOutMillisecs) const throw()
|
||||
{
|
||||
EventStruct* const es = (EventStruct*) internal;
|
||||
|
||||
bool ok = true;
|
||||
pthread_mutex_lock (&es->mutex);
|
||||
|
||||
if (timeOutMillisecs < 0)
|
||||
|
|
@ -251400,16 +251401,15 @@ bool WaitableEvent::wait (const int timeOutMillisecs) const throw()
|
|||
|
||||
if (pthread_cond_timedwait (&es->condition, &es->mutex, &time) == ETIMEDOUT)
|
||||
{
|
||||
ok = false;
|
||||
break;
|
||||
pthread_mutex_unlock (&es->mutex);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
es->triggered = false;
|
||||
|
||||
pthread_mutex_unlock (&es->mutex);
|
||||
return ok;
|
||||
return true;
|
||||
}
|
||||
|
||||
void WaitableEvent::signal() const throw()
|
||||
|
|
@ -253515,7 +253515,7 @@ void MessageManager::doPlatformSpecificShutdown()
|
|||
}
|
||||
}
|
||||
|
||||
bool juce_postMessageToSystemQueue (void* message)
|
||||
bool juce_postMessageToSystemQueue (Message* message)
|
||||
{
|
||||
if (errorCondition)
|
||||
return false;
|
||||
|
|
@ -260845,8 +260845,6 @@ WaitableEvent::~WaitableEvent() throw()
|
|||
bool WaitableEvent::wait (const int timeOutMillisecs) const throw()
|
||||
{
|
||||
EventStruct* const es = (EventStruct*) internal;
|
||||
|
||||
bool ok = true;
|
||||
pthread_mutex_lock (&es->mutex);
|
||||
|
||||
if (timeOutMillisecs < 0)
|
||||
|
|
@ -260873,16 +260871,15 @@ bool WaitableEvent::wait (const int timeOutMillisecs) const throw()
|
|||
|
||||
if (pthread_cond_timedwait (&es->condition, &es->mutex, &time) == ETIMEDOUT)
|
||||
{
|
||||
ok = false;
|
||||
break;
|
||||
pthread_mutex_unlock (&es->mutex);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
es->triggered = false;
|
||||
|
||||
pthread_mutex_unlock (&es->mutex);
|
||||
return ok;
|
||||
return true;
|
||||
}
|
||||
|
||||
void WaitableEvent::signal() const throw()
|
||||
|
|
@ -261790,10 +261787,9 @@ END_JUCE_NAMESPACE
|
|||
- (void) applicationDidFinishLaunching: (UIApplication*) application
|
||||
{
|
||||
String dummy;
|
||||
|
||||
if (! juce_intialisingApp->initialiseApp (dummy))
|
||||
{
|
||||
// (should quit)
|
||||
}
|
||||
exit (0);
|
||||
}
|
||||
|
||||
- (void) applicationWillResignActive: (UIApplication*) application
|
||||
|
|
@ -263076,7 +263072,7 @@ public:
|
|||
|
||||
void drawHorizontalLine (const int y, double left, double right)
|
||||
{
|
||||
CGContextFillRect (context, CGRectMake (left, y, right - left, 1.0f));
|
||||
CGContextFillRect (context, CGRectMake (left, flipHeight - (y + 1.0f), right - left, 1.0f));
|
||||
}
|
||||
|
||||
void setFont (const Font& newFont)
|
||||
|
|
@ -263470,7 +263466,7 @@ public:
|
|||
|
||||
UIWindow* window;
|
||||
JuceUIView* view;
|
||||
bool isSharedWindow, fullScreen;
|
||||
bool isSharedWindow, fullScreen, insideDrawRect;
|
||||
};
|
||||
|
||||
END_JUCE_NAMESPACE
|
||||
|
|
@ -263673,7 +263669,8 @@ UIViewComponentPeer::UIViewComponentPeer (Component* const component,
|
|||
window (0),
|
||||
view (0),
|
||||
isSharedWindow (viewToAttachTo != 0),
|
||||
fullScreen (false)
|
||||
fullScreen (false),
|
||||
insideDrawRect (false)
|
||||
{
|
||||
CGRect r;
|
||||
r.origin.x = 0;
|
||||
|
|
@ -264058,7 +264055,10 @@ void UIViewComponentPeer::drawRect (CGRect r)
|
|||
|
||||
CGContextConcatCTM (cg, CGAffineTransformMake (1, 0, 0, -1, 0, view.bounds.size.height));
|
||||
CoreGraphicsContext g (cg, view.bounds.size.height);
|
||||
|
||||
insideDrawRect = true;
|
||||
handlePaint (g);
|
||||
insideDrawRect = false;
|
||||
}
|
||||
|
||||
bool UIViewComponentPeer::canBecomeKeyWindow()
|
||||
|
|
@ -264084,19 +264084,33 @@ void juce_setKioskComponent (Component* kioskModeComponent, bool enableOrDisable
|
|||
{
|
||||
}
|
||||
|
||||
class AsyncRepaintMessage : public CallbackMessage
|
||||
{
|
||||
public:
|
||||
UIViewComponentPeer* const peer;
|
||||
const Rectangle rect;
|
||||
|
||||
AsyncRepaintMessage (UIViewComponentPeer* const peer_, const Rectangle& rect_)
|
||||
: peer (peer_), rect (rect_)
|
||||
{
|
||||
}
|
||||
|
||||
void messageCallback()
|
||||
{
|
||||
if (ComponentPeer::isValidPeer (peer))
|
||||
peer->repaint (rect.getX(), rect.getY(), rect.getWidth(), rect.getHeight());
|
||||
}
|
||||
};
|
||||
|
||||
void UIViewComponentPeer::repaint (int x, int y, int w, int h)
|
||||
{
|
||||
CGRect r = CGRectMake ((float) x, (float) y, (float) w, (float) h);
|
||||
|
||||
if (! MessageManager::getInstance()->isThisTheMessageThread())
|
||||
if (insideDrawRect || ! MessageManager::getInstance()->isThisTheMessageThread())
|
||||
{
|
||||
[view performSelectorOnMainThread: @selector (asyncRepaint:)
|
||||
withObject: [NSData dataWithBytes: &r length: sizeof (r)]
|
||||
waitUntilDone: NO];
|
||||
(new AsyncRepaintMessage (this, Rectangle (x, y, w, h)))->post();
|
||||
}
|
||||
else
|
||||
{
|
||||
[view setNeedsDisplayInRect: r];
|
||||
[view setNeedsDisplayInRect: CGRectMake ((float) x, (float) y, (float) w, (float) h)];
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -264199,83 +264213,11 @@ struct CallbackMessagePayload
|
|||
bool volatile hasBeenExecuted;
|
||||
};
|
||||
|
||||
/* When you use multiple DLLs which share similarly-named obj-c classes - like
|
||||
for example having more than one juce plugin loaded into a host, then when a
|
||||
method is called, the actual code that runs might actually be in a different module
|
||||
than the one you expect... So any calls to library functions or statics that are
|
||||
made inside obj-c methods will probably end up getting executed in a different DLL's
|
||||
memory space. Not a great thing to happen - this obviously leads to bizarre crashes.
|
||||
|
||||
To work around this insanity, I'm only allowing obj-c methods to make calls to
|
||||
virtual methods of an object that's known to live inside the right module's space.
|
||||
*/
|
||||
class AppDelegateRedirector
|
||||
{
|
||||
public:
|
||||
AppDelegateRedirector() {}
|
||||
virtual ~AppDelegateRedirector() {}
|
||||
|
||||
virtual BOOL openFile (const NSString* filename)
|
||||
{
|
||||
if (JUCEApplication::getInstance() != 0)
|
||||
{
|
||||
JUCEApplication::getInstance()->anotherInstanceStarted (nsStringToJuce (filename));
|
||||
return YES;
|
||||
}
|
||||
|
||||
return NO;
|
||||
}
|
||||
|
||||
virtual void openFiles (NSArray* filenames)
|
||||
{
|
||||
StringArray files;
|
||||
for (unsigned int i = 0; i < [filenames count]; ++i)
|
||||
files.add (nsStringToJuce ((NSString*) [filenames objectAtIndex: i]));
|
||||
|
||||
if (files.size() > 0 && JUCEApplication::getInstance() != 0)
|
||||
{
|
||||
JUCEApplication::getInstance()->anotherInstanceStarted (files.joinIntoString (T(" ")));
|
||||
}
|
||||
}
|
||||
|
||||
virtual void focusChanged()
|
||||
{
|
||||
juce_HandleProcessFocusChange();
|
||||
}
|
||||
|
||||
virtual void deliverMessage (void* message)
|
||||
{
|
||||
// no need for an mm lock here - deliverMessage locks it
|
||||
MessageManager::getInstance()->deliverMessage (message);
|
||||
}
|
||||
|
||||
virtual void performCallback (CallbackMessagePayload* pl)
|
||||
{
|
||||
pl->result = (*pl->function) (pl->parameter);
|
||||
pl->hasBeenExecuted = true;
|
||||
}
|
||||
|
||||
virtual void deleteSelf()
|
||||
{
|
||||
delete this;
|
||||
}
|
||||
};
|
||||
|
||||
END_JUCE_NAMESPACE
|
||||
using namespace JUCE_NAMESPACE;
|
||||
|
||||
#define JuceAppDelegate MakeObjCClassName(JuceAppDelegate)
|
||||
|
||||
static int numPendingMessages = 0;
|
||||
|
||||
@interface JuceAppDelegate : NSObject <UIApplicationDelegate>
|
||||
{
|
||||
@private
|
||||
id oldDelegate;
|
||||
AppDelegateRedirector* redirector;
|
||||
|
||||
@public
|
||||
bool flushingMessages;
|
||||
}
|
||||
|
||||
- (JuceAppDelegate*) init;
|
||||
|
|
@ -264286,7 +264228,6 @@ static int numPendingMessages = 0;
|
|||
- (void) applicationWillUnhide: (NSNotification*) aNotification;
|
||||
- (void) customEvent: (id) data;
|
||||
- (void) performCallback: (id) info;
|
||||
- (void) dummyMethod;
|
||||
@end
|
||||
|
||||
@implementation JuceAppDelegate
|
||||
|
|
@ -264295,11 +264236,6 @@ static int numPendingMessages = 0;
|
|||
{
|
||||
[super init];
|
||||
|
||||
redirector = new AppDelegateRedirector();
|
||||
numPendingMessages = 0;
|
||||
flushingMessages = false;
|
||||
|
||||
oldDelegate = [[UIApplication sharedApplication] delegate];
|
||||
[[UIApplication sharedApplication] setDelegate: self];
|
||||
|
||||
return self;
|
||||
|
|
@ -264307,44 +264243,45 @@ static int numPendingMessages = 0;
|
|||
|
||||
- (void) dealloc
|
||||
{
|
||||
if (oldDelegate != 0)
|
||||
[[UIApplication sharedApplication] setDelegate: oldDelegate];
|
||||
|
||||
redirector->deleteSelf();
|
||||
[[UIApplication sharedApplication] setDelegate: nil];
|
||||
[super dealloc];
|
||||
}
|
||||
|
||||
- (BOOL) application: (UIApplication*) application handleOpenURL: (NSURL*) url
|
||||
{
|
||||
return redirector->openFile ([url absoluteString]);
|
||||
if (JUCEApplication::getInstance() != 0)
|
||||
{
|
||||
JUCEApplication::getInstance()->anotherInstanceStarted (nsStringToJuce ([url absoluteString]));
|
||||
return YES;
|
||||
}
|
||||
|
||||
return NO;
|
||||
}
|
||||
|
||||
- (void) applicationDidBecomeActive: (NSNotification*) aNotification
|
||||
{
|
||||
redirector->focusChanged();
|
||||
juce_HandleProcessFocusChange();
|
||||
}
|
||||
|
||||
- (void) applicationDidResignActive: (NSNotification*) aNotification
|
||||
{
|
||||
redirector->focusChanged();
|
||||
juce_HandleProcessFocusChange();
|
||||
}
|
||||
|
||||
- (void) applicationWillUnhide: (NSNotification*) aNotification
|
||||
{
|
||||
redirector->focusChanged();
|
||||
juce_HandleProcessFocusChange();
|
||||
}
|
||||
|
||||
- (void) customEvent: (id) n
|
||||
{
|
||||
atomicDecrement (numPendingMessages);
|
||||
|
||||
NSData* data = (NSData*) n;
|
||||
void* message = 0;
|
||||
[data getBytes: &message length: sizeof (message)];
|
||||
[data release];
|
||||
|
||||
if (message != 0 && ! flushingMessages)
|
||||
redirector->deliverMessage (message);
|
||||
if (message != 0)
|
||||
MessageManager::getInstance()->deliverMessage (message);
|
||||
}
|
||||
|
||||
- (void) performCallback: (id) info
|
||||
|
|
@ -264354,7 +264291,10 @@ static int numPendingMessages = 0;
|
|||
CallbackMessagePayload* pl = (CallbackMessagePayload*) [((NSData*) info) bytes];
|
||||
|
||||
if (pl != 0)
|
||||
redirector->performCallback (pl);
|
||||
{
|
||||
pl->result = (*pl->function) (pl->parameter);
|
||||
pl->hasBeenExecuted = true;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
|
|
@ -264362,8 +264302,6 @@ static int numPendingMessages = 0;
|
|||
}
|
||||
}
|
||||
|
||||
- (void) dummyMethod {} // (used as a way of running a dummy thread)
|
||||
|
||||
@end
|
||||
|
||||
BEGIN_JUCE_NAMESPACE
|
||||
|
|
@ -264373,7 +264311,6 @@ static JuceAppDelegate* juceAppDelegate = 0;
|
|||
void MessageManager::runDispatchLoop()
|
||||
{
|
||||
jassert (isThisTheMessageThread()); // must only be called by the message thread
|
||||
|
||||
runDispatchLoopUntil (-1);
|
||||
}
|
||||
|
||||
|
|
@ -264406,30 +264343,61 @@ bool MessageManager::runDispatchLoopUntil (int millisecondsToRunFor)
|
|||
return ! quitMessagePosted;
|
||||
}
|
||||
|
||||
static CFRunLoopTimerRef messageTimer = 0;
|
||||
static Array <void*, CriticalSection>* pendingMessages = 0;
|
||||
|
||||
static void timerCallback (CFRunLoopTimerRef, void*)
|
||||
{
|
||||
if (pendingMessages != 0)
|
||||
{
|
||||
const int numToDispatch = jmin (4, pendingMessages->size());
|
||||
|
||||
for (int i = 0; i < numToDispatch; ++i)
|
||||
{
|
||||
void* const nextMessage = (*pendingMessages)[i];
|
||||
|
||||
if (nextMessage != 0)
|
||||
MessageManager::getInstance()->deliverMessage (nextMessage);
|
||||
}
|
||||
|
||||
pendingMessages->removeRange (0, numToDispatch);
|
||||
|
||||
if (pendingMessages->size() > 0)
|
||||
CFRunLoopTimerSetNextFireDate (messageTimer, CFAbsoluteTimeGetCurrent() - 0.5);
|
||||
}
|
||||
}
|
||||
|
||||
void MessageManager::doPlatformSpecificInitialisation()
|
||||
{
|
||||
pendingMessages = new Array <void*, CriticalSection>();
|
||||
|
||||
messageTimer = CFRunLoopTimerCreate (kCFAllocatorDefault, CFAbsoluteTimeGetCurrent() + 60.0, 60.0,
|
||||
0, 0, timerCallback, 0);
|
||||
|
||||
CFRunLoopAddTimer (CFRunLoopGetMain(), messageTimer, kCFRunLoopCommonModes);
|
||||
|
||||
if (juceAppDelegate == 0)
|
||||
juceAppDelegate = [[JuceAppDelegate alloc] init];
|
||||
}
|
||||
|
||||
void MessageManager::doPlatformSpecificShutdown()
|
||||
{
|
||||
CFRunLoopTimerInvalidate (messageTimer);
|
||||
CFRunLoopRemoveTimer (CFRunLoopGetMain(), messageTimer, kCFRunLoopCommonModes);
|
||||
CFRelease (messageTimer);
|
||||
messageTimer = 0;
|
||||
|
||||
if (pendingMessages != 0)
|
||||
{
|
||||
while (pendingMessages->size() > 0)
|
||||
delete ((Message*) pendingMessages->remove(0));
|
||||
|
||||
deleteAndZero (pendingMessages);
|
||||
}
|
||||
|
||||
if (juceAppDelegate != 0)
|
||||
{
|
||||
[[NSRunLoop currentRunLoop] cancelPerformSelectorsWithTarget: juceAppDelegate];
|
||||
[[NSNotificationCenter defaultCenter] removeObserver: juceAppDelegate];
|
||||
|
||||
// Annoyingly, cancelPerformSelectorsWithTarget can't actually cancel the messages
|
||||
// sent by performSelectorOnMainThread, so need to manually flush these before quitting..
|
||||
juceAppDelegate->flushingMessages = true;
|
||||
|
||||
for (int i = 100; --i >= 0 && numPendingMessages > 0;)
|
||||
{
|
||||
const ScopedAutoReleasePool pool;
|
||||
[[NSRunLoop currentRunLoop] runMode: NSDefaultRunLoopMode
|
||||
beforeDate: [NSDate dateWithTimeIntervalSinceNow: 5 * 0.001]];
|
||||
}
|
||||
|
||||
[juceAppDelegate release];
|
||||
juceAppDelegate = 0;
|
||||
}
|
||||
|
|
@ -264437,11 +264405,12 @@ void MessageManager::doPlatformSpecificShutdown()
|
|||
|
||||
bool juce_postMessageToSystemQueue (void* message)
|
||||
{
|
||||
atomicIncrement (numPendingMessages);
|
||||
if (pendingMessages != 0)
|
||||
{
|
||||
pendingMessages->add (message);
|
||||
CFRunLoopTimerSetNextFireDate (messageTimer, CFAbsoluteTimeGetCurrent() - 1.0);
|
||||
}
|
||||
|
||||
[juceAppDelegate performSelectorOnMainThread: @selector (customEvent:)
|
||||
withObject: (id) [[NSData alloc] initWithBytes: &message length: (int) sizeof (message)]
|
||||
waitUntilDone: NO];
|
||||
return true;
|
||||
}
|
||||
|
||||
|
|
@ -265795,7 +265764,7 @@ private:
|
|||
|
||||
void interruptionListener (UInt32 inInterruption)
|
||||
{
|
||||
if (inInterruption == kAudioSessionBeginInterruption)
|
||||
/*if (inInterruption == kAudioSessionBeginInterruption)
|
||||
{
|
||||
isRunning = false;
|
||||
AudioOutputUnitStop (audioUnit);
|
||||
|
|
@ -265808,7 +265777,7 @@ private:
|
|||
isRunning = true;
|
||||
propertyChanged (0, 0, 0);
|
||||
}
|
||||
}
|
||||
}*/
|
||||
|
||||
if (inInterruption == kAudioSessionEndInterruption)
|
||||
{
|
||||
|
|
@ -267529,7 +267498,7 @@ public:
|
|||
|
||||
void drawHorizontalLine (const int y, double left, double right)
|
||||
{
|
||||
CGContextFillRect (context, CGRectMake (left, y, right - left, 1.0f));
|
||||
CGContextFillRect (context, CGRectMake (left, flipHeight - (y + 1.0f), right - left, 1.0f));
|
||||
}
|
||||
|
||||
void setFont (const Font& newFont)
|
||||
|
|
@ -269305,20 +269274,34 @@ void juce_setKioskComponent (Component* kioskModeComponent, bool enableOrDisable
|
|||
}
|
||||
}
|
||||
|
||||
class AsyncRepaintMessage : public CallbackMessage
|
||||
{
|
||||
public:
|
||||
NSViewComponentPeer* const peer;
|
||||
const Rectangle rect;
|
||||
|
||||
AsyncRepaintMessage (NSViewComponentPeer* const peer_, const Rectangle& rect_)
|
||||
: peer (peer_), rect (rect_)
|
||||
{
|
||||
}
|
||||
|
||||
void messageCallback()
|
||||
{
|
||||
if (ComponentPeer::isValidPeer (peer))
|
||||
peer->repaint (rect.getX(), rect.getY(), rect.getWidth(), rect.getHeight());
|
||||
}
|
||||
};
|
||||
|
||||
void NSViewComponentPeer::repaint (int x, int y, int w, int h)
|
||||
{
|
||||
NSRect r = NSMakeRect ((float) x, (float) ([view frame].size.height - (y + h)),
|
||||
(float) w, (float) h);
|
||||
|
||||
if (insideDrawRect)
|
||||
{
|
||||
[view performSelectorOnMainThread: @selector (asyncRepaint:)
|
||||
withObject: [NSData dataWithBytes: &r length: sizeof (r)]
|
||||
waitUntilDone: NO];
|
||||
(new AsyncRepaintMessage (this, Rectangle (x, y, w, h)))->post();
|
||||
}
|
||||
else
|
||||
{
|
||||
[view setNeedsDisplayInRect: r];
|
||||
[view setNeedsDisplayInRect: NSMakeRect ((float) x, (float) ([view frame].size.height - (y + h)),
|
||||
(float) w, (float) h)];
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -271625,8 +271608,36 @@ struct CallbackMessagePayload
|
|||
class AppDelegateRedirector
|
||||
{
|
||||
public:
|
||||
AppDelegateRedirector() {}
|
||||
virtual ~AppDelegateRedirector() {}
|
||||
AppDelegateRedirector()
|
||||
{
|
||||
CFRunLoopTimerContext context;
|
||||
zerostruct (context);
|
||||
context.info = this;
|
||||
|
||||
timer = CFRunLoopTimerCreate (kCFAllocatorDefault, CFAbsoluteTimeGetCurrent() + 60.0, 60.0, 0, 0,
|
||||
AppDelegateRedirector::timerCallbackStatic, &context);
|
||||
|
||||
#if MAC_OS_X_VERSION_MIN_REQUIRED > MAC_OS_X_VERSION_10_4
|
||||
CFRunLoopAddTimer (CFRunLoopGetMain(), timer, kCFRunLoopCommonModes);
|
||||
#else
|
||||
CFRunLoopAddTimer (CFRunLoopGetCurrent(), timer, kCFRunLoopCommonModes);
|
||||
#endif
|
||||
}
|
||||
|
||||
virtual ~AppDelegateRedirector()
|
||||
{
|
||||
CFRunLoopTimerInvalidate (timer);
|
||||
|
||||
#if MAC_OS_X_VERSION_MIN_REQUIRED > MAC_OS_X_VERSION_10_4
|
||||
CFRunLoopRemoveTimer (CFRunLoopGetMain(), timer, kCFRunLoopCommonModes);
|
||||
#else
|
||||
CFRunLoopRemoveTimer (CFRunLoopGetCurrent(), timer, kCFRunLoopCommonModes);
|
||||
#endif
|
||||
CFRelease (timer);
|
||||
|
||||
while (messages.size() > 0)
|
||||
delete ((Message*) messages.remove(0));
|
||||
}
|
||||
|
||||
virtual NSApplicationTerminateReply shouldTerminate()
|
||||
{
|
||||
|
|
@ -271667,12 +271678,6 @@ public:
|
|||
juce_HandleProcessFocusChange();
|
||||
}
|
||||
|
||||
virtual void deliverMessage (void* message)
|
||||
{
|
||||
// no need for an mm lock here - deliverMessage locks it
|
||||
MessageManager::getInstance()->deliverMessage (message);
|
||||
}
|
||||
|
||||
virtual void performCallback (CallbackMessagePayload* pl)
|
||||
{
|
||||
pl->result = (*pl->function) (pl->parameter);
|
||||
|
|
@ -271683,6 +271688,39 @@ public:
|
|||
{
|
||||
delete this;
|
||||
}
|
||||
|
||||
void postMessage (void* m) throw()
|
||||
{
|
||||
messages.add (m);
|
||||
CFRunLoopTimerSetNextFireDate (timer, CFAbsoluteTimeGetCurrent() - 0.5);
|
||||
}
|
||||
|
||||
private:
|
||||
CFRunLoopTimerRef timer;
|
||||
Array <void*, CriticalSection> messages;
|
||||
|
||||
void timerCallback() throw()
|
||||
{
|
||||
const int numToDispatch = jmin (4, messages.size());
|
||||
|
||||
for (int i = 0; i < numToDispatch; ++i)
|
||||
{
|
||||
void* const nextMessage = messages[i];
|
||||
|
||||
if (nextMessage != 0)
|
||||
MessageManager::getInstance()->deliverMessage (nextMessage);
|
||||
}
|
||||
|
||||
messages.removeRange (0, numToDispatch);
|
||||
|
||||
if (messages.size() > 0)
|
||||
CFRunLoopTimerSetNextFireDate (timer, CFAbsoluteTimeGetCurrent() - 0.5);
|
||||
}
|
||||
|
||||
static void timerCallbackStatic (CFRunLoopTimerRef, void* info)
|
||||
{
|
||||
((AppDelegateRedirector*) info)->timerCallback();
|
||||
}
|
||||
};
|
||||
|
||||
END_JUCE_NAMESPACE
|
||||
|
|
@ -271690,17 +271728,13 @@ using namespace JUCE_NAMESPACE;
|
|||
|
||||
#define JuceAppDelegate MakeObjCClassName(JuceAppDelegate)
|
||||
|
||||
static int numPendingMessages = 0;
|
||||
|
||||
@interface JuceAppDelegate : NSObject
|
||||
{
|
||||
@private
|
||||
id oldDelegate;
|
||||
AppDelegateRedirector* redirector;
|
||||
NSTimer* messageTimer;
|
||||
|
||||
@public
|
||||
bool flushingMessages;
|
||||
AppDelegateRedirector* redirector;
|
||||
}
|
||||
|
||||
- (JuceAppDelegate*) init;
|
||||
|
|
@ -271711,7 +271745,6 @@ static int numPendingMessages = 0;
|
|||
- (void) applicationDidBecomeActive: (NSNotification*) aNotification;
|
||||
- (void) applicationDidResignActive: (NSNotification*) aNotification;
|
||||
- (void) applicationWillUnhide: (NSNotification*) aNotification;
|
||||
- (void) customEvent: (id) data;
|
||||
- (void) performCallback: (id) info;
|
||||
- (void) dummyMethod;
|
||||
@end
|
||||
|
|
@ -271723,8 +271756,6 @@ static int numPendingMessages = 0;
|
|||
[super init];
|
||||
|
||||
redirector = new AppDelegateRedirector();
|
||||
numPendingMessages = 0;
|
||||
flushingMessages = false;
|
||||
|
||||
NSNotificationCenter* center = [NSNotificationCenter defaultCenter];
|
||||
|
||||
|
|
@ -271788,19 +271819,6 @@ static int numPendingMessages = 0;
|
|||
redirector->focusChanged();
|
||||
}
|
||||
|
||||
- (void) customEvent: (id) n
|
||||
{
|
||||
atomicDecrement (numPendingMessages);
|
||||
|
||||
NSData* data = (NSData*) n;
|
||||
void* message = 0;
|
||||
[data getBytes: &message length: sizeof (message)];
|
||||
[data release];
|
||||
|
||||
if (message != 0 && ! flushingMessages)
|
||||
redirector->deliverMessage (message);
|
||||
}
|
||||
|
||||
- (void) performCallback: (id) info
|
||||
{
|
||||
if ([info isKindOfClass: [NSData class]])
|
||||
|
|
@ -271977,18 +271995,6 @@ void MessageManager::doPlatformSpecificShutdown()
|
|||
{
|
||||
[[NSRunLoop currentRunLoop] cancelPerformSelectorsWithTarget: juceAppDelegate];
|
||||
[[NSNotificationCenter defaultCenter] removeObserver: juceAppDelegate];
|
||||
|
||||
// Annoyingly, cancelPerformSelectorsWithTarget can't actually cancel the messages
|
||||
// sent by performSelectorOnMainThread, so need to manually flush these before quitting..
|
||||
juceAppDelegate->flushingMessages = true;
|
||||
|
||||
for (int i = 100; --i >= 0 && numPendingMessages > 0;)
|
||||
{
|
||||
const ScopedAutoReleasePool pool;
|
||||
[[NSRunLoop currentRunLoop] runMode: NSDefaultRunLoopMode
|
||||
beforeDate: [NSDate dateWithTimeIntervalSinceNow: 5 * 0.001]];
|
||||
}
|
||||
|
||||
[juceAppDelegate release];
|
||||
juceAppDelegate = 0;
|
||||
}
|
||||
|
|
@ -271996,11 +272002,7 @@ void MessageManager::doPlatformSpecificShutdown()
|
|||
|
||||
bool juce_postMessageToSystemQueue (void* message)
|
||||
{
|
||||
atomicIncrement (numPendingMessages);
|
||||
|
||||
[juceAppDelegate performSelectorOnMainThread: @selector (customEvent:)
|
||||
withObject: (id) [[NSData alloc] initWithBytes: &message length: (int) sizeof (message)]
|
||||
waitUntilDone: NO];
|
||||
juceAppDelegate->redirector->postMessage (message);
|
||||
return true;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -194,6 +194,7 @@ bool JUCEApplication::initialiseApp (String& commandLine)
|
|||
|
||||
initialiseJuce_GUI();
|
||||
|
||||
#if ! JUCE_IPHONE
|
||||
jassert (appLock == 0); // initialiseApp must only be called once!
|
||||
|
||||
if (! moreThanOneInstanceAllowed())
|
||||
|
|
@ -211,6 +212,7 @@ bool JUCEApplication::initialiseApp (String& commandLine)
|
|||
return false;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
// let the app do its setting-up..
|
||||
initialise (commandLineParameters);
|
||||
|
|
@ -289,9 +291,9 @@ int JUCEApplication::main (int argc, char* argv[],
|
|||
return juce_IPhoneMain (argc, argv, newApp);
|
||||
#else
|
||||
|
||||
#if JUCE_MAC
|
||||
#if JUCE_MAC
|
||||
const ScopedAutoReleasePool pool;
|
||||
#endif
|
||||
#endif
|
||||
|
||||
String cmd;
|
||||
for (int i = 1; i < argc; ++i)
|
||||
|
|
|
|||
|
|
@ -117,9 +117,12 @@ void MessageManager::deliverMessage (void* message)
|
|||
{
|
||||
quitMessageReceived = true;
|
||||
}
|
||||
else if (dynamic_cast <CallbackMessage*> (m) != 0)
|
||||
else
|
||||
{
|
||||
(dynamic_cast <CallbackMessage*> (m))->messageCallback();
|
||||
CallbackMessage* const cm = dynamic_cast <CallbackMessage*> (m);
|
||||
|
||||
if (cm != 0)
|
||||
cm->messageCallback();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -686,6 +686,9 @@ public:
|
|||
atom->getText (passwordCharacter),
|
||||
atomX, 0.0f);
|
||||
|
||||
if (indexToFind - indexInText >= g.getNumGlyphs())
|
||||
return atomRight;
|
||||
|
||||
return jmin (atomRight, g.getGlyph (indexToFind - indexInText).getLeft());
|
||||
}
|
||||
|
||||
|
|
@ -703,7 +706,7 @@ public:
|
|||
atomX, 0.0f);
|
||||
|
||||
int j;
|
||||
for (j = 0; j < atom->numChars; ++j)
|
||||
for (j = 0; j < g.getNumGlyphs(); ++j)
|
||||
if ((g.getGlyph(j).getLeft() + g.getGlyph(j).getRight()) / 2 > xToFind)
|
||||
break;
|
||||
|
||||
|
|
|
|||
|
|
@ -159,7 +159,7 @@ void GlyphArrangement::addGlyphArrangement (const GlyphArrangement& other) throw
|
|||
|
||||
void GlyphArrangement::removeRangeOfGlyphs (int startIndex, const int num) throw()
|
||||
{
|
||||
glyphs.removeRange (startIndex, num);
|
||||
glyphs.removeRange (startIndex, num < 0 ? glyphs.size() : num);
|
||||
}
|
||||
|
||||
//==============================================================================
|
||||
|
|
@ -222,22 +222,13 @@ void GlyphArrangement::addCurtailedLineOfText (const Font& font,
|
|||
|
||||
void GlyphArrangement::appendEllipsis (const Font& font, const float maxXPixels) throw()
|
||||
{
|
||||
//const TypefaceGlyphInfo* const dotGlyph = font.getTypeface()->getGlyph (T('.'));
|
||||
|
||||
if (/*dotGlyph != 0 &&*/ glyphs.size() > 0)
|
||||
if (glyphs.size() > 0)
|
||||
{
|
||||
//PositionedGlyph* glyph = glyphs.getLast();
|
||||
//const float fontHeight = glyph->font.getHeight();
|
||||
//const float fontHorizontalScale = glyph->font.getHorizontalScale();
|
||||
|
||||
Array<int> dotGlyphs;
|
||||
Array<float> dotXs;
|
||||
font.getGlyphPositions (T(".."), dotGlyphs, dotXs);
|
||||
|
||||
const float dx = dotXs[1];
|
||||
//fontHeight * fontHorizontalScale
|
||||
// * (font.getExtraKerningFactor() + dotGlyph->getHorizontalSpacing (T('.')));
|
||||
|
||||
float xOffset = 0.0f, yOffset = 0.0f;
|
||||
|
||||
for (int dotPos = 3; --dotPos >= 0 && glyphs.size() > 0;)
|
||||
|
|
@ -558,7 +549,7 @@ void GlyphArrangement::addFittedText (const Font& f,
|
|||
|
||||
if (startIndex < glyphs.size())
|
||||
{
|
||||
glyphs.removeRange (startIndex, glyphs.size());
|
||||
removeRangeOfGlyphs (startIndex, -1);
|
||||
|
||||
if (startIndex - originalStartIndex > 4)
|
||||
{
|
||||
|
|
|
|||
|
|
@ -187,8 +187,8 @@ const AffineTransform AffineTransform::rotation (const float angle,
|
|||
const AffineTransform AffineTransform::scaled (const float factorX,
|
||||
const float factorY) const throw()
|
||||
{
|
||||
return followedBy (factorX, 0, 0,
|
||||
0, factorY, 0);
|
||||
return AffineTransform (factorX * mat00, factorX * mat01, factorX * mat02,
|
||||
factorY * mat10, factorY * mat11, factorY * mat12);
|
||||
}
|
||||
|
||||
const AffineTransform AffineTransform::scale (const float factorX,
|
||||
|
|
|
|||
|
|
@ -92,8 +92,6 @@ WaitableEvent::~WaitableEvent() throw()
|
|||
bool WaitableEvent::wait (const int timeOutMillisecs) const throw()
|
||||
{
|
||||
EventStruct* const es = (EventStruct*) internal;
|
||||
|
||||
bool ok = true;
|
||||
pthread_mutex_lock (&es->mutex);
|
||||
|
||||
if (timeOutMillisecs < 0)
|
||||
|
|
@ -120,16 +118,15 @@ bool WaitableEvent::wait (const int timeOutMillisecs) const throw()
|
|||
|
||||
if (pthread_cond_timedwait (&es->condition, &es->mutex, &time) == ETIMEDOUT)
|
||||
{
|
||||
ok = false;
|
||||
break;
|
||||
pthread_mutex_unlock (&es->mutex);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
es->triggered = false;
|
||||
|
||||
pthread_mutex_unlock (&es->mutex);
|
||||
return ok;
|
||||
return true;
|
||||
}
|
||||
|
||||
void WaitableEvent::signal() const throw()
|
||||
|
|
|
|||
|
|
@ -71,7 +71,9 @@ BEGIN_JUCE_NAMESPACE
|
|||
#include "../gui/components/special/juce_SystemTrayIconComponent.h"
|
||||
#include "../gui/components/filebrowser/juce_FileChooser.h"
|
||||
#include "../gui/components/lookandfeel/juce_LookAndFeel.h"
|
||||
#if JUCE_USE_CDBURNER
|
||||
#include "../audio/audio_file_formats/juce_AudioCDBurner.h"
|
||||
#endif
|
||||
#include "../audio/audio_file_formats/juce_AudioCDReader.h"
|
||||
#include "../audio/audio_sources/juce_AudioSource.h"
|
||||
#include "../audio/dsp/juce_AudioDataConverters.h"
|
||||
|
|
|
|||
|
|
@ -397,7 +397,7 @@ private:
|
|||
|
||||
void interruptionListener (UInt32 inInterruption)
|
||||
{
|
||||
if (inInterruption == kAudioSessionBeginInterruption)
|
||||
/*if (inInterruption == kAudioSessionBeginInterruption)
|
||||
{
|
||||
isRunning = false;
|
||||
AudioOutputUnitStop (audioUnit);
|
||||
|
|
@ -410,7 +410,7 @@ private:
|
|||
isRunning = true;
|
||||
propertyChanged (0, 0, 0);
|
||||
}
|
||||
}
|
||||
}*/
|
||||
|
||||
if (inInterruption == kAudioSessionEndInterruption)
|
||||
{
|
||||
|
|
|
|||
|
|
@ -35,83 +35,11 @@ struct CallbackMessagePayload
|
|||
bool volatile hasBeenExecuted;
|
||||
};
|
||||
|
||||
/* When you use multiple DLLs which share similarly-named obj-c classes - like
|
||||
for example having more than one juce plugin loaded into a host, then when a
|
||||
method is called, the actual code that runs might actually be in a different module
|
||||
than the one you expect... So any calls to library functions or statics that are
|
||||
made inside obj-c methods will probably end up getting executed in a different DLL's
|
||||
memory space. Not a great thing to happen - this obviously leads to bizarre crashes.
|
||||
|
||||
To work around this insanity, I'm only allowing obj-c methods to make calls to
|
||||
virtual methods of an object that's known to live inside the right module's space.
|
||||
*/
|
||||
class AppDelegateRedirector
|
||||
{
|
||||
public:
|
||||
AppDelegateRedirector() {}
|
||||
virtual ~AppDelegateRedirector() {}
|
||||
|
||||
virtual BOOL openFile (const NSString* filename)
|
||||
{
|
||||
if (JUCEApplication::getInstance() != 0)
|
||||
{
|
||||
JUCEApplication::getInstance()->anotherInstanceStarted (nsStringToJuce (filename));
|
||||
return YES;
|
||||
}
|
||||
|
||||
return NO;
|
||||
}
|
||||
|
||||
virtual void openFiles (NSArray* filenames)
|
||||
{
|
||||
StringArray files;
|
||||
for (unsigned int i = 0; i < [filenames count]; ++i)
|
||||
files.add (nsStringToJuce ((NSString*) [filenames objectAtIndex: i]));
|
||||
|
||||
if (files.size() > 0 && JUCEApplication::getInstance() != 0)
|
||||
{
|
||||
JUCEApplication::getInstance()->anotherInstanceStarted (files.joinIntoString (T(" ")));
|
||||
}
|
||||
}
|
||||
|
||||
virtual void focusChanged()
|
||||
{
|
||||
juce_HandleProcessFocusChange();
|
||||
}
|
||||
|
||||
virtual void deliverMessage (void* message)
|
||||
{
|
||||
// no need for an mm lock here - deliverMessage locks it
|
||||
MessageManager::getInstance()->deliverMessage (message);
|
||||
}
|
||||
|
||||
virtual void performCallback (CallbackMessagePayload* pl)
|
||||
{
|
||||
pl->result = (*pl->function) (pl->parameter);
|
||||
pl->hasBeenExecuted = true;
|
||||
}
|
||||
|
||||
virtual void deleteSelf()
|
||||
{
|
||||
delete this;
|
||||
}
|
||||
};
|
||||
|
||||
END_JUCE_NAMESPACE
|
||||
using namespace JUCE_NAMESPACE;
|
||||
|
||||
#define JuceAppDelegate MakeObjCClassName(JuceAppDelegate)
|
||||
|
||||
static int numPendingMessages = 0;
|
||||
|
||||
@interface JuceAppDelegate : NSObject <UIApplicationDelegate>
|
||||
{
|
||||
@private
|
||||
id oldDelegate;
|
||||
AppDelegateRedirector* redirector;
|
||||
|
||||
@public
|
||||
bool flushingMessages;
|
||||
}
|
||||
|
||||
- (JuceAppDelegate*) init;
|
||||
|
|
@ -122,7 +50,6 @@ static int numPendingMessages = 0;
|
|||
- (void) applicationWillUnhide: (NSNotification*) aNotification;
|
||||
- (void) customEvent: (id) data;
|
||||
- (void) performCallback: (id) info;
|
||||
- (void) dummyMethod;
|
||||
@end
|
||||
|
||||
@implementation JuceAppDelegate
|
||||
|
|
@ -131,11 +58,6 @@ static int numPendingMessages = 0;
|
|||
{
|
||||
[super init];
|
||||
|
||||
redirector = new AppDelegateRedirector();
|
||||
numPendingMessages = 0;
|
||||
flushingMessages = false;
|
||||
|
||||
oldDelegate = [[UIApplication sharedApplication] delegate];
|
||||
[[UIApplication sharedApplication] setDelegate: self];
|
||||
|
||||
return self;
|
||||
|
|
@ -143,44 +65,45 @@ static int numPendingMessages = 0;
|
|||
|
||||
- (void) dealloc
|
||||
{
|
||||
if (oldDelegate != 0)
|
||||
[[UIApplication sharedApplication] setDelegate: oldDelegate];
|
||||
|
||||
redirector->deleteSelf();
|
||||
[[UIApplication sharedApplication] setDelegate: nil];
|
||||
[super dealloc];
|
||||
}
|
||||
|
||||
- (BOOL) application: (UIApplication*) application handleOpenURL: (NSURL*) url
|
||||
{
|
||||
return redirector->openFile ([url absoluteString]);
|
||||
if (JUCEApplication::getInstance() != 0)
|
||||
{
|
||||
JUCEApplication::getInstance()->anotherInstanceStarted (nsStringToJuce ([url absoluteString]));
|
||||
return YES;
|
||||
}
|
||||
|
||||
return NO;
|
||||
}
|
||||
|
||||
- (void) applicationDidBecomeActive: (NSNotification*) aNotification
|
||||
{
|
||||
redirector->focusChanged();
|
||||
juce_HandleProcessFocusChange();
|
||||
}
|
||||
|
||||
- (void) applicationDidResignActive: (NSNotification*) aNotification
|
||||
{
|
||||
redirector->focusChanged();
|
||||
juce_HandleProcessFocusChange();
|
||||
}
|
||||
|
||||
- (void) applicationWillUnhide: (NSNotification*) aNotification
|
||||
{
|
||||
redirector->focusChanged();
|
||||
juce_HandleProcessFocusChange();
|
||||
}
|
||||
|
||||
- (void) customEvent: (id) n
|
||||
{
|
||||
atomicDecrement (numPendingMessages);
|
||||
|
||||
NSData* data = (NSData*) n;
|
||||
void* message = 0;
|
||||
[data getBytes: &message length: sizeof (message)];
|
||||
[data release];
|
||||
|
||||
if (message != 0 && ! flushingMessages)
|
||||
redirector->deliverMessage (message);
|
||||
if (message != 0)
|
||||
MessageManager::getInstance()->deliverMessage (message);
|
||||
}
|
||||
|
||||
- (void) performCallback: (id) info
|
||||
|
|
@ -190,7 +113,10 @@ static int numPendingMessages = 0;
|
|||
CallbackMessagePayload* pl = (CallbackMessagePayload*) [((NSData*) info) bytes];
|
||||
|
||||
if (pl != 0)
|
||||
redirector->performCallback (pl);
|
||||
{
|
||||
pl->result = (*pl->function) (pl->parameter);
|
||||
pl->hasBeenExecuted = true;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
|
|
@ -198,8 +124,6 @@ static int numPendingMessages = 0;
|
|||
}
|
||||
}
|
||||
|
||||
- (void) dummyMethod {} // (used as a way of running a dummy thread)
|
||||
|
||||
@end
|
||||
|
||||
BEGIN_JUCE_NAMESPACE
|
||||
|
|
@ -209,7 +133,6 @@ static JuceAppDelegate* juceAppDelegate = 0;
|
|||
void MessageManager::runDispatchLoop()
|
||||
{
|
||||
jassert (isThisTheMessageThread()); // must only be called by the message thread
|
||||
|
||||
runDispatchLoopUntil (-1);
|
||||
}
|
||||
|
||||
|
|
@ -243,30 +166,61 @@ bool MessageManager::runDispatchLoopUntil (int millisecondsToRunFor)
|
|||
}
|
||||
|
||||
//==============================================================================
|
||||
static CFRunLoopTimerRef messageTimer = 0;
|
||||
static Array <void*, CriticalSection>* pendingMessages = 0;
|
||||
|
||||
static void timerCallback (CFRunLoopTimerRef, void*)
|
||||
{
|
||||
if (pendingMessages != 0)
|
||||
{
|
||||
const int numToDispatch = jmin (4, pendingMessages->size());
|
||||
|
||||
for (int i = 0; i < numToDispatch; ++i)
|
||||
{
|
||||
void* const nextMessage = (*pendingMessages)[i];
|
||||
|
||||
if (nextMessage != 0)
|
||||
MessageManager::getInstance()->deliverMessage (nextMessage);
|
||||
}
|
||||
|
||||
pendingMessages->removeRange (0, numToDispatch);
|
||||
|
||||
if (pendingMessages->size() > 0)
|
||||
CFRunLoopTimerSetNextFireDate (messageTimer, CFAbsoluteTimeGetCurrent() - 0.5);
|
||||
}
|
||||
}
|
||||
|
||||
void MessageManager::doPlatformSpecificInitialisation()
|
||||
{
|
||||
pendingMessages = new Array <void*, CriticalSection>();
|
||||
|
||||
messageTimer = CFRunLoopTimerCreate (kCFAllocatorDefault, CFAbsoluteTimeGetCurrent() + 60.0, 60.0,
|
||||
0, 0, timerCallback, 0);
|
||||
|
||||
CFRunLoopAddTimer (CFRunLoopGetMain(), messageTimer, kCFRunLoopCommonModes);
|
||||
|
||||
if (juceAppDelegate == 0)
|
||||
juceAppDelegate = [[JuceAppDelegate alloc] init];
|
||||
}
|
||||
|
||||
void MessageManager::doPlatformSpecificShutdown()
|
||||
{
|
||||
CFRunLoopTimerInvalidate (messageTimer);
|
||||
CFRunLoopRemoveTimer (CFRunLoopGetMain(), messageTimer, kCFRunLoopCommonModes);
|
||||
CFRelease (messageTimer);
|
||||
messageTimer = 0;
|
||||
|
||||
if (pendingMessages != 0)
|
||||
{
|
||||
while (pendingMessages->size() > 0)
|
||||
delete ((Message*) pendingMessages->remove(0));
|
||||
|
||||
deleteAndZero (pendingMessages);
|
||||
}
|
||||
|
||||
if (juceAppDelegate != 0)
|
||||
{
|
||||
[[NSRunLoop currentRunLoop] cancelPerformSelectorsWithTarget: juceAppDelegate];
|
||||
[[NSNotificationCenter defaultCenter] removeObserver: juceAppDelegate];
|
||||
|
||||
// Annoyingly, cancelPerformSelectorsWithTarget can't actually cancel the messages
|
||||
// sent by performSelectorOnMainThread, so need to manually flush these before quitting..
|
||||
juceAppDelegate->flushingMessages = true;
|
||||
|
||||
for (int i = 100; --i >= 0 && numPendingMessages > 0;)
|
||||
{
|
||||
const ScopedAutoReleasePool pool;
|
||||
[[NSRunLoop currentRunLoop] runMode: NSDefaultRunLoopMode
|
||||
beforeDate: [NSDate dateWithTimeIntervalSinceNow: 5 * 0.001]];
|
||||
}
|
||||
|
||||
[juceAppDelegate release];
|
||||
juceAppDelegate = 0;
|
||||
}
|
||||
|
|
@ -274,11 +228,12 @@ void MessageManager::doPlatformSpecificShutdown()
|
|||
|
||||
bool juce_postMessageToSystemQueue (void* message)
|
||||
{
|
||||
atomicIncrement (numPendingMessages);
|
||||
if (pendingMessages != 0)
|
||||
{
|
||||
pendingMessages->add (message);
|
||||
CFRunLoopTimerSetNextFireDate (messageTimer, CFAbsoluteTimeGetCurrent() - 1.0);
|
||||
}
|
||||
|
||||
[juceAppDelegate performSelectorOnMainThread: @selector (customEvent:)
|
||||
withObject: (id) [[NSData alloc] initWithBytes: &message length: (int) sizeof (message)]
|
||||
waitUntilDone: NO];
|
||||
return true;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -47,10 +47,9 @@ END_JUCE_NAMESPACE
|
|||
- (void) applicationDidFinishLaunching: (UIApplication*) application
|
||||
{
|
||||
String dummy;
|
||||
|
||||
if (! juce_intialisingApp->initialiseApp (dummy))
|
||||
{
|
||||
// (should quit)
|
||||
}
|
||||
exit (0);
|
||||
}
|
||||
|
||||
- (void) applicationWillResignActive: (UIApplication*) application
|
||||
|
|
|
|||
|
|
@ -132,7 +132,7 @@ public:
|
|||
|
||||
UIWindow* window;
|
||||
JuceUIView* view;
|
||||
bool isSharedWindow, fullScreen;
|
||||
bool isSharedWindow, fullScreen, insideDrawRect;
|
||||
};
|
||||
|
||||
//==============================================================================
|
||||
|
|
@ -344,7 +344,8 @@ UIViewComponentPeer::UIViewComponentPeer (Component* const component,
|
|||
window (0),
|
||||
view (0),
|
||||
isSharedWindow (viewToAttachTo != 0),
|
||||
fullScreen (false)
|
||||
fullScreen (false),
|
||||
insideDrawRect (false)
|
||||
{
|
||||
CGRect r;
|
||||
r.origin.x = 0;
|
||||
|
|
@ -733,7 +734,10 @@ void UIViewComponentPeer::drawRect (CGRect r)
|
|||
|
||||
CGContextConcatCTM (cg, CGAffineTransformMake (1, 0, 0, -1, 0, view.bounds.size.height));
|
||||
CoreGraphicsContext g (cg, view.bounds.size.height);
|
||||
|
||||
insideDrawRect = true;
|
||||
handlePaint (g);
|
||||
insideDrawRect = false;
|
||||
}
|
||||
|
||||
bool UIViewComponentPeer::canBecomeKeyWindow()
|
||||
|
|
@ -761,19 +765,33 @@ void juce_setKioskComponent (Component* kioskModeComponent, bool enableOrDisable
|
|||
}
|
||||
|
||||
//==============================================================================
|
||||
class AsyncRepaintMessage : public CallbackMessage
|
||||
{
|
||||
public:
|
||||
UIViewComponentPeer* const peer;
|
||||
const Rectangle rect;
|
||||
|
||||
AsyncRepaintMessage (UIViewComponentPeer* const peer_, const Rectangle& rect_)
|
||||
: peer (peer_), rect (rect_)
|
||||
{
|
||||
}
|
||||
|
||||
void messageCallback()
|
||||
{
|
||||
if (ComponentPeer::isValidPeer (peer))
|
||||
peer->repaint (rect.getX(), rect.getY(), rect.getWidth(), rect.getHeight());
|
||||
}
|
||||
};
|
||||
|
||||
void UIViewComponentPeer::repaint (int x, int y, int w, int h)
|
||||
{
|
||||
CGRect r = CGRectMake ((float) x, (float) y, (float) w, (float) h);
|
||||
|
||||
if (! MessageManager::getInstance()->isThisTheMessageThread())
|
||||
if (insideDrawRect || ! MessageManager::getInstance()->isThisTheMessageThread())
|
||||
{
|
||||
[view performSelectorOnMainThread: @selector (asyncRepaint:)
|
||||
withObject: [NSData dataWithBytes: &r length: sizeof (r)]
|
||||
waitUntilDone: NO];
|
||||
(new AsyncRepaintMessage (this, Rectangle (x, y, w, h)))->post();
|
||||
}
|
||||
else
|
||||
{
|
||||
[view setNeedsDisplayInRect: r];
|
||||
[view setNeedsDisplayInRect: CGRectMake ((float) x, (float) y, (float) w, (float) h)];
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -377,7 +377,7 @@ public:
|
|||
|
||||
void drawHorizontalLine (const int y, double left, double right)
|
||||
{
|
||||
CGContextFillRect (context, CGRectMake (left, y, right - left, 1.0f));
|
||||
CGContextFillRect (context, CGRectMake (left, flipHeight - (y + 1.0f), right - left, 1.0f));
|
||||
}
|
||||
|
||||
void setFont (const Font& newFont)
|
||||
|
|
|
|||
|
|
@ -48,8 +48,36 @@ struct CallbackMessagePayload
|
|||
class AppDelegateRedirector
|
||||
{
|
||||
public:
|
||||
AppDelegateRedirector() {}
|
||||
virtual ~AppDelegateRedirector() {}
|
||||
AppDelegateRedirector()
|
||||
{
|
||||
CFRunLoopTimerContext context;
|
||||
zerostruct (context);
|
||||
context.info = this;
|
||||
|
||||
timer = CFRunLoopTimerCreate (kCFAllocatorDefault, CFAbsoluteTimeGetCurrent() + 60.0, 60.0, 0, 0,
|
||||
AppDelegateRedirector::timerCallbackStatic, &context);
|
||||
|
||||
#if MAC_OS_X_VERSION_MIN_REQUIRED > MAC_OS_X_VERSION_10_4
|
||||
CFRunLoopAddTimer (CFRunLoopGetMain(), timer, kCFRunLoopCommonModes);
|
||||
#else
|
||||
CFRunLoopAddTimer (CFRunLoopGetCurrent(), timer, kCFRunLoopCommonModes);
|
||||
#endif
|
||||
}
|
||||
|
||||
virtual ~AppDelegateRedirector()
|
||||
{
|
||||
CFRunLoopTimerInvalidate (timer);
|
||||
|
||||
#if MAC_OS_X_VERSION_MIN_REQUIRED > MAC_OS_X_VERSION_10_4
|
||||
CFRunLoopRemoveTimer (CFRunLoopGetMain(), timer, kCFRunLoopCommonModes);
|
||||
#else
|
||||
CFRunLoopRemoveTimer (CFRunLoopGetCurrent(), timer, kCFRunLoopCommonModes);
|
||||
#endif
|
||||
CFRelease (timer);
|
||||
|
||||
while (messages.size() > 0)
|
||||
delete ((Message*) messages.remove(0));
|
||||
}
|
||||
|
||||
virtual NSApplicationTerminateReply shouldTerminate()
|
||||
{
|
||||
|
|
@ -90,12 +118,6 @@ public:
|
|||
juce_HandleProcessFocusChange();
|
||||
}
|
||||
|
||||
virtual void deliverMessage (void* message)
|
||||
{
|
||||
// no need for an mm lock here - deliverMessage locks it
|
||||
MessageManager::getInstance()->deliverMessage (message);
|
||||
}
|
||||
|
||||
virtual void performCallback (CallbackMessagePayload* pl)
|
||||
{
|
||||
pl->result = (*pl->function) (pl->parameter);
|
||||
|
|
@ -106,23 +128,54 @@ public:
|
|||
{
|
||||
delete this;
|
||||
}
|
||||
|
||||
void postMessage (void* m) throw()
|
||||
{
|
||||
messages.add (m);
|
||||
CFRunLoopTimerSetNextFireDate (timer, CFAbsoluteTimeGetCurrent() - 0.5);
|
||||
}
|
||||
|
||||
private:
|
||||
CFRunLoopTimerRef timer;
|
||||
Array <void*, CriticalSection> messages;
|
||||
|
||||
void timerCallback() throw()
|
||||
{
|
||||
const int numToDispatch = jmin (4, messages.size());
|
||||
|
||||
for (int i = 0; i < numToDispatch; ++i)
|
||||
{
|
||||
void* const nextMessage = messages[i];
|
||||
|
||||
if (nextMessage != 0)
|
||||
MessageManager::getInstance()->deliverMessage (nextMessage);
|
||||
}
|
||||
|
||||
messages.removeRange (0, numToDispatch);
|
||||
|
||||
if (messages.size() > 0)
|
||||
CFRunLoopTimerSetNextFireDate (timer, CFAbsoluteTimeGetCurrent() - 0.5);
|
||||
}
|
||||
|
||||
static void timerCallbackStatic (CFRunLoopTimerRef, void* info)
|
||||
{
|
||||
((AppDelegateRedirector*) info)->timerCallback();
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
END_JUCE_NAMESPACE
|
||||
using namespace JUCE_NAMESPACE;
|
||||
|
||||
#define JuceAppDelegate MakeObjCClassName(JuceAppDelegate)
|
||||
|
||||
static int numPendingMessages = 0;
|
||||
|
||||
@interface JuceAppDelegate : NSObject
|
||||
{
|
||||
@private
|
||||
id oldDelegate;
|
||||
AppDelegateRedirector* redirector;
|
||||
|
||||
@public
|
||||
bool flushingMessages;
|
||||
AppDelegateRedirector* redirector;
|
||||
}
|
||||
|
||||
- (JuceAppDelegate*) init;
|
||||
|
|
@ -133,7 +186,6 @@ static int numPendingMessages = 0;
|
|||
- (void) applicationDidBecomeActive: (NSNotification*) aNotification;
|
||||
- (void) applicationDidResignActive: (NSNotification*) aNotification;
|
||||
- (void) applicationWillUnhide: (NSNotification*) aNotification;
|
||||
- (void) customEvent: (id) data;
|
||||
- (void) performCallback: (id) info;
|
||||
- (void) dummyMethod;
|
||||
@end
|
||||
|
|
@ -145,8 +197,6 @@ static int numPendingMessages = 0;
|
|||
[super init];
|
||||
|
||||
redirector = new AppDelegateRedirector();
|
||||
numPendingMessages = 0;
|
||||
flushingMessages = false;
|
||||
|
||||
NSNotificationCenter* center = [NSNotificationCenter defaultCenter];
|
||||
|
||||
|
|
@ -210,19 +260,6 @@ static int numPendingMessages = 0;
|
|||
redirector->focusChanged();
|
||||
}
|
||||
|
||||
- (void) customEvent: (id) n
|
||||
{
|
||||
atomicDecrement (numPendingMessages);
|
||||
|
||||
NSData* data = (NSData*) n;
|
||||
void* message = 0;
|
||||
[data getBytes: &message length: sizeof (message)];
|
||||
[data release];
|
||||
|
||||
if (message != 0 && ! flushingMessages)
|
||||
redirector->deliverMessage (message);
|
||||
}
|
||||
|
||||
- (void) performCallback: (id) info
|
||||
{
|
||||
if ([info isKindOfClass: [NSData class]])
|
||||
|
|
@ -400,18 +437,6 @@ void MessageManager::doPlatformSpecificShutdown()
|
|||
{
|
||||
[[NSRunLoop currentRunLoop] cancelPerformSelectorsWithTarget: juceAppDelegate];
|
||||
[[NSNotificationCenter defaultCenter] removeObserver: juceAppDelegate];
|
||||
|
||||
// Annoyingly, cancelPerformSelectorsWithTarget can't actually cancel the messages
|
||||
// sent by performSelectorOnMainThread, so need to manually flush these before quitting..
|
||||
juceAppDelegate->flushingMessages = true;
|
||||
|
||||
for (int i = 100; --i >= 0 && numPendingMessages > 0;)
|
||||
{
|
||||
const ScopedAutoReleasePool pool;
|
||||
[[NSRunLoop currentRunLoop] runMode: NSDefaultRunLoopMode
|
||||
beforeDate: [NSDate dateWithTimeIntervalSinceNow: 5 * 0.001]];
|
||||
}
|
||||
|
||||
[juceAppDelegate release];
|
||||
juceAppDelegate = 0;
|
||||
}
|
||||
|
|
@ -419,11 +444,7 @@ void MessageManager::doPlatformSpecificShutdown()
|
|||
|
||||
bool juce_postMessageToSystemQueue (void* message)
|
||||
{
|
||||
atomicIncrement (numPendingMessages);
|
||||
|
||||
[juceAppDelegate performSelectorOnMainThread: @selector (customEvent:)
|
||||
withObject: (id) [[NSData alloc] initWithBytes: &message length: (int) sizeof (message)]
|
||||
waitUntilDone: NO];
|
||||
juceAppDelegate->redirector->postMessage (message);
|
||||
return true;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -1531,20 +1531,34 @@ void juce_setKioskComponent (Component* kioskModeComponent, bool enableOrDisable
|
|||
}
|
||||
|
||||
//==============================================================================
|
||||
class AsyncRepaintMessage : public CallbackMessage
|
||||
{
|
||||
public:
|
||||
NSViewComponentPeer* const peer;
|
||||
const Rectangle rect;
|
||||
|
||||
AsyncRepaintMessage (NSViewComponentPeer* const peer_, const Rectangle& rect_)
|
||||
: peer (peer_), rect (rect_)
|
||||
{
|
||||
}
|
||||
|
||||
void messageCallback()
|
||||
{
|
||||
if (ComponentPeer::isValidPeer (peer))
|
||||
peer->repaint (rect.getX(), rect.getY(), rect.getWidth(), rect.getHeight());
|
||||
}
|
||||
};
|
||||
|
||||
void NSViewComponentPeer::repaint (int x, int y, int w, int h)
|
||||
{
|
||||
NSRect r = NSMakeRect ((float) x, (float) ([view frame].size.height - (y + h)),
|
||||
(float) w, (float) h);
|
||||
|
||||
if (insideDrawRect)
|
||||
{
|
||||
[view performSelectorOnMainThread: @selector (asyncRepaint:)
|
||||
withObject: [NSData dataWithBytes: &r length: sizeof (r)]
|
||||
waitUntilDone: NO];
|
||||
(new AsyncRepaintMessage (this, Rectangle (x, y, w, h)))->post();
|
||||
}
|
||||
else
|
||||
{
|
||||
[view setNeedsDisplayInRect: r];
|
||||
[view setNeedsDisplayInRect: NSMakeRect ((float) x, (float) ([view frame].size.height - (y + h)),
|
||||
(float) w, (float) h)];
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue