| // Copyright (c) 2016 The Chromium Embedded Framework 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 "tests/shared/browser/main_message_loop_external_pump.h" |
| |
| #import <AppKit/AppKit.h> |
| #import <Foundation/Foundation.h> |
| |
| #include "include/cef_app.h" |
| |
| @class EventHandler; |
| |
| namespace client { |
| |
| class MainMessageLoopExternalPumpMac : public MainMessageLoopExternalPump { |
| public: |
| MainMessageLoopExternalPumpMac(); |
| ~MainMessageLoopExternalPumpMac(); |
| |
| // MainMessageLoopStd methods: |
| void Quit() OVERRIDE; |
| int Run() OVERRIDE; |
| |
| // MainMessageLoopExternalPump methods: |
| void OnScheduleMessagePumpWork(int64 delay_ms) OVERRIDE; |
| |
| // Internal methods used for processing the event callbacks. They are public |
| // for simplicity but should not be used directly. |
| void HandleScheduleWork(int64 delay_ms); |
| void HandleTimerTimeout(); |
| |
| protected: |
| // MainMessageLoopExternalPump methods: |
| void SetTimer(int64 delay_ms) OVERRIDE; |
| void KillTimer() OVERRIDE; |
| bool IsTimerPending() OVERRIDE { return timer_ != nil; } |
| |
| private: |
| // Owner thread that will run events. |
| NSThread* owner_thread_; |
| |
| // Pending work timer. |
| NSTimer* timer_; |
| |
| // Used to handle event callbacks on the owner thread. |
| EventHandler* event_handler_; |
| }; |
| |
| } // namespace client |
| |
| // Object that handles event callbacks on the owner thread. |
| @interface EventHandler : NSObject { |
| @private |
| client::MainMessageLoopExternalPumpMac* pump_; |
| } |
| |
| - (id)initWithPump:(client::MainMessageLoopExternalPumpMac*)pump; |
| - (void)scheduleWork:(NSNumber*)delay_ms; |
| - (void)timerTimeout:(id)obj; |
| @end |
| |
| @implementation EventHandler |
| |
| - (id)initWithPump:(client::MainMessageLoopExternalPumpMac*)pump { |
| if (self = [super init]) { |
| pump_ = pump; |
| } |
| return self; |
| } |
| |
| - (void)scheduleWork:(NSNumber*)delay_ms { |
| pump_->HandleScheduleWork([delay_ms integerValue]); |
| } |
| |
| - (void)timerTimeout:(id)obj { |
| pump_->HandleTimerTimeout(); |
| } |
| |
| @end |
| |
| namespace client { |
| |
| MainMessageLoopExternalPumpMac::MainMessageLoopExternalPumpMac() |
| : owner_thread_([NSThread currentThread]), timer_(nil) { |
| #if !__has_feature(objc_arc) |
| [owner_thread_ retain]; |
| #endif // !__has_feature(objc_arc) |
| event_handler_ = [[EventHandler alloc] initWithPump:this]; |
| } |
| |
| MainMessageLoopExternalPumpMac::~MainMessageLoopExternalPumpMac() { |
| KillTimer(); |
| #if !__has_feature(objc_arc) |
| [owner_thread_ release]; |
| [event_handler_ release]; |
| #endif // !__has_feature(objc_arc) |
| owner_thread_ = nil; |
| event_handler_ = nil; |
| } |
| |
| void MainMessageLoopExternalPumpMac::Quit() { |
| [NSApp stop:nil]; |
| } |
| |
| int MainMessageLoopExternalPumpMac::Run() { |
| // Run the message loop. |
| [NSApp run]; |
| |
| KillTimer(); |
| |
| // We need to run the message pump until it is idle. However we don't have |
| // that information here so we run the message loop "for a while". |
| for (int i = 0; i < 10; ++i) { |
| // Let default runloop observers run. |
| CFRunLoopRunInMode(kCFRunLoopDefaultMode, 0.001, 1); |
| |
| // Do some work. |
| CefDoMessageLoopWork(); |
| |
| // Sleep to allow the CEF proc to do work. |
| [NSThread sleepForTimeInterval:0.05]; |
| } |
| |
| return 0; |
| } |
| |
| void MainMessageLoopExternalPumpMac::OnScheduleMessagePumpWork(int64 delay_ms) { |
| // This method may be called on any thread. |
| NSNumber* number = [NSNumber numberWithInt:static_cast<int>(delay_ms)]; |
| [event_handler_ performSelector:@selector(scheduleWork:) |
| onThread:owner_thread_ |
| withObject:number |
| waitUntilDone:NO]; |
| } |
| |
| void MainMessageLoopExternalPumpMac::HandleScheduleWork(int64 delay_ms) { |
| OnScheduleWork(delay_ms); |
| } |
| |
| void MainMessageLoopExternalPumpMac::HandleTimerTimeout() { |
| OnTimerTimeout(); |
| } |
| |
| void MainMessageLoopExternalPumpMac::SetTimer(int64 delay_ms) { |
| DCHECK_GT(delay_ms, 0); |
| DCHECK(!timer_); |
| |
| const double delay_s = static_cast<double>(delay_ms) / 1000.0; |
| timer_ = [NSTimer timerWithTimeInterval:delay_s |
| target:event_handler_ |
| selector:@selector(timerTimeout:) |
| userInfo:nil |
| repeats:NO]; |
| #if !__has_feature(objc_arc) |
| [timer_ retain]; |
| #endif // !__has_feature(objc_arc) |
| |
| // Add the timer to default and tracking runloop modes. |
| NSRunLoop* owner_runloop = [NSRunLoop currentRunLoop]; |
| [owner_runloop addTimer:timer_ forMode:NSRunLoopCommonModes]; |
| [owner_runloop addTimer:timer_ forMode:NSEventTrackingRunLoopMode]; |
| } |
| |
| void MainMessageLoopExternalPumpMac::KillTimer() { |
| if (timer_ != nil) { |
| [timer_ invalidate]; |
| #if !__has_feature(objc_arc) |
| [timer_ release]; |
| #endif // !__has_feature(objc_arc) |
| timer_ = nil; |
| } |
| } |
| |
| // static |
| scoped_ptr<MainMessageLoopExternalPump> MainMessageLoopExternalPump::Create() { |
| return scoped_ptr<MainMessageLoopExternalPump>( |
| new MainMessageLoopExternalPumpMac()); |
| } |
| |
| } // namespace client |