+void wxApp::WakeUpIdle()
+{
+ /* When called from the main thread the NSAutoreleasePool managed by
+ the [NSApplication run] method would ordinarily be in place and so
+ one would think a pool here would be unnecessary.
+
+ However, when called from a different thread there is usually no
+ NSAutoreleasePool in place because wxThread has no knowledge of
+ wxCocoa. The pool here is generally only ever going to contain
+ the NSEvent we create with the factory method. As soon as we add
+ it to the main event queue with postEvent:atStart: it is retained
+ and so safe for our pool to release.
+ */
+ wxAutoNSAutoreleasePool pool;
+ /* NOTE: This is a little heavy handed. What this does is cause an
+ AppKit NSEvent to be added to NSApplication's queue (which is always
+ on the main thread). This will cause the main thread runloop to
+ exit which returns control to nextEventMatchingMask which returns
+ the event which is then sent with sendEvent: and essentially dropped
+ since it's not for a window (windowNumber 0) and NSApplication
+ certainly doesn't understand it.
+
+ With the exception of wxEventLoop::Exit which uses us to cause the
+ runloop to exit and return to the NSApplication event loop, most
+ callers only need wx idle to happen, or more specifically only really
+ need to ensure that ProcessPendingEvents is called which is currently
+ done without exiting the runloop.
+
+ Be careful if you decide to change the implementation of this method
+ as wxEventLoop::Exit depends on the current behavior.
+ */
+ [m_cocoaApp postEvent:[NSEvent otherEventWithType:NSApplicationDefined
+ location:NSZeroPoint modifierFlags:NSAnyEventMask
+ timestamp:0 windowNumber:0 context:nil
+ subtype:0 data1:0 data2:0] atStart:NO];
+}
+
+extern "C" static void ObserveMainRunLoopBeforeWaiting(CFRunLoopObserverRef observer, CFRunLoopActivity activity, void *info);
+extern "C" static void ObserveMainRunLoopBeforeWaiting(CFRunLoopObserverRef observer, CFRunLoopActivity activity, void *info)
+{
+ static_cast<wxApp*>(info)->CF_ObserveMainRunLoopBeforeWaiting(observer, activity);
+}
+
+#if 0
+static int sg_cApplicationWillUpdate = 0;
+#endif
+
+/*!
+ Invoked from the applicationWillUpdate notification observer. See the
+ NSApplication documentation for the official statement on when this
+ will be called. Since it can be hard to understand for a Cocoa newbie
+ I'll try to explain it here as it relates to wxCocoa.
+
+ Basically, we get called from within nextEventMatchingMask if and only
+ if any user code told the application to send the update notification
+ (sort of like a request for idle events). However, unlike wx idle events,
+ this notification is sent quite often, nearly every time through the loop
+ because nearly every control tells the application to send it.
+
+ Because wx idle events are only supposed to be sent when the event loop
+ is about to block we instead schedule a function to be called just
+ before the run loop waits and send the idle events from there.
+
+ It also has the desirable effect of only sending the wx idle events when
+ the event loop is actualy going to block. If the event loop is being
+ pumped manualy (e.g. like a PeekMessage) then the kCFRunLoopBeforeWaiting
+ observer never fires. Our Yield() method depends on this because sending
+ idle events from within Yield would be bad.
+
+ Normally you might think that we could just set the observer up once and
+ leave it attached. However, this is problematic because our run loop
+ observer calls user code (the idle handlers) which can actually display
+ modal dialogs. Displaying a modal dialog causes reentry of the event
+ loop, usually in a different run loop mode than the main loop (e.g. in
+ modal-dialog mode instead of default mode). Because we only register the
+ observer with the run loop mode at the time of this call, it won't be
+ called from a modal loop.
+
+ We want it to be called and thus we need a new observer.
+ */
+void wxApp::CocoaDelegate_applicationWillUpdate()
+{
+ wxLogTrace(wxTRACE_COCOA,wxT("applicationWillUpdate"));
+
+// CFRunLoopRef cfRunLoop = [[NSRunLoop currentRunLoop] getCFRunLoop];
+ CFRunLoopRef cfRunLoop = CFRunLoopGetCurrent();
+ wxCFRef<CFStringRef> cfRunLoopMode(CFRunLoopCopyCurrentMode(cfRunLoop));
+
+ /* If we have an observer and that observer is for the wrong run loop
+ mode then invalidate it and release it.
+ */
+ if(m_cfRunLoopIdleObserver != NULL && m_cfObservedRunLoopMode != cfRunLoopMode)
+ {
+ CFRunLoopObserverInvalidate(m_cfRunLoopIdleObserver);
+ m_cfRunLoopIdleObserver.reset();
+ }
+#if 0
+ ++sg_cApplicationWillUpdate;
+#endif
+ /* This will be true either on the first call or when the above code has
+ invalidated and released the exisiting observer.
+ */
+ if(m_cfRunLoopIdleObserver == NULL)
+ {
+ // Enable idle event handling
+ CFRunLoopObserverContext observerContext =
+ { 0
+ , this
+ , NULL
+ , NULL
+ , NULL
+ };
+ /* NOTE: I can't recall why we don't just let the observer repeat
+ instead of invalidating itself each time it fires thus requiring
+ it to be recreated for each shot but there was if I remember
+ some good (but very obscure) reason for it.
+
+ On the other hand, I could be wrong so don't take that as gospel.
+ */
+ m_cfRunLoopIdleObserver.reset(CFRunLoopObserverCreate(kCFAllocatorDefault, kCFRunLoopBeforeWaiting, /*repeats*/FALSE, /*priority*/0, ObserveMainRunLoopBeforeWaiting, &observerContext));
+ m_cfObservedRunLoopMode = cfRunLoopMode;
+ CFRunLoopAddObserver(cfRunLoop, m_cfRunLoopIdleObserver, m_cfObservedRunLoopMode);
+ }
+}
+
+static inline bool FakeNeedMoreIdle()
+{
+#if 0
+// Return true on every 10th call.
+ static int idleCount = 0;
+ return ++idleCount % 10;
+#else
+ return false;
+#endif
+}
+
+/*!
+ Called by CFRunLoop just before waiting. This is the appropriate time to
+ send idle events. Unlike other ports, we don't peek the queue for events
+ and stop idling if there is one. Instead, if the user requests more idle
+ events we tell Cocoa to send us an applicationWillUpdate notification
+ which will cause our observer of that notification to tell CFRunLoop to
+ call us before waiting which will cause us to be fired again but only
+ after exhausting the event queue.
+
+ The reason we do it this way is that peeking for an event causes CFRunLoop
+ to reenter and fire off its timers, observers, and sources which we're
+ better off avoiding. Doing it this way, we basically let CFRunLoop do the
+ work of peeking for the next event which is much nicer.
+ */
+void wxApp::CF_ObserveMainRunLoopBeforeWaiting(CFRunLoopObserverRef observer, int activity)
+{
+ // Ensure that CocoaDelegate_applicationWillUpdate will recreate us.
+ // We've already been invalidated by CFRunLoop because we are one-shot.
+ m_cfRunLoopIdleObserver.reset();
+#if 0
+ wxLogTrace(wxTRACE_COCOA,wxT("Idle BEGIN (%d)"), sg_cApplicationWillUpdate);
+ sg_cApplicationWillUpdate = 0;
+#else
+ wxLogTrace(wxTRACE_COCOA,wxT("Idle BEGIN"));
+#endif
+ if( ProcessIdle() || FakeNeedMoreIdle() )
+ {
+ wxLogTrace(wxTRACE_COCOA, wxT("Idle REQUEST MORE"));
+ [NSApp setWindowsNeedUpdate:YES];
+ }
+ else
+ {
+ wxLogTrace(wxTRACE_COCOA, wxT("Idle END"));
+ }
+}
+