0

Mac-specific CFRunLoop-based MessagePump implementation

Review URL: http://codereview.chromium.org/444

git-svn-id: svn://svn.chromium.org/chrome/trunk/src@2521 0039d316-1c4b-4281-b951-d872f2087c98
This commit is contained in:
mark@chromium.org
2008-09-23 21:08:28 +00:00
parent 0aaaa256de
commit 96c9ea12f0
5 changed files with 573 additions and 7 deletions

@ -80,6 +80,8 @@
7B8505D90E5B445100730B43 /* libbase_gfx.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 825403B10D92D2E50006B936 /* libbase_gfx.a */; };
7B85062A0E5B556900730B43 /* libpng.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 7B165D5E0E55081400185273 /* libpng.a */; };
7B85062F0E5B559A00730B43 /* libzlib.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 7B165D6E0E55081400185273 /* libzlib.a */; };
7BA355EB0E898C100023C8B9 /* message_pump_mac.mm in Sources */ = {isa = PBXBuildFile; fileRef = 7BA355EA0E898C100023C8B9 /* message_pump_mac.mm */; };
7BA3562C0E898F880023C8B9 /* AppKit.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 7BA3562B0E898F7B0023C8B9 /* AppKit.framework */; };
7BAE30E50E6D939F00C3F750 /* atomicops_unittest.cc in Sources */ = {isa = PBXBuildFile; fileRef = 7BAE30E10E6D939800C3F750 /* atomicops_unittest.cc */; };
7BAE30E60E6D939F00C3F750 /* simple_thread_unittest.cc in Sources */ = {isa = PBXBuildFile; fileRef = 7BAE30E40E6D939800C3F750 /* simple_thread_unittest.cc */; };
7BAE30E70E6D93A300C3F750 /* simple_thread.cc in Sources */ = {isa = PBXBuildFile; fileRef = 7BAE30E20E6D939800C3F750 /* simple_thread.cc */; };
@ -237,14 +239,14 @@
isa = PBXContainerItemProxy;
containerPortal = 7B26301F0E82F1E6001CE27F /* libevent.xcodeproj */;
proxyType = 2;
remoteGlobalIDString = 7B262E840E82E5D7001CE27F /* libevent.a */;
remoteGlobalIDString = 7B262E840E82E5D7001CE27F;
remoteInfo = libevent;
};
7B2630250E82F1EF001CE27F /* PBXContainerItemProxy */ = {
isa = PBXContainerItemProxy;
containerPortal = 7B26301F0E82F1E6001CE27F /* libevent.xcodeproj */;
proxyType = 1;
remoteGlobalIDString = 7B262E830E82E5D7001CE27F /* libevent */;
remoteGlobalIDString = 7B262E830E82E5D7001CE27F;
remoteInfo = libevent;
};
7B4DF5310E5B6A4B004D7619 /* PBXContainerItemProxy */ = {
@ -379,6 +381,9 @@
7B8505A50E5B3FBE00730B43 /* skia_utils.cc */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = skia_utils.cc; sourceTree = "<group>"; };
7B8505A60E5B3FBE00730B43 /* skia_utils.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = skia_utils.h; sourceTree = "<group>"; };
7B8505A80E5B3FBE00730B43 /* vector_canvas_unittest.cc */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = vector_canvas_unittest.cc; sourceTree = "<group>"; };
7BA355E90E898C100023C8B9 /* message_pump_mac.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = message_pump_mac.h; sourceTree = "<group>"; };
7BA355EA0E898C100023C8B9 /* message_pump_mac.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; path = message_pump_mac.mm; sourceTree = "<group>"; };
7BA3562B0E898F7B0023C8B9 /* AppKit.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = AppKit.framework; path = System/Library/Frameworks/AppKit.framework; sourceTree = "<group>"; };
7BAE30E10E6D939800C3F750 /* atomicops_unittest.cc */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = atomicops_unittest.cc; sourceTree = "<group>"; };
7BAE30E20E6D939800C3F750 /* simple_thread.cc */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = simple_thread.cc; sourceTree = "<group>"; };
7BAE30E30E6D939800C3F750 /* simple_thread.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = simple_thread.h; sourceTree = "<group>"; };
@ -660,6 +665,7 @@
isa = PBXFrameworksBuildPhase;
buildActionMask = 2147483647;
files = (
7BA3562C0E898F880023C8B9 /* AppKit.framework in Frameworks */,
ABE1BA2A0E7574D1009041DA /* ApplicationServices.framework in Frameworks */,
7B78D40E0E54FE8000609465 /* Foundation.framework in Frameworks */,
7B78D38C0E54FDEC00609465 /* libbase.a in Frameworks */,
@ -870,6 +876,8 @@
93611ADD0E5A7FC500F9405D /* message_pump_default.h */,
7B26302D0E82F218001CE27F /* message_pump_libevent.cc */,
7B26302E0E82F218001CE27F /* message_pump_libevent.h */,
7BA355E90E898C100023C8B9 /* message_pump_mac.h */,
7BA355EA0E898C100023C8B9 /* message_pump_mac.mm */,
7BF8828F0E719389000BAF8A /* non_thread_safe.cc */,
7BF882900E719389000BAF8A /* non_thread_safe.h */,
825403390D92D2210006B936 /* observer_list.h */,
@ -1066,6 +1074,7 @@
829E2FA80DBFD7D500819EBF /* Frameworks */ = {
isa = PBXGroup;
children = (
7BA3562B0E898F7B0023C8B9 /* AppKit.framework */,
ABE1BA290E7574D1009041DA /* ApplicationServices.framework */,
7B78D40D0E54FE8000609465 /* Foundation.framework */,
);
@ -1317,6 +1326,7 @@
93611AE10E5A7FE200F9405D /* message_loop.cc in Sources */,
93611ADF0E5A7FC500F9405D /* message_pump_default.cc in Sources */,
7B26302F0E82F218001CE27F /* message_pump_libevent.cc in Sources */,
7BA355EB0E898C100023C8B9 /* message_pump_mac.mm in Sources */,
7BF882910E719389000BAF8A /* non_thread_safe.cc in Sources */,
ABF4B9B50DC2BC9F00A6E319 /* path_service.cc in Sources */,
824654A60DC25CD7007C2BAA /* pickle.cc in Sources */,

@ -13,6 +13,9 @@
#include "base/string_util.h"
#include "base/thread_local.h"
#if defined(OS_MACOSX)
#include "base/message_pump_mac.h"
#endif
#if defined(OS_POSIX)
#include "base/message_pump_libevent.h"
#endif
@ -83,14 +86,19 @@ MessageLoop::MessageLoop(Type type)
pump_ = new base::MessagePumpWin();
}
#elif defined(OS_POSIX)
#if defined(OS_MACOSX)
if (type_ == TYPE_UI) {
pump_ = base::MessagePumpMac::Create();
} else
#endif // OS_MACOSX
if (type_ == TYPE_IO) {
pump_ = new base::MessagePumpLibevent();
} else {
pump_ = new base::MessagePumpDefault();
}
#else
#else // OS_POSIX
pump_ = new base::MessagePumpDefault();
#endif
#endif // OS_POSIX
}
MessageLoop::~MessageLoop() {

181
base/message_pump_mac.h Normal file

@ -0,0 +1,181 @@
// Copyright (c) 2008 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
// The basis for all native run loops on the Mac is the CFRunLoop. It can be
// used directly, it can be used as the driving force behind the similar
// Foundation NSRunLoop, and it can be used to implement higher-level event
// loops such as the NSApplication event loop.
//
// This file introduces a basic CFRunLoop-based implementation of the
// MessagePump interface called CFRunLoopBase. CFRunLoopBase contains all
// of the machinery necessary to dispatch events to a delegate, but does not
// implement the specific run loop. Concrete subclasses must provide their
// own DoRun and Quit implementations.
//
// A concrete subclass that just runs a CFRunLoop loop is provided in
// MessagePumpCFRunLoop. For an NSRunLoop, the similar MessagePumpNSRunLoop
// is provided.
//
// For the application's event loop, an implementation based on AppKit's
// NSApplication event system is provided in MessagePumpNSApplication.
//
// Typically, MessagePumpNSApplication only makes sense on a Cocoa
// application's main thread. If a CFRunLoop-based message pump is needed on
// any other thread, one of the other concrete subclasses is preferrable.
// MessagePumpMac::Create is defined, which returns a new NSApplication-based
// or NSRunLoop-based MessagePump subclass depending on which thread it is
// called on.
#ifndef BASE_MESSAGE_PUMP_MAC_H_
#define BASE_MESSAGE_PUMP_MAC_H_
#include "base/message_pump.h"
#include <CoreFoundation/CoreFoundation.h>
#include "base/time.h"
namespace base {
class MessagePumpCFRunLoopBase : public MessagePump {
public:
MessagePumpCFRunLoopBase();
virtual ~MessagePumpCFRunLoopBase();
// Subclasses should implement the work they need to do in MessagePump::Run
// in the DoRun method. MessagePumpCFRunLoopBase::Run calls DoRun directly.
// This arrangement is used because MessagePumpCFRunLoopBase needs to set
// up and tear down things before and after the "meat" of DoRun.
virtual void Run(Delegate* delegate);
virtual void DoRun(Delegate* delegate) = 0;
virtual void ScheduleWork();
virtual void ScheduleDelayedWork(const Time& delayed_work_time);
protected:
// The thread's run loop.
CFRunLoopRef run_loop_;
private:
// Timer callback scheduled by ScheduleDelayedWork. This does not do any
// work, but it signals delayed_work_source_ so that delayed work can be
// performed within the appropriate priority constraints.
static void RunDelayedWorkTimer(CFRunLoopTimerRef timer, void* info);
// Perform highest-priority work. This is associated with work_source_
// signalled by ScheduleWork.
static void RunWork(void* info);
// Perform delayed-priority work. This is associated with
// delayed_work_source_ signalled by RunDelayedWorkTimer, and is responsible
// for calling ScheduleDelayedWork again if appropriate.
static void RunDelayedWork(void* info);
// Observer callback responsible for performing idle-priority work, before
// the run loop goes to sleep. Associated with idle_work_observer_.
static void RunIdleWork(CFRunLoopObserverRef observer,
CFRunLoopActivity activity, void* info);
// The timer, sources, and observer are described above alongside their
// callbacks.
CFRunLoopTimerRef delayed_work_timer_;
CFRunLoopSourceRef work_source_;
CFRunLoopSourceRef delayed_work_source_;
CFRunLoopObserverRef idle_work_observer_;
// (weak) Delegate passed as an argument to the innermost Run call.
Delegate* delegate_;
DISALLOW_COPY_AND_ASSIGN(MessagePumpCFRunLoopBase);
};
class MessagePumpCFRunLoop : public MessagePumpCFRunLoopBase {
public:
MessagePumpCFRunLoop();
virtual ~MessagePumpCFRunLoop();
virtual void DoRun(Delegate* delegate);
virtual void Quit();
private:
// Observer callback called when the run loop starts and stops, at the
// beginning and end of calls to CFRunLoopRun. This is used to maintain
// nesting_level_ and to handle deferred loop quits. Associated with
// enter_exit_observer_.
static void EnterExitRunLoop(CFRunLoopObserverRef observer,
CFRunLoopActivity activity, void* info);
// Observer for EnterExitRunLoop.
CFRunLoopObserverRef enter_exit_observer_;
// The recursion depth of the currently-executing CFRunLoopRun loop on the
// run loop's thread. 0 if no run loops are running inside of whatever scope
// the object was created in.
int nesting_level_;
// The recursion depth (calculated in the same way as nesting_level_) of the
// innermost executing CFRunLoopRun loop started by a call to Run.
int innermost_quittable_;
// True if Quit is called to stop the innermost MessagePump
// (innermost_quittable_) but some other CFRunLoopRun loop (nesting_level_)
// is running inside the MessagePump's innermost Run call.
bool quit_pending_;
DISALLOW_COPY_AND_ASSIGN(MessagePumpCFRunLoop);
};
class MessagePumpNSRunLoop : public MessagePumpCFRunLoopBase {
public:
MessagePumpNSRunLoop();
virtual ~MessagePumpNSRunLoop();
virtual void DoRun(Delegate* delegate);
virtual void Quit();
private:
// A source that doesn't do anything but provide something signalable
// attached to the run loop. This source will be signalled when Quit
// is called, to cause the loop to wake up so that it can stop.
CFRunLoopSourceRef quit_source_;
// False after Quit is called.
bool keep_running_;
DISALLOW_COPY_AND_ASSIGN(MessagePumpNSRunLoop);
};
class MessagePumpNSApplication : public MessagePumpCFRunLoopBase {
public:
MessagePumpNSApplication();
virtual void DoRun(Delegate* delegate);
virtual void Quit();
private:
// False after Quit is called.
bool keep_running_;
// True if DoRun is managing its own run loop as opposed to letting
// -[NSApplication run] handle it. The outermost run loop in the application
// is managed by -[NSApplication run], inner run loops are handled by a loop
// in DoRun.
bool running_own_loop_;
DISALLOW_COPY_AND_ASSIGN(MessagePumpNSApplication);
};
class MessagePumpMac {
public:
// Returns a new instance of MessagePumpNSApplication if called on the main
// thread. Otherwise, returns a new instance of MessagePumpNSRunLoop.
static MessagePump* Create();
private:
DISALLOW_IMPLICIT_CONSTRUCTORS(MessagePumpMac);
};
} // namespace base
#endif // BASE_MESSAGE_PUMP_MAC_H_

363
base/message_pump_mac.mm Normal file

@ -0,0 +1,363 @@
// Copyright (c) 2008 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "base/message_pump_mac.h"
#import <AppKit/AppKit.h>
#import <Foundation/Foundation.h>
#include <float.h>
namespace {
void NoOp(void* info) {
}
} // namespace
namespace base {
// Must be called on the run loop thread.
MessagePumpCFRunLoopBase::MessagePumpCFRunLoopBase()
: delegate_(NULL) {
run_loop_ = CFRunLoopGetCurrent();
CFRetain(run_loop_);
// Set a repeating timer with a preposterous firing time and interval. The
// timer will effectively never fire as-is. The firing time will be adjusted
// as needed when ScheduleDelayedWork is called.
CFRunLoopTimerContext timer_context = CFRunLoopTimerContext();
timer_context.info = this;
delayed_work_timer_ = CFRunLoopTimerCreate(NULL, // allocator
DBL_MAX, // fire time
DBL_MAX, // interval
0, // flags (ignored)
0, // priority (ignored)
RunDelayedWorkTimer,
&timer_context);
CFRunLoopAddTimer(run_loop_, delayed_work_timer_, kCFRunLoopCommonModes);
CFRunLoopSourceContext source_context = CFRunLoopSourceContext();
source_context.info = this;
source_context.perform = RunWork;
work_source_ = CFRunLoopSourceCreate(NULL, // allocator
0, // priority
&source_context);
CFRunLoopAddSource(run_loop_, work_source_, kCFRunLoopCommonModes);
source_context.perform = RunDelayedWork;
delayed_work_source_ = CFRunLoopSourceCreate(NULL, // allocator
1, // priority
&source_context);
CFRunLoopAddSource(run_loop_, delayed_work_source_, kCFRunLoopCommonModes);
CFRunLoopObserverContext observer_context = CFRunLoopObserverContext();
observer_context.info = this;
idle_work_observer_ = CFRunLoopObserverCreate(NULL, // allocator
kCFRunLoopBeforeWaiting,
true, // repeat
0, // priority
RunIdleWork,
&observer_context);
CFRunLoopAddObserver(run_loop_, idle_work_observer_, kCFRunLoopCommonModes);
}
// Ideally called on the run loop thread.
MessagePumpCFRunLoopBase::~MessagePumpCFRunLoopBase() {
CFRunLoopRemoveObserver(run_loop_, idle_work_observer_,
kCFRunLoopCommonModes);
CFRelease(idle_work_observer_);
CFRunLoopRemoveSource(run_loop_, delayed_work_source_, kCFRunLoopCommonModes);
CFRelease(delayed_work_source_);
CFRunLoopRemoveSource(run_loop_, work_source_, kCFRunLoopCommonModes);
CFRelease(work_source_);
CFRunLoopRemoveTimer(run_loop_, delayed_work_timer_, kCFRunLoopCommonModes);
CFRelease(delayed_work_timer_);
CFRelease(run_loop_);
}
// Must be called on the run loop thread.
void MessagePumpCFRunLoopBase::Run(Delegate* delegate) {
Delegate* last_delegate = delegate_;
delegate_ = delegate;
DoRun(delegate);
delegate_ = last_delegate;
}
// May be called on any thread.
void MessagePumpCFRunLoopBase::ScheduleWork() {
CFRunLoopSourceSignal(work_source_);
CFRunLoopWakeUp(run_loop_);
}
// Must be called on the run loop thread.
void MessagePumpCFRunLoopBase::ScheduleDelayedWork(
const Time& delayed_work_time) {
Time::Exploded exploded;
delayed_work_time.UTCExplode(&exploded);
double seconds = exploded.second +
(static_cast<double>((delayed_work_time.ToInternalValue()) %
Time::kMicrosecondsPerSecond) /
Time::kMicrosecondsPerSecond);
CFGregorianDate gregorian = {
exploded.year,
exploded.month,
exploded.day_of_month,
exploded.hour,
exploded.minute,
seconds
};
CFAbsoluteTime fire_time = CFGregorianDateGetAbsoluteTime(gregorian, NULL);
CFRunLoopTimerSetNextFireDate(delayed_work_timer_, fire_time);
}
// Called from the run loop.
// static
void MessagePumpCFRunLoopBase::RunDelayedWorkTimer(CFRunLoopTimerRef timer,
void* info) {
MessagePumpCFRunLoop* self = static_cast<MessagePumpCFRunLoop*>(info);
// CFRunLoopTimers fire outside of the priority scheme for CFRunLoopSources.
// In order to establish the proper priority where delegate_->DoDelayedWork
// can only be called if delegate_->DoWork returns false, the timer used
// to schedule delayed work must signal a CFRunLoopSource set at a lower
// priority than the one used for delegate_->DoWork.
CFRunLoopSourceSignal(self->delayed_work_source_);
}
// Called from the run loop.
// static
void MessagePumpCFRunLoopBase::RunWork(void* info) {
MessagePumpCFRunLoop* self = static_cast<MessagePumpCFRunLoop*>(info);
// Call DoWork once, and if something was done, arrange to come back here
// again as long as the loop is still running.
if (self->delegate_->DoWork()) {
CFRunLoopSourceSignal(self->work_source_);
}
}
// Called from the run loop.
// static
void MessagePumpCFRunLoopBase::RunDelayedWork(void* info) {
MessagePumpCFRunLoop* self = static_cast<MessagePumpCFRunLoop*>(info);
Time next_time;
self->delegate_->DoDelayedWork(&next_time);
if (!next_time.is_null()) {
TimeDelta delay = next_time - Time::Now();
if (delay > TimeDelta()) {
// There's more delayed work to be done in the future.
self->ScheduleDelayedWork(next_time);
} else {
// There's more delayed work to be done, and its time is in the past.
// Arrange to come back here directly as long as the loop is still
// running.
CFRunLoopSourceSignal(self->delayed_work_source_);
}
}
}
// Called from the run loop.
// static
void MessagePumpCFRunLoopBase::RunIdleWork(CFRunLoopObserverRef observer,
CFRunLoopActivity activity,
void* info) {
MessagePumpCFRunLoop* self = static_cast<MessagePumpCFRunLoop*>(info);
if (self->delegate_->DoIdleWork()) {
// If idle work was done, don't let the loop go to sleep. More idle work
// might be waiting.
CFRunLoopWakeUp(self->run_loop_);
}
}
// Must be called on the run loop thread.
MessagePumpCFRunLoop::MessagePumpCFRunLoop()
: nesting_level_(0),
innermost_quittable_(0),
quit_pending_(false) {
CFRunLoopObserverContext observer_context = CFRunLoopObserverContext();
observer_context.info = this;
enter_exit_observer_ = CFRunLoopObserverCreate(NULL, // allocator
kCFRunLoopEntry |
kCFRunLoopExit,
true, // repeat
0, // priority
EnterExitRunLoop,
&observer_context);
CFRunLoopAddObserver(run_loop_, enter_exit_observer_, kCFRunLoopCommonModes);
}
// Ideally called on the run loop thread. If other CFRunLoopRun loops were
// running lower on the run loop thread's stack when this object was created,
// the same number of CFRunLoopRun loops must be running when this object is
// destroyed.
MessagePumpCFRunLoop::~MessagePumpCFRunLoop() {
CFRunLoopRemoveObserver(run_loop_, enter_exit_observer_,
kCFRunLoopCommonModes);
CFRelease(enter_exit_observer_);
}
// Called by CFRunLoopBase::DoRun. If other CFRunLoopRun loops were running
// lower on the run loop thread's stack when this object was created, the same
// number of CFRunLoopRun loops must be running for the outermost call to Run.
// Run/DoRun are reentrant after that point.
void MessagePumpCFRunLoop::DoRun(Delegate* delegate) {
// nesting_level_ will be incremented in EnterExitRunLoop, so set
// innermost_quittable_ accordingly.
int last_innermost_quittable = innermost_quittable_;
innermost_quittable_ = nesting_level_ + 1;
CFRunLoopRun();
// Restore the previous state of the object.
innermost_quittable_ = last_innermost_quittable;
}
// Must be called on the run loop thread.
void MessagePumpCFRunLoop::Quit() {
// Stop the innermost run loop managed by this MessagePumpCFRunLoop object.
if (nesting_level_ == innermost_quittable_) {
// This object is running the innermost loop, just stop it.
CFRunLoopStop(run_loop_);
} else {
// There's another loop running inside the loop managed by this object.
// In other words, someone else called CFRunLoopRun on the same thread,
// higher on the stack than our highest Run call. Don't preempt other
// run loops, just mark the object to quit our innermost run loop as soon
// as the other inner loops we don't manage are done.
quit_pending_ = true;
}
}
// Called from the run loop.
// static
void MessagePumpCFRunLoop::EnterExitRunLoop(CFRunLoopObserverRef observer,
CFRunLoopActivity activity,
void* info) {
MessagePumpCFRunLoop* self = static_cast<MessagePumpCFRunLoop*>(info);
switch (activity) {
case kCFRunLoopEntry:
// If the run loop was entered by a call to Run, this will properly
// balance the decrement done in Run before entering the loop.
++self->nesting_level_;
break;
case kCFRunLoopExit:
if (--self->nesting_level_ == self->innermost_quittable_ &&
self->quit_pending_) {
// Quit was called while loops other than those managed by this object
// were running further inside a run loop managed by this object. Now
// that all unmanaged inner run loops are gone, stop the loop running
// just inside Run.
CFRunLoopStop(self->run_loop_);
self->quit_pending_ = false;
}
break;
default:
break;
}
}
MessagePumpNSRunLoop::MessagePumpNSRunLoop()
: keep_running_(true) {
CFRunLoopSourceContext source_context = CFRunLoopSourceContext();
source_context.perform = NoOp;
quit_source_ = CFRunLoopSourceCreate(NULL, // allocator
0, // priority
&source_context);
CFRunLoopAddSource(run_loop_, quit_source_, kCFRunLoopCommonModes);
}
MessagePumpNSRunLoop::~MessagePumpNSRunLoop() {
CFRunLoopRemoveSource(run_loop_, quit_source_, kCFRunLoopCommonModes);
CFRelease(quit_source_);
}
void MessagePumpNSRunLoop::DoRun(Delegate* delegate) {
while (keep_running_) {
// NSRunLoop manages autorelease pools itself.
[[NSRunLoop currentRunLoop] runMode:NSDefaultRunLoopMode
beforeDate:[NSDate distantFuture]];
}
keep_running_ = true;
}
void MessagePumpNSRunLoop::Quit() {
keep_running_ = false;
CFRunLoopSourceSignal(quit_source_);
CFRunLoopWakeUp(run_loop_);
}
MessagePumpNSApplication::MessagePumpNSApplication()
: keep_running_(true),
running_own_loop_(false) {
}
void MessagePumpNSApplication::DoRun(Delegate* delegate) {
bool last_running_own_loop_ = running_own_loop_;
[NSApplication sharedApplication];
if (![NSApp isRunning]) {
running_own_loop_ = false;
// NSApplication manages autorelease pools itself when run this way.
[NSApp run];
} else {
running_own_loop_ = true;
while (keep_running_) {
NSAutoreleasePool* autorelease_pool = [[NSAutoreleasePool alloc] init];
NSEvent* event = [NSApp nextEventMatchingMask:NSAnyEventMask
untilDate:[NSDate distantFuture]
inMode:NSDefaultRunLoopMode
dequeue:YES];
if (event) {
[NSApp sendEvent:event];
}
[autorelease_pool drain];
}
keep_running_ = true;
}
running_own_loop_ = last_running_own_loop_;
}
void MessagePumpNSApplication::Quit() {
if (!running_own_loop_) {
[NSApp stop:nil];
} else {
keep_running_ = false;
}
// Send a fake event to wake the loop up.
[NSApp postEvent:[NSEvent otherEventWithType:NSApplicationDefined
location:NSMakePoint(0,0)
modifierFlags:0
timestamp:0
windowNumber:0
context:NULL
subtype:0
data1:0
data2:0]
atStart:NO];
}
// static
MessagePump* MessagePumpMac::Create() {
if ([NSThread isMainThread]) {
return new MessagePumpNSApplication;
}
return new MessagePumpNSRunLoop;
}
} // namespace base

@ -100,6 +100,7 @@
7BA0169E0E5A1EAE00044150 /* libzlib.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 7BA016980E5A1E8700044150 /* libzlib.a */; };
7BA016A30E5A1EE900044150 /* gzip_header.cc in Sources */ = {isa = PBXBuildFile; fileRef = 7BED32B70E5A181C00A747DB /* gzip_header.cc */; };
7BA0172F0E5A244D00044150 /* bzip2_filter.cc in Sources */ = {isa = PBXBuildFile; fileRef = 7BED32750E5A181C00A747DB /* bzip2_filter.cc */; };
7BA359120E89903B0023C8B9 /* AppKit.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 7BA357A60E8990260023C8B9 /* AppKit.framework */; };
7BD8F70C0E65DCD800034DE9 /* block_files_unittest.cc in Sources */ = {isa = PBXBuildFile; fileRef = 7BED32F90E5A190600A747DB /* block_files_unittest.cc */; };
7BD8F70D0E65DCE000034DE9 /* disk_cache_test_base.cc in Sources */ = {isa = PBXBuildFile; fileRef = 7BED32D50E5A190600A747DB /* disk_cache_test_base.cc */; };
7BD8F70E0E65DCE500034DE9 /* disk_cache_test_util.cc in Sources */ = {isa = PBXBuildFile; fileRef = 7BED32FA0E5A190600A747DB /* disk_cache_test_util.cc */; };
@ -370,6 +371,7 @@
7BA0157A0E5A1C9100044150 /* Foundation.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Foundation.framework; path = System/Library/Frameworks/Foundation.framework; sourceTree = "<group>"; };
7BA016870E5A1E6E00044150 /* bzip2.xcodeproj */ = {isa = PBXFileReference; lastKnownFileType = "wrapper.pb-project"; name = bzip2.xcodeproj; path = third_party/bzip2/bzip2.xcodeproj; sourceTree = "<group>"; };
7BA016930E5A1E8700044150 /* zlib.xcodeproj */ = {isa = PBXFileReference; lastKnownFileType = "wrapper.pb-project"; name = zlib.xcodeproj; path = third_party/zlib/zlib.xcodeproj; sourceTree = "<group>"; };
7BA357A60E8990260023C8B9 /* AppKit.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = AppKit.framework; path = System/Library/Frameworks/AppKit.framework; sourceTree = "<group>"; };
7BED316E0E5A145200A747DB /* common.xcconfig */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.xcconfig; path = common.xcconfig; sourceTree = "<group>"; };
7BED316F0E5A145200A747DB /* debug.xcconfig */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.xcconfig; path = debug.xcconfig; sourceTree = "<group>"; };
7BED31700E5A145200A747DB /* executable.xcconfig */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.xcconfig; path = executable.xcconfig; sourceTree = "<group>"; };
@ -590,9 +592,9 @@
7BED33BA0E5A198600A747DB /* url_request_file_job.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = url_request_file_job.h; sourceTree = "<group>"; };
7BED33BB0E5A198600A747DB /* url_request_inet_job.cc */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = url_request_inet_job.cc; sourceTree = "<group>"; };
7BED33BC0E5A198600A747DB /* url_request_http_job.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = url_request_http_job.h; sourceTree = "<group>"; };
8200F2020E5F741E005A3C44 /* CoreServices.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = CoreServices.framework; path = /System/Library/Frameworks/CoreServices.framework; sourceTree = "<absolute>"; };
8200F2020E5F741E005A3C44 /* CoreServices.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = CoreServices.framework; path = System/Library/Frameworks/CoreServices.framework; sourceTree = "<group>"; };
82113A1C0E8434EE00E3848F /* x509_certificate_unittest.cc */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = x509_certificate_unittest.cc; sourceTree = "<group>"; };
82113A270E84360200E3848F /* Security.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Security.framework; path = /System/Library/Frameworks/Security.framework; sourceTree = "<absolute>"; };
82113A270E84360200E3848F /* Security.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Security.framework; path = System/Library/Frameworks/Security.framework; sourceTree = "<group>"; };
E47E933E0E8924DC00CA613E /* tcp_client_socket_libevent.cc */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = tcp_client_socket_libevent.cc; sourceTree = "<group>"; };
E49DD2E80E892F8C003C7A87 /* sdch_manager.cc */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = sdch_manager.cc; sourceTree = "<group>"; };
E49DD2E90E892F8C003C7A87 /* sdch_manager.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = sdch_manager.h; sourceTree = "<group>"; };
@ -619,6 +621,7 @@
isa = PBXFrameworksBuildPhase;
buildActionMask = 2147483647;
files = (
7BA359120E89903B0023C8B9 /* AppKit.framework in Frameworks */,
8200F2030E5F741E005A3C44 /* CoreServices.framework in Frameworks */,
7BA015FA0E5A1CA600044150 /* Foundation.framework in Frameworks */,
7BED34450E5A1A9600A747DB /* libbase.a in Frameworks */,
@ -732,9 +735,10 @@
7BED31A20E5A15DD00A747DB /* Frameworks */ = {
isa = PBXGroup;
children = (
82113A270E84360200E3848F /* Security.framework */,
7BA357A60E8990260023C8B9 /* AppKit.framework */,
8200F2020E5F741E005A3C44 /* CoreServices.framework */,
7BA0157A0E5A1C9100044150 /* Foundation.framework */,
82113A270E84360200E3848F /* Security.framework */,
);
name = Frameworks;
sourceTree = SDKROOT;