// Copyright (c) 2013 The Chromium Embedded Framework Authors. // Portions copyright (c) 2010 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. #import #include "cefsimple/simple_app.h" #include "cefsimple/simple_handler.h" #include "include/cef_application_mac.h" #include "include/wrapper/cef_helpers.h" // Receives notifications from the application. @interface SimpleAppDelegate : NSObject - (void)createApplication:(id)object; - (void)tryToTerminateApplication:(NSApplication*)app; @end // Provide the CefAppProtocol implementation required by CEF. @interface SimpleApplication : NSApplication { @private BOOL handlingSendEvent_; } @end @implementation SimpleApplication - (BOOL)isHandlingSendEvent { return handlingSendEvent_; } - (void)setHandlingSendEvent:(BOOL)handlingSendEvent { handlingSendEvent_ = handlingSendEvent; } - (void)sendEvent:(NSEvent*)event { CefScopedSendingEvent sendingEventScoper; [super sendEvent:event]; } // |-terminate:| is the entry point for orderly "quit" operations in Cocoa. This // includes the application menu's quit menu item and keyboard equivalent, the // application's dock icon menu's quit menu item, "quit" (not "force quit") in // the Activity Monitor, and quits triggered by user logout and system restart // and shutdown. // // The default |-terminate:| implementation ends the process by calling exit(), // and thus never leaves the main run loop. This is unsuitable for Chromium // since Chromium depends on leaving the main run loop to perform an orderly // shutdown. We support the normal |-terminate:| interface by overriding the // default implementation. Our implementation, which is very specific to the // needs of Chromium, works by asking the application delegate to terminate // using its |-tryToTerminateApplication:| method. // // |-tryToTerminateApplication:| differs from the standard // |-applicationShouldTerminate:| in that no special event loop is run in the // case that immediate termination is not possible (e.g., if dialog boxes // allowing the user to cancel have to be shown). Instead, this method tries to // close all browsers by calling CloseBrowser(false) via // ClientHandler::CloseAllBrowsers. Calling CloseBrowser will result in a call // to ClientHandler::DoClose and execution of |-performClose:| on the NSWindow. // DoClose sets a flag that is used to differentiate between new close events // (e.g., user clicked the window close button) and in-progress close events // (e.g., user approved the close window dialog). The NSWindowDelegate // |-windowShouldClose:| method checks this flag and either calls // CloseBrowser(false) in the case of a new close event or destructs the // NSWindow in the case of an in-progress close event. // ClientHandler::OnBeforeClose will be called after the CEF NSView hosted in // the NSWindow is dealloc'ed. // // After the final browser window has closed ClientHandler::OnBeforeClose will // begin actual tear-down of the application by calling CefQuitMessageLoop. // This ends the NSApplication event loop and execution then returns to the // main() function for cleanup before application termination. // // The standard |-applicationShouldTerminate:| is not supported, and code paths // leading to it must be redirected. - (void)terminate:(id)sender { SimpleAppDelegate* delegate = static_cast([NSApp delegate]); [delegate tryToTerminateApplication:self]; // Return, don't exit. The application is responsible for exiting on its own. } @end @implementation SimpleAppDelegate // Create the application on the UI thread. - (void)createApplication:(id)object { [NSApplication sharedApplication]; [NSBundle loadNibNamed:@"MainMenu" owner:NSApp]; // Set the delegate for application events. [NSApp setDelegate:self]; } - (void)tryToTerminateApplication:(NSApplication*)app { SimpleHandler* handler = SimpleHandler::GetInstance(); if (handler && !handler->IsClosing()) handler->CloseAllBrowsers(false); } - (NSApplicationTerminateReply)applicationShouldTerminate: (NSApplication *)sender { return NSTerminateNow; } @end // Entry point function for the browser process. int main(int argc, char* argv[]) { // Provide CEF with command-line arguments. CefMainArgs main_args(argc, argv); // SimpleApp implements application-level callbacks. It will create the first // browser instance in OnContextInitialized() after CEF has initialized. CefRefPtr app(new SimpleApp); // Initialize the AutoRelease pool. NSAutoreleasePool* autopool = [[NSAutoreleasePool alloc] init]; // Initialize the SimpleApplication instance. [SimpleApplication sharedApplication]; // Specify CEF global settings here. CefSettings settings; // Initialize CEF for the browser process. CefInitialize(main_args, settings, app.get(), NULL); // Create the application delegate. NSObject* delegate = [[SimpleAppDelegate alloc] init]; [delegate performSelectorOnMainThread:@selector(createApplication:) withObject:nil waitUntilDone:NO]; // Run the CEF message loop. This will block until CefQuitMessageLoop() is // called. CefRunMessageLoop(); // Shut down CEF. CefShutdown(); // Release the delegate. [delegate release]; // Release the AutoRelease pool. [autopool release]; return 0; }