#import "chrome/browser/app_controller_mac.h"
-#include "apps/app_shim/app_shim_mac.h"
#include "apps/app_shim/extension_app_shim_handler_mac.h"
#include "apps/app_window_registry.h"
#include "base/auto_reset.h"
#include "base/files/file_path.h"
#include "base/mac/foundation_util.h"
#include "base/mac/mac_util.h"
+#include "base/mac/sdk_forward_declarations.h"
#include "base/message_loop/message_loop.h"
#include "base/prefs/pref_service.h"
#include "base/strings/string_number_conversions.h"
#include "chrome/browser/extensions/extension_service.h"
#include "chrome/browser/first_run/first_run.h"
#include "chrome/browser/lifetime/application_lifetime.h"
+#include "chrome/browser/mac/mac_startup_profiler.h"
#include "chrome/browser/profiles/profile_info_cache_observer.h"
#include "chrome/browser/profiles/profile_manager.h"
#include "chrome/browser/profiles/profiles_state.h"
#include "chrome/browser/sessions/session_service_factory.h"
#include "chrome/browser/sessions/tab_restore_service.h"
#include "chrome/browser/sessions/tab_restore_service_factory.h"
-#include "chrome/browser/signin/signin_manager.h"
#include "chrome/browser/signin/signin_manager_factory.h"
#include "chrome/browser/signin/signin_promo.h"
#include "chrome/browser/sync/profile_sync_service.h"
#include "chrome/browser/ui/browser_window.h"
#include "chrome/browser/ui/chrome_pages.h"
#import "chrome/browser/ui/cocoa/apps/app_shim_menu_controller_mac.h"
+#include "chrome/browser/ui/cocoa/apps/quit_with_apps_controller_mac.h"
#import "chrome/browser/ui/cocoa/bookmarks/bookmark_menu_bridge.h"
#import "chrome/browser/ui/cocoa/browser_window_cocoa.h"
#import "chrome/browser/ui/cocoa/browser_window_controller.h"
#import "chrome/browser/ui/cocoa/encoding_menu_controller_delegate_mac.h"
#import "chrome/browser/ui/cocoa/history_menu_bridge.h"
#include "chrome/browser/ui/cocoa/last_active_browser_cocoa.h"
-#import "chrome/browser/ui/cocoa/profile_menu_controller.h"
+#import "chrome/browser/ui/cocoa/profiles/profile_menu_controller.h"
#import "chrome/browser/ui/cocoa/tabs/tab_strip_controller.h"
#import "chrome/browser/ui/cocoa/tabs/tab_window_controller.h"
#include "chrome/browser/ui/cocoa/task_manager_mac.h"
#include "chrome/common/extensions/extension_constants.h"
#include "chrome/common/mac/app_mode_common.h"
#include "chrome/common/pref_names.h"
-#include "chrome/common/profile_management_switches.h"
#include "chrome/common/url_constants.h"
+#include "components/signin/core/common/profile_management_switches.h"
+#include "components/signin/core/browser/signin_manager.h"
#include "content/public/browser/browser_thread.h"
#include "content/public/browser/download_manager.h"
#include "content/public/browser/notification_service.h"
#include "extensions/browser/extension_system.h"
#include "grit/chromium_strings.h"
#include "grit/generated_resources.h"
-#include "net/base/net_util.h"
+#include "net/base/filename_util.h"
#include "ui/base/cocoa/focus_window_set.h"
#include "ui/base/l10n/l10n_util.h"
#include "ui/base/l10n/l10n_util_mac.h"
// not possible. If the last active browser is minimized (in particular, if
// there are only minimized windows), it will unminimize it.
Browser* ActivateBrowser(Profile* profile) {
- Browser* browser = chrome::FindLastActiveWithProfile(profile,
+ Browser* browser = chrome::FindLastActiveWithProfile(
+ profile->IsGuestSession() ? profile->GetOffTheRecordProfile() : profile,
chrome::HOST_DESKTOP_TYPE_NATIVE);
if (browser)
browser->window()->Activate();
- (void)initMenuState;
- (void)initProfileMenu;
- (void)updateConfirmToQuitPrefMenuItem:(NSMenuItem*)item;
+- (void)updateDisplayMessageCenterPrefMenuItem:(NSMenuItem*)item;
- (void)registerServicesMenuTypesTo:(NSApplication*)app;
- (void)openUrls:(const std::vector<GURL>&)urls;
- (void)getUrl:(NSAppleEventDescriptor*)event
// the profile is loaded or any preferences have been registered). Defer any
// user-data initialization until -applicationDidFinishLaunching:.
- (void)awakeFromNib {
+ MacStartupProfiler::GetInstance()->Profile(
+ MacStartupProfiler::AWAKE_FROM_NIB);
// We need to register the handlers early to catch events fired on launch.
NSAppleEventManager* em = [NSAppleEventManager sharedAppleEventManager];
[em setEventHandler:self
// (NSApplicationDelegate protocol) This is the Apple-approved place to override
// the default handlers.
- (void)applicationWillFinishLaunching:(NSNotification*)notification {
- // Nothing here right now.
+ MacStartupProfiler::GetInstance()->Profile(
+ MacStartupProfiler::WILL_FINISH_LAUNCHING);
+}
+
+- (void)applicationWillHide:(NSNotification*)notification {
+ apps::ExtensionAppShimHandler::OnChromeWillHide();
}
- (BOOL)tryToTerminateApplication:(NSApplication*)app {
[self applicationShouldTerminate:app] != NSTerminateNow)
return NO;
+ // Check for active apps. If quitting is prevented, only close browsers and
+ // sessions.
+ if (!browser_shutdown::IsTryingToQuit() &&
+ quitWithAppsController_ && !quitWithAppsController_->ShouldQuit()) {
+ content::NotificationService::current()->Notify(
+ chrome::NOTIFICATION_CLOSE_ALL_BROWSERS_REQUEST,
+ content::NotificationService::AllSources(),
+ content::NotificationService::NoDetails());
+ // This will close all browser sessions.
+ chrome::CloseAllBrowsers();
+ return NO;
+ }
+
size_t num_browsers = chrome::GetTotalBrowserCount();
// Initiate a shutdown (via chrome::CloseAllBrowsersAndQuit()) if we aren't
browserWindows.insert(browser->window()->GetNativeWindow());
}
if (!browserWindows.empty()) {
- ui::FocusWindowSet(browserWindows, false);
+ ui::FocusWindowSetOnCurrentSpace(browserWindows);
}
}
#endif
}
+- (void)openStartupUrls {
+ // On Mac, the URLs are passed in via Cocoa, not command line. The Chrome
+ // NSApplication is created in MainMessageLoop, and then the shortcut urls
+ // are passed in via Apple events. At this point, the first browser is
+ // already loaded in PreMainMessageLoop. If we initialize NSApplication
+ // before PreMainMessageLoop to capture shortcut URL events, it may cause
+ // more problems because it relies on things created in PreMainMessageLoop
+ // and may break existing message loop design.
+ if (startupUrls_.empty())
+ return;
+
+ // If there's only 1 tab and the tab is NTP, close this NTP tab and open all
+ // startup urls in new tabs, because the omnibox will stay focused if we
+ // load url in NTP tab.
+ Browser* browser = chrome::GetLastActiveBrowser();
+ int startupIndex = TabStripModel::kNoTab;
+ content::WebContents* startupContent = NULL;
+
+ if (browser && browser->tab_strip_model()->count() == 1) {
+ startupIndex = browser->tab_strip_model()->active_index();
+ startupContent = browser->tab_strip_model()->GetActiveWebContents();
+ }
+
+ if (startupUrls_.size()) {
+ [self openUrls:startupUrls_];
+ startupUrls_.clear();
+ }
+
+ if (startupIndex != TabStripModel::kNoTab &&
+ startupContent->GetVisibleURL() == GURL(chrome::kChromeUINewTabURL)) {
+ browser->tab_strip_model()->CloseWebContentsAt(startupIndex,
+ TabStripModel::CLOSE_NONE);
+ }
+}
+
// This is called after profiles have been loaded and preferences registered.
// It is safe to access the default profile here.
- (void)applicationDidFinishLaunching:(NSNotification*)notify {
+ MacStartupProfiler::GetInstance()->Profile(
+ MacStartupProfiler::DID_FINISH_LAUNCHING);
+ MacStartupProfiler::GetInstance()->RecordMetrics();
+
// Notify BrowserList to keep the application running so it doesn't go away
// when all the browser windows get closed.
chrome::IncrementKeepAliveCount();
// main menu item titles are not yet initialized in awakeFromNib.
[self initAppShimMenuController];
+ // If enabled, keep Chrome alive when apps are open instead of quitting all
+ // apps.
+ quitWithAppsController_ = new QuitWithAppsController();
+
// Build up the encoding menu, the order of the items differs based on the
// current locale (see http://crbug.com/7647 for details).
// We need a valid g_browser_process to get the profile which is why we can't
startupComplete_ = YES;
- // TODO(viettrungluu): This is very temporary, since this should be done "in"
- // |BrowserMain()|, i.e., this list of startup URLs should be appended to the
- // (probably-empty) list of URLs from the command line.
- if (startupUrls_.size()) {
- [self openUrls:startupUrls_];
- [self clearStartupUrls];
- }
+ [self openStartupUrls];
PrefService* localState = g_browser_process->local_state();
if (localState) {
} else if (action == @selector(toggleConfirmToQuit:)) {
[self updateConfirmToQuitPrefMenuItem:static_cast<NSMenuItem*>(item)];
enable = YES;
+ } else if (action == @selector(toggleDisplayMessageCenter:)) {
+ NSMenuItem* menuItem = static_cast<NSMenuItem*>(item);
+ [self updateDisplayMessageCenterPrefMenuItem:menuItem];
+ enable = YES;
} else if (action == @selector(executeApplication:)) {
enable = YES;
}
// check, otherwise it should have been disabled in the UI in
// |-validateUserInterfaceItem:|.
- (void)commandDispatch:(id)sender {
- Profile* lastProfile = [self lastProfile];
+ Profile* lastProfile = [self safeLastProfileForNewWindows];
// Handle the case where we're dispatching a command from a sender that's in a
// browser window. This means that the command came from a background window
// See http://crbug.com/309656.
reopenTime_ = base::TimeTicks::Now();
} else {
- ui::FocusWindowSet(browserWindows, false);
+ ui::FocusWindowSetOnCurrentSpace(browserWindows);
}
// Return NO; we've done (or soon will do) the deminiaturize, so
// AppKit shouldn't do anything.
// Normally, it'd just open a new empty page.
{
static BOOL doneOnce = NO;
- if (!doneOnce) {
- doneOnce = YES;
- if (base::mac::WasLaunchedAsHiddenLoginItem()) {
- SessionService* sessionService =
- SessionServiceFactory::GetForProfileForSessionRestore(
- [self lastProfile]);
- if (sessionService &&
- sessionService->RestoreIfNecessary(std::vector<GURL>()))
- return NO;
- }
- }
- }
-
- // Platform apps don't use browser windows so don't do anything if there are
- // visible windows, otherwise, launch the browser with the same command line
- // which should launch the app again.
- const CommandLine& command_line = *CommandLine::ForCurrentProcess();
- if (command_line.HasSwitch(switches::kAppId)) {
- if (hasVisibleWindows)
- return YES;
-
- {
- base::AutoReset<bool> auto_reset_in_run(&g_is_opening_new_window, true);
- int return_code;
- StartupBrowserCreator browser_creator;
- browser_creator.LaunchBrowser(
- command_line, [self lastProfile], base::FilePath(),
- chrome::startup::IS_NOT_PROCESS_STARTUP,
- chrome::startup::IS_NOT_FIRST_RUN, &return_code);
+ BOOL attemptRestore = apps::AppShimHandler::ShouldRestoreSession() ||
+ (!doneOnce && base::mac::WasLaunchedAsHiddenLoginItem());
+ doneOnce = YES;
+ if (attemptRestore) {
+ SessionService* sessionService =
+ SessionServiceFactory::GetForProfileForSessionRestore(
+ [self lastProfile]);
+ if (sessionService &&
+ sessionService->RestoreIfNecessary(std::vector<GURL>()))
+ return NO;
}
- return NO;
}
// Otherwise open a new window.
[item setState:enabled ? NSOnState : NSOffState];
}
+- (void)updateDisplayMessageCenterPrefMenuItem:(NSMenuItem*)item {
+ const PrefService* prefService = g_browser_process->local_state();
+ bool enabled = prefService->GetBoolean(prefs::kMessageCenterShowIcon);
+ // The item should be checked if "show icon" is false, since the text reads
+ // "Hide notification center icon."
+ [item setState:enabled ? NSOffState : NSOnState];
+}
+
- (void)registerServicesMenuTypesTo:(NSApplication*)app {
// Note that RenderWidgetHostViewCocoa implements NSServicesRequests which
// handles requests from services.
*CommandLine::ForCurrentProcess()));
}
+- (Profile*)safeLastProfileForNewWindows {
+ Profile* profile = [self lastProfile];
+
+ // Guest sessions must always be OffTheRecord. Use that when opening windows.
+ if (profile->IsGuestSession())
+ return profile->GetOffTheRecordProfile();
+
+ return profile;
+}
+
// Various methods to open URLs that we get in a native fashion. We use
// StartupBrowserCreator here because on the other platforms, URLs to open come
// through the ProcessSingleton, and it calls StartupBrowserCreator. It's best
chrome::ShowSettings(browser);
} else {
// No browser window, so create one for the options tab.
- chrome::OpenOptionsWindow([self lastProfile]);
+ chrome::OpenOptionsWindow([self safeLastProfileForNewWindows]);
}
}
chrome::ShowAboutChrome(browser);
} else {
// No browser window, so create one for the about tab.
- chrome::OpenAboutWindow([self lastProfile]);
+ chrome::OpenAboutWindow([self safeLastProfileForNewWindows]);
}
}
prefService->SetBoolean(prefs::kConfirmToQuitEnabled, !enabled);
}
+- (IBAction)toggleDisplayMessageCenter:(id)sender {
+ PrefService* prefService = g_browser_process->local_state();
+ bool enabled = prefService->GetBoolean(prefs::kMessageCenterShowIcon);
+ prefService->SetBoolean(prefs::kMessageCenterShowIcon, !enabled);
+}
+
// Explicitly bring to the foreground when creating new windows from the dock.
- (void)commandFromDock:(id)sender {
[NSApp activateIgnoringOtherApps:YES];
[dockMenu addItem:item];
// |profile| can be NULL during unit tests.
- if (!profile || !profile->IsManaged()) {
+ if (!profile || !profile->IsSupervised()) {
titleStr = l10n_util::GetNSStringWithFixup(IDS_NEW_INCOGNITO_WINDOW_MAC);
item.reset(
[[NSMenuItem alloc] initWithTitle:titleStr
return startupUrls_;
}
-- (void)clearStartupUrls {
- startupUrls_.clear();
-}
-
- (BookmarkMenuBridge*)bookmarkMenuBridge {
return bookmarkMenuBridge_.get();
}
WorkAreaChanged());
}
+- (BOOL)application:(NSApplication*)application
+ willContinueUserActivityWithType:(NSString*)userActivityType {
+ return [userActivityType isEqualToString:NSUserActivityTypeBrowsingWeb];
+}
+
+- (BOOL)application:(NSApplication*)application
+ continueUserActivity:(NSUserActivity*)userActivity
+ restorationHandler:(void (^)(NSArray*))restorationHandler {
+ if (![userActivity.activityType
+ isEqualToString:NSUserActivityTypeBrowsingWeb]) {
+ return NO;
+ }
+
+ NSURL* url = userActivity.webPageURL;
+ if (!url)
+ return NO;
+
+ GURL gurl(base::SysNSStringToUTF8([url absoluteString]));
+ std::vector<GURL> gurlVector;
+ gurlVector.push_back(gurl);
+
+ [self openUrls:gurlVector];
+ return YES;
+}
+
+- (void)application:(NSApplication*)application
+ didFailToContinueUserActivityWithType:(NSString*)userActivityType
+ error:(NSError*)error {
+}
+
@end // @implementation AppController
//---------------------------------------------------------------------------