• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1// Copyright (c) 2013 The Chromium Embedded Framework Authors.
2// Portions copyright (c) 2010 The Chromium Authors. All rights reserved.
3// Use of this source code is governed by a BSD-style license that can be
4// found in the LICENSE file.
5
6#import <Cocoa/Cocoa.h>
7
8#include "include/cef_application_mac.h"
9#include "include/cef_command_line.h"
10#include "include/wrapper/cef_helpers.h"
11#include "include/wrapper/cef_library_loader.h"
12#include "tests/cefsimple/simple_app.h"
13#include "tests/cefsimple/simple_handler.h"
14
15// Receives notifications from the application.
16@interface SimpleAppDelegate : NSObject <NSApplicationDelegate>
17
18- (void)createApplication:(id)object;
19- (void)tryToTerminateApplication:(NSApplication*)app;
20@end
21
22// Provide the CefAppProtocol implementation required by CEF.
23@interface SimpleApplication : NSApplication <CefAppProtocol> {
24 @private
25  BOOL handlingSendEvent_;
26}
27@end
28
29@implementation SimpleApplication
30- (BOOL)isHandlingSendEvent {
31  return handlingSendEvent_;
32}
33
34- (void)setHandlingSendEvent:(BOOL)handlingSendEvent {
35  handlingSendEvent_ = handlingSendEvent;
36}
37
38- (void)sendEvent:(NSEvent*)event {
39  CefScopedSendingEvent sendingEventScoper;
40  [super sendEvent:event];
41}
42
43// |-terminate:| is the entry point for orderly "quit" operations in Cocoa. This
44// includes the application menu's quit menu item and keyboard equivalent, the
45// application's dock icon menu's quit menu item, "quit" (not "force quit") in
46// the Activity Monitor, and quits triggered by user logout and system restart
47// and shutdown.
48//
49// The default |-terminate:| implementation ends the process by calling exit(),
50// and thus never leaves the main run loop. This is unsuitable for Chromium
51// since Chromium depends on leaving the main run loop to perform an orderly
52// shutdown. We support the normal |-terminate:| interface by overriding the
53// default implementation. Our implementation, which is very specific to the
54// needs of Chromium, works by asking the application delegate to terminate
55// using its |-tryToTerminateApplication:| method.
56//
57// |-tryToTerminateApplication:| differs from the standard
58// |-applicationShouldTerminate:| in that no special event loop is run in the
59// case that immediate termination is not possible (e.g., if dialog boxes
60// allowing the user to cancel have to be shown). Instead, this method tries to
61// close all browsers by calling CloseBrowser(false) via
62// ClientHandler::CloseAllBrowsers. Calling CloseBrowser will result in a call
63// to ClientHandler::DoClose and execution of |-performClose:| on the NSWindow.
64// DoClose sets a flag that is used to differentiate between new close events
65// (e.g., user clicked the window close button) and in-progress close events
66// (e.g., user approved the close window dialog). The NSWindowDelegate
67// |-windowShouldClose:| method checks this flag and either calls
68// CloseBrowser(false) in the case of a new close event or destructs the
69// NSWindow in the case of an in-progress close event.
70// ClientHandler::OnBeforeClose will be called after the CEF NSView hosted in
71// the NSWindow is dealloc'ed.
72//
73// After the final browser window has closed ClientHandler::OnBeforeClose will
74// begin actual tear-down of the application by calling CefQuitMessageLoop.
75// This ends the NSApplication event loop and execution then returns to the
76// main() function for cleanup before application termination.
77//
78// The standard |-applicationShouldTerminate:| is not supported, and code paths
79// leading to it must be redirected.
80- (void)terminate:(id)sender {
81  SimpleAppDelegate* delegate =
82      static_cast<SimpleAppDelegate*>([NSApp delegate]);
83  [delegate tryToTerminateApplication:self];
84  // Return, don't exit. The application is responsible for exiting on its own.
85}
86@end
87
88@implementation SimpleAppDelegate
89
90// Create the application on the UI thread.
91- (void)createApplication:(id)object {
92  [[NSBundle mainBundle] loadNibNamed:@"MainMenu"
93                                owner:NSApp
94                      topLevelObjects:nil];
95
96  // Set the delegate for application events.
97  [[NSApplication sharedApplication] setDelegate:self];
98}
99
100- (void)tryToTerminateApplication:(NSApplication*)app {
101  SimpleHandler* handler = SimpleHandler::GetInstance();
102  if (handler && !handler->IsClosing())
103    handler->CloseAllBrowsers(false);
104}
105
106- (NSApplicationTerminateReply)applicationShouldTerminate:
107    (NSApplication*)sender {
108  return NSTerminateNow;
109}
110@end
111
112// Entry point function for the browser process.
113int main(int argc, char* argv[]) {
114  // Load the CEF framework library at runtime instead of linking directly
115  // as required by the macOS sandbox implementation.
116  CefScopedLibraryLoader library_loader;
117  if (!library_loader.LoadInMain())
118    return 1;
119
120  // Provide CEF with command-line arguments.
121  CefMainArgs main_args(argc, argv);
122
123  @autoreleasepool {
124    // Initialize the SimpleApplication instance.
125    [SimpleApplication sharedApplication];
126
127    // If there was an invocation to NSApp prior to this method, then the NSApp
128    // will not be a SimpleApplication, but will instead be an NSApplication.
129    // This is undesirable and we must enforce that this doesn't happen.
130    CHECK([NSApp isKindOfClass:[SimpleApplication class]]);
131
132    // Parse command-line arguments for use in this method.
133    CefRefPtr<CefCommandLine> command_line =
134        CefCommandLine::CreateCommandLine();
135    command_line->InitFromArgv(argc, argv);
136
137    // Specify CEF global settings here.
138    CefSettings settings;
139
140    const bool with_chrome_runtime =
141        command_line->HasSwitch("enable-chrome-runtime");
142
143    if (with_chrome_runtime) {
144      // Enable experimental Chrome runtime. See issue #2969 for details.
145      settings.chrome_runtime = true;
146    }
147
148    // When generating projects with CMake the CEF_USE_SANDBOX value will be
149    // defined automatically. Pass -DUSE_SANDBOX=OFF to the CMake command-line
150    // to disable use of the sandbox.
151#if !defined(CEF_USE_SANDBOX)
152    settings.no_sandbox = true;
153#endif
154
155    // SimpleApp implements application-level callbacks for the browser process.
156    // It will create the first browser instance in OnContextInitialized() after
157    // CEF has initialized.
158    CefRefPtr<SimpleApp> app(new SimpleApp);
159
160    // Initialize CEF for the browser process.
161    CefInitialize(main_args, settings, app.get(), nullptr);
162
163    // Create the application delegate.
164    NSObject* delegate = [[SimpleAppDelegate alloc] init];
165    [delegate performSelectorOnMainThread:@selector(createApplication:)
166                               withObject:nil
167                            waitUntilDone:NO];
168
169    // Run the CEF message loop. This will block until CefQuitMessageLoop() is
170    // called.
171    CefRunMessageLoop();
172
173    // Shut down CEF.
174    CefShutdown();
175
176    // Release the delegate.
177#if !__has_feature(objc_arc)
178    [delegate release];
179#endif  // !__has_feature(objc_arc)
180    delegate = nil;
181  }  // @autoreleasepool
182
183  return 0;
184}
185