blob: 6317a79765b8fbb88424188bc8a4129cec8ef572 [file] [log] [blame]
[email protected]1bcdb532009-01-16 17:47:571// Copyright (c) 2009 The Chromium Authors. All rights reserved.
2// Use of this source code is governed by a BSD-style license that can be
3// found in the LICENSE file.
4
[email protected]2c47bc12009-04-10 20:14:005#import "chrome/browser/app_controller_mac.h"
[email protected]1bcdb532009-01-16 17:47:576
[email protected]288bfcd32009-09-14 18:14:467#include "app/l10n_util_mac.h"
[email protected]57750f822009-04-21 21:43:098#include "base/command_line.h"
[email protected]09729a552009-08-03 23:21:419#include "base/mac_util.h"
[email protected]2c47bc12009-04-10 20:14:0010#include "base/message_loop.h"
[email protected]57750f822009-04-21 21:43:0911#include "base/sys_string_conversions.h"
[email protected]2c47bc12009-04-10 20:14:0012#include "chrome/app/chrome_dll_resource.h"
13#include "chrome/browser/browser.h"
[email protected]57750f822009-04-21 21:43:0914#include "chrome/browser/browser_init.h"
[email protected]2c47bc12009-04-10 20:14:0015#include "chrome/browser/browser_list.h"
[email protected]5c238752009-06-13 10:29:0716#include "chrome/browser/browser_process.h"
[email protected]41741a962009-02-18 21:51:3917#include "chrome/browser/browser_shutdown.h"
[email protected]ce560f82009-06-03 09:39:4418#include "chrome/browser/browser_window.h"
[email protected]bde3dda2009-05-20 22:13:0719#import "chrome/browser/cocoa/about_window_controller.h"
[email protected]3f34599d2009-03-25 22:11:4320#import "chrome/browser/cocoa/bookmark_menu_bridge.h"
[email protected]a9e8afc2009-08-11 22:03:1721#import "chrome/browser/cocoa/browser_window_cocoa.h"
22#import "chrome/browser/cocoa/browser_window_controller.h"
[email protected]3896b182009-11-03 16:15:3223#import "chrome/browser/cocoa/bug_report_window_controller.h"
[email protected]93e181762009-05-29 14:30:3824#import "chrome/browser/cocoa/clear_browsing_data_controller.h"
[email protected]2bcec612009-05-14 17:50:5325#import "chrome/browser/cocoa/encoding_menu_controller_delegate_mac.h"
[email protected]4aee5652009-11-19 18:59:2126#import "chrome/browser/cocoa/history_menu_bridge.h"
27#import "chrome/browser/cocoa/import_settings_dialog.h"
[email protected]42404382009-04-30 17:59:2428#import "chrome/browser/cocoa/preferences_window_controller.h"
[email protected]449dd2f2009-05-27 13:04:0029#import "chrome/browser/cocoa/tab_strip_controller.h"
30#import "chrome/browser/cocoa/tab_window_controller.h"
[email protected]ceaaf1812010-01-20 22:13:0931#include "chrome/browser/cocoa/task_manager_mac.h"
[email protected]2c47bc12009-04-10 20:14:0032#include "chrome/browser/command_updater.h"
[email protected]09729a552009-08-03 23:21:4133#include "chrome/browser/download/download_manager.h"
[email protected]4aee5652009-11-19 18:59:2134#include "chrome/browser/metrics/user_metrics.h"
[email protected]60ad3e22009-09-18 21:07:1935#include "chrome/browser/options_window.h"
[email protected]fbc947b2009-06-19 13:28:2436#include "chrome/browser/sessions/tab_restore_service.h"
[email protected]f9bc9b92009-11-24 00:55:3537#include "chrome/browser/sync/profile_sync_service.h"
[email protected]40f047972009-11-25 03:54:4038#include "chrome/browser/sync/sync_ui_util.h"
39#include "chrome/browser/sync/sync_ui_util_mac.h"
[email protected]60ad3e22009-09-18 21:07:1940#include "chrome/browser/tab_contents/tab_contents.h"
[email protected]f4acfae82009-09-11 00:33:3841#include "chrome/common/chrome_switches.h"
[email protected]a96ec6a2009-11-04 17:27:0842#include "chrome/common/notification_service.h"
[email protected]cd63ef62009-05-06 19:41:3743#include "chrome/common/pref_names.h"
44#include "chrome/common/pref_service.h"
[email protected]2c47bc12009-04-10 20:14:0045#include "chrome/browser/profile_manager.h"
46#include "chrome/common/temp_scaffolding_stubs.h"
[email protected]9dcb59662009-09-23 01:15:5047#include "grit/chromium_strings.h"
[email protected]09729a552009-08-03 23:21:4148#include "grit/generated_resources.h"
[email protected]caadfca2010-01-22 21:51:2149#include "net/base/net_util.h"
[email protected]88d74942009-01-21 22:04:4450
[email protected]f2c20fa2009-12-01 17:42:0251// 10.6 adds a public API for the Spotlight-backed search menu item in the Help
52// menu. Provide the declaration so it can be called below when building with
53// the 10.5 SDK.
54#if !defined(MAC_OS_X_VERSION_10_6) || \
55 MAC_OS_X_VERSION_MAX_ALLOWED < MAC_OS_X_VERSION_10_6
56@interface NSApplication (SnowLeopardSDKDeclarations)
[email protected]caadfca2010-01-22 21:51:2157- (void)setHelpMenu:(NSMenu*)helpMenu;
[email protected]f2c20fa2009-12-01 17:42:0258@end
59#endif
60
[email protected]88d74942009-01-21 22:04:4461@interface AppController(PRIVATE)
62- (void)initMenuState;
[email protected]136140c2009-05-19 13:58:2563- (void)openURLs:(const std::vector<GURL>&)urls;
[email protected]57750f822009-04-21 21:43:0964- (void)getUrl:(NSAppleEventDescriptor*)event
65 withReply:(NSAppleEventDescriptor*)reply;
[email protected]449dd2f2009-05-27 13:04:0066- (void)windowLayeringDidChange:(NSNotification*)inNotification;
[email protected]73f5b362009-08-10 23:58:2167- (BOOL)userWillWaitForInProgressDownloads:(int)downloadCount;
[email protected]09729a552009-08-03 23:21:4168- (BOOL)shouldQuitWithInProgressDownloads;
[email protected]d989f07c2009-11-14 00:35:4669- (void)showPreferencesWindow:(id)sender
70 page:(OptionsPage)page
71 profile:(Profile*)profile;
[email protected]88d74942009-01-21 22:04:4472@end
[email protected]1bcdb532009-01-16 17:47:5773
[email protected]216e9042009-10-29 17:05:2374// True while AppController is calling Browser::OpenEmptyWindow(). We need a
75// global flag here, analogue to BrowserInit::InProcessStartup() because
76// otherwise the SessionService will try to restore sessions when we make a new
77// window while there are no other active windows.
78static bool g_is_opening_new_window = false;
79
[email protected]1bcdb532009-01-16 17:47:5780@implementation AppController
81
[email protected]caadfca2010-01-22 21:51:2182@synthesize startupComplete = startupComplete_;
83
[email protected]cd63ef62009-05-06 19:41:3784// This method is called very early in application startup (ie, before
85// the profile is loaded or any preferences have been registered). Defer any
86// user-data initialization until -applicationDidFinishLaunching:.
[email protected]88d74942009-01-21 22:04:4487- (void)awakeFromNib {
[email protected]136140c2009-05-19 13:58:2588 // We need to register the handlers early to catch events fired on launch.
[email protected]57750f822009-04-21 21:43:0989 NSAppleEventManager* em = [NSAppleEventManager sharedAppleEventManager];
90 [em setEventHandler:self
91 andSelector:@selector(getUrl:withReply:)
92 forEventClass:kInternetEventClass
93 andEventID:kAEGetURL];
94 [em setEventHandler:self
95 andSelector:@selector(getUrl:withReply:)
96 forEventClass:'WWW!' // A particularly ancient AppleEvent that dates
97 andEventID:'OURL']; // back to the Spyglass days.
[email protected]cd63ef62009-05-06 19:41:3798
[email protected]449dd2f2009-05-27 13:04:0099 // Register for various window layering changes. We use these to update
100 // various UI elements (command-key equivalents, etc) when the frontmost
101 // window changes.
102 NSNotificationCenter* notificationCenter =
103 [NSNotificationCenter defaultCenter];
[email protected]ce560f82009-06-03 09:39:44104 [notificationCenter
[email protected]449dd2f2009-05-27 13:04:00105 addObserver:self
106 selector:@selector(windowLayeringDidChange:)
107 name:NSWindowDidBecomeKeyNotification
108 object:nil];
109 [notificationCenter
110 addObserver:self
111 selector:@selector(windowLayeringDidChange:)
112 name:NSWindowDidResignKeyNotification
113 object:nil];
114 [notificationCenter
115 addObserver:self
116 selector:@selector(windowLayeringDidChange:)
117 name:NSWindowDidBecomeMainNotification
118 object:nil];
119 [notificationCenter
120 addObserver:self
121 selector:@selector(windowLayeringDidChange:)
122 name:NSWindowDidResignMainNotification
123 object:nil];
124
125 // Register for a notification that the number of tabs changes in windows
126 // so we can adjust the close tab/window command keys.
127 [notificationCenter
128 addObserver:self
129 selector:@selector(tabsChanged:)
130 name:kTabStripNumberOfTabsChanged
131 object:nil];
132
[email protected]136140c2009-05-19 13:58:25133 // Set up the command updater for when there are no windows open
134 [self initMenuState];
[email protected]f4acfae82009-09-11 00:33:38135
136 // Activate (bring to foreground) if asked to do so. On
137 // Windows this logic isn't necessary since
138 // BrowserWindow::Activate() calls ::SetForegroundWindow() which is
139 // adequate. On Mac, BrowserWindow::Activate() calls -[NSWindow
140 // makeKeyAndOrderFront:] which does not activate the application
141 // itself.
142 const CommandLine& parsed_command_line = *CommandLine::ForCurrentProcess();
143 if (parsed_command_line.HasSwitch(switches::kActivateOnLaunch)) {
144 [NSApp activateIgnoringOtherApps:YES];
145 }
[email protected]136140c2009-05-19 13:58:25146}
147
[email protected]a9e8afc2009-08-11 22:03:17148- (NSApplicationTerminateReply)applicationShouldTerminate:
149 (NSApplication *)sender {
[email protected]a9e8afc2009-08-11 22:03:17150 // Check for in-progress downloads, and prompt the user if they really want to
151 // quit (and thus cancel the downloads).
152 if (![self shouldQuitWithInProgressDownloads])
153 return NSTerminateCancel;
154
155 return NSTerminateNow;
156}
157
[email protected]449dd2f2009-05-27 13:04:00158// Called when the app is shutting down. Clean-up as appropriate.
159- (void)applicationWillTerminate:(NSNotification *)aNotification {
[email protected]3b6aa8b62009-09-15 21:36:11160 NSAppleEventManager* em = [NSAppleEventManager sharedAppleEventManager];
161 [em removeEventHandlerForEventClass:kInternetEventClass
162 andEventID:kAEGetURL];
163 [em removeEventHandlerForEventClass:'WWW!'
164 andEventID:'OURL'];
[email protected]3b6aa8b62009-09-15 21:36:11165
166 // Close all the windows.
167 BrowserList::CloseAllBrowsers(true);
168
169 // On Windows, this is done in Browser::OnWindowClosing, but that's not
170 // appropriate on Mac since we don't shut down when we reach zero windows.
171 browser_shutdown::OnShutdownStarting(browser_shutdown::BROWSER_EXIT);
172
173 // Release the reference to the browser process. Once all the browsers get
174 // dealloc'd, it will stop the RunLoop and fall back into main().
175 g_browser_process->ReleaseModule();
[email protected]fbc947b2009-06-19 13:28:24176
[email protected]d4e18652009-11-19 21:52:16177 // Close these off if they have open windows.
178 [prefsController_ close];
179 [aboutController_ close];
180
[email protected]449dd2f2009-05-27 13:04:00181 [[NSNotificationCenter defaultCenter] removeObserver:self];
182}
183
[email protected]3b6aa8b62009-09-15 21:36:11184- (void)didEndMainMessageLoop {
185 DCHECK(!BrowserList::HasBrowserWithProfile([self defaultProfile]));
186 if (!BrowserList::HasBrowserWithProfile([self defaultProfile])) {
187 // As we're shutting down, we need to nuke the TabRestoreService, which
188 // will start the shutdown of the NavigationControllers and allow for
189 // proper shutdown. If we don't do this, Chrome won't shut down cleanly,
190 // and may end up crashing when some thread tries to use the IO thread (or
191 // another thread) that is no longer valid.
192 [self defaultProfile]->ResetTabRestoreService();
193 }
194}
195
[email protected]449dd2f2009-05-27 13:04:00196// Helper routine to get the window controller if the key window is a tabbed
197// window, or nil if not. Examples of non-tabbed windows are "about" or
198// "preferences".
199- (TabWindowController*)keyWindowTabController {
200 NSWindowController* keyWindowController =
[email protected]5dbabd02009-09-17 20:44:13201 [[NSApp keyWindow] windowController];
[email protected]449dd2f2009-05-27 13:04:00202 if ([keyWindowController isKindOfClass:[TabWindowController class]])
203 return (TabWindowController*)keyWindowController;
204
205 return nil;
206}
207
[email protected]74c0c642009-09-22 21:25:50208// Helper routine to get the window controller if the main window is a tabbed
209// window, or nil if not. Examples of non-tabbed windows are "about" or
210// "preferences".
211- (TabWindowController*)mainWindowTabController {
212 NSWindowController* mainWindowController =
213 [[NSApp mainWindow] windowController];
214 if ([mainWindowController isKindOfClass:[TabWindowController class]])
215 return (TabWindowController*)mainWindowController;
216
217 return nil;
218}
219
[email protected]449dd2f2009-05-27 13:04:00220// If the window has tabs, make "close window" be cmd-shift-w, otherwise leave
221// it as the normal cmd-w. Capitalization of the key equivalent affects whether
222// the shift modifer is used.
223- (void)adjustCloseWindowMenuItemKeyEquivalent:(BOOL)inHaveTabs {
224 [closeWindowMenuItem_ setKeyEquivalent:(inHaveTabs ? @"W" : @"w")];
[email protected]74c0c642009-09-22 21:25:50225 [closeWindowMenuItem_ setKeyEquivalentModifierMask:NSCommandKeyMask];
[email protected]449dd2f2009-05-27 13:04:00226}
227
228// If the window has tabs, make "close tab" take over cmd-w, otherwise it
229// shouldn't have any key-equivalent because it should be disabled.
230- (void)adjustCloseTabMenuItemKeyEquivalent:(BOOL)hasTabs {
231 if (hasTabs) {
232 [closeTabMenuItem_ setKeyEquivalent:@"w"];
233 [closeTabMenuItem_ setKeyEquivalentModifierMask:NSCommandKeyMask];
234 } else {
235 [closeTabMenuItem_ setKeyEquivalent:@""];
236 [closeTabMenuItem_ setKeyEquivalentModifierMask:0];
237 }
238}
239
[email protected]74c0c642009-09-22 21:25:50240// Explicitly remove any command-key equivalents from the close tab/window
241// menus so that nothing can go haywire if we get a user action during pending
242// updates.
243- (void)clearCloseMenuItemKeyEquivalents {
244 [closeTabMenuItem_ setKeyEquivalent:@""];
245 [closeTabMenuItem_ setKeyEquivalentModifierMask:0];
246 [closeWindowMenuItem_ setKeyEquivalent:@""];
247 [closeWindowMenuItem_ setKeyEquivalentModifierMask:0];
248}
249
[email protected]449dd2f2009-05-27 13:04:00250// See if we have a window with tabs open, and adjust the key equivalents for
251// Close Tab/Close Window accordingly
252- (void)fixCloseMenuItemKeyEquivalents {
253 TabWindowController* tabController = [self keyWindowTabController];
[email protected]74c0c642009-09-22 21:25:50254 if (!tabController && ![NSApp keyWindow]) {
255 // There might be a small amount of time where there is no key window,
256 // so just use our main browser window if there is one.
257 tabController = [self mainWindowTabController];
258 }
[email protected]449dd2f2009-05-27 13:04:00259 BOOL windowWithMultipleTabs =
260 (tabController && [tabController numberOfTabs] > 1);
261 [self adjustCloseWindowMenuItemKeyEquivalent:windowWithMultipleTabs];
262 [self adjustCloseTabMenuItemKeyEquivalent:windowWithMultipleTabs];
263 fileMenuUpdatePending_ = NO;
264}
265
266// Fix up the "close tab/close window" command-key equivalents. We do this
267// after a delay to ensure that window layer state has been set by the time
[email protected]f2a5c342010-01-21 17:00:29268// we do the enabling. This should only be called on the main thread, code that
269// calls this (even as a side-effect) from other threads needs to be fixed.
[email protected]449dd2f2009-05-27 13:04:00270- (void)delayedFixCloseMenuItemKeyEquivalents {
[email protected]f2a5c342010-01-21 17:00:29271 DCHECK([NSThread isMainThread]);
[email protected]449dd2f2009-05-27 13:04:00272 if (!fileMenuUpdatePending_) {
[email protected]74c0c642009-09-22 21:25:50273 // The OS prefers keypresses to timers, so it's possible that a cmd-w
274 // can sneak in before this timer fires. In order to prevent that from
275 // having any bad consequences, just clear the keys combos altogether. They
276 // will be reset when the timer eventually fires.
277 [self clearCloseMenuItemKeyEquivalents];
[email protected]f2a5c342010-01-21 17:00:29278 [self performSelectorOnMainThread:@selector(fixCloseMenuItemKeyEquivalents)
279 withObject:nil
280 waitUntilDone:NO];
[email protected]449dd2f2009-05-27 13:04:00281 fileMenuUpdatePending_ = YES;
282 }
283}
284
285// Called when we get a notification about the window layering changing to
286// update the UI based on the new main window.
287- (void)windowLayeringDidChange:(NSNotification*)notify {
288 [self delayedFixCloseMenuItemKeyEquivalents];
[email protected]ce560f82009-06-03 09:39:44289
[email protected]449dd2f2009-05-27 13:04:00290 // TODO(pinkerton): If we have other things here, such as inspector panels
291 // that follow the contents of the selected webpage, we would update those
292 // here.
293}
294
295// Called when the number of tabs changes in one of the browser windows. The
296// object is the tab strip controller, but we don't currently care.
297- (void)tabsChanged:(NSNotification*)notify {
[email protected]e72746b12009-10-19 14:11:51298 // We don't need to do this on a delay, as in the method above, because the
299 // window layering isn't changing. As a result, there's no chance that a
300 // different window will sneak in as the key window and cause the problems
301 // we hacked around above by clearing the key equivalents.
302 [self fixCloseMenuItemKeyEquivalents];
[email protected]449dd2f2009-05-27 13:04:00303}
304
[email protected]414fde592009-05-21 16:14:43305// If the auto-update interval is not set, make it 5 hours.
306// This code is specific to Mac Chrome Dev Channel.
307// Placed here for 2 reasons:
308// 1) Same spot as other Pref stuff
309// 2) Try and be friendly by keeping this after app launch
310// TODO(jrg): remove once we go Beta.
311- (void)setUpdateCheckInterval {
312#if defined(GOOGLE_CHROME_BUILD)
313 CFStringRef app = (CFStringRef)@"com.google.Keystone.Agent";
314 CFStringRef checkInterval = (CFStringRef)@"checkInterval";
315 CFPropertyListRef plist = CFPreferencesCopyAppValue(checkInterval, app);
316 if (!plist) {
317 const float fiveHoursInSeconds = 5.0 * 60.0 * 60.0;
318 NSNumber *value = [NSNumber numberWithFloat:fiveHoursInSeconds];
319 CFPreferencesSetAppValue(checkInterval, value, app);
320 CFPreferencesAppSynchronize(app);
321 }
322#endif
323}
324
[email protected]136140c2009-05-19 13:58:25325// This is called after profiles have been loaded and preferences registered.
326// It is safe to access the default profile here.
327- (void)applicationDidFinishLaunching:(NSNotification*)notify {
328 // Hold an extra ref to the BrowserProcess singleton so it doesn't go away
329 // when all the browser windows get closed. We'll release it on quit which
330 // will be the signal to exit.
331 DCHECK(g_browser_process);
332 g_browser_process->AddRefModule();
333
[email protected]e5575022009-08-22 00:31:22334 bookmarkMenuBridge_.reset(new BookmarkMenuBridge([self defaultProfile]));
[email protected]1c84c82c2009-07-27 15:37:25335 historyMenuBridge_.reset(new HistoryMenuBridge([self defaultProfile]));
[email protected]cd63ef62009-05-06 19:41:37336
[email protected]414fde592009-05-21 16:14:43337 [self setUpdateCheckInterval];
[email protected]2bcec612009-05-14 17:50:53338
339 // Build up the encoding menu, the order of the items differs based on the
340 // current locale (see http://crbug.com/7647 for details).
341 // We need a valid g_browser_process to get the profile which is why we can't
342 // call this from awakeFromNib.
[email protected]fc349322009-09-23 22:28:23343 NSMenu* view_menu = [[[NSApp mainMenu] itemWithTag:IDC_VIEW_MENU] submenu];
344 NSMenuItem* encoding_menu_item = [view_menu itemWithTag:IDC_ENCODING_MENU];
345 NSMenu *encoding_menu = [encoding_menu_item submenu];
346 EncodingMenuControllerDelegate::BuildEncodingMenu([self defaultProfile],
347 encoding_menu);
[email protected]2bcec612009-05-14 17:50:53348
[email protected]f2c20fa2009-12-01 17:42:02349 // Since Chrome is localized to more languages than the OS, tell Cocoa which
350 // menu is the Help so it can add the search item to it.
[email protected]caadfca2010-01-22 21:51:21351 if (helpMenu_ && [NSApp respondsToSelector:@selector(setHelpMenu:)])
[email protected]f2c20fa2009-12-01 17:42:02352 [NSApp setHelpMenu:helpMenu_];
[email protected]f2c20fa2009-12-01 17:42:02353
[email protected]caadfca2010-01-22 21:51:21354 startupComplete_ = YES;
355
356 // TODO(viettrungluu): This is very temporary, since this should be done "in"
357 // |BrowserMain()|, i.e., this list of startup URLs should be appended to the
358 // (probably-empty) list of URLs from the command line.
359 if (startupURLs_.size()) {
360 [self openURLs:startupURLs_];
361 [self clearStartupURLs];
362 }
[email protected]7c321082009-02-09 15:35:47363}
364
[email protected]a96ec6a2009-11-04 17:27:08365// This is called after profiles have been loaded and preferences registered.
366// It is safe to access the default profile here.
367- (void)applicationDidBecomeActive:(NSNotification*)notify {
368 NotificationService::current()->Notify(NotificationType::APP_ACTIVATED,
369 NotificationService::AllSources(),
370 NotificationService::NoDetails());
371}
372
[email protected]73f5b362009-08-10 23:58:21373// Helper function for populating and displaying the in progress downloads at
374// exit alert panel.
375- (BOOL)userWillWaitForInProgressDownloads:(int)downloadCount {
[email protected]e8b5f7882009-09-14 20:59:13376 NSString* warningText = nil;
377 NSString* explanationText = nil;
[email protected]73f5b362009-08-10 23:58:21378 NSString* waitTitle = nil;
379 NSString* exitTitle = nil;
380
[email protected]9dcb59662009-09-23 01:15:50381 std::wstring product_name = l10n_util::GetString(IDS_PRODUCT_NAME);
382
[email protected]73f5b362009-08-10 23:58:21383 // Set the dialog text based on whether or not there are multiple downloads.
384 if (downloadCount == 1) {
[email protected]e8b5f7882009-09-14 20:59:13385 // Dialog text: warning and explanation.
386 warningText =
[email protected]9dcb59662009-09-23 01:15:50387 base::SysWideToNSString(l10n_util::GetStringF(
388 IDS_SINGLE_DOWNLOAD_REMOVE_CONFIRM_WARNING, product_name));
[email protected]e8b5f7882009-09-14 20:59:13389 explanationText =
[email protected]9dcb59662009-09-23 01:15:50390 base::SysWideToNSString(l10n_util::GetStringF(
391 IDS_SINGLE_DOWNLOAD_REMOVE_CONFIRM_EXPLANATION, product_name));
[email protected]73f5b362009-08-10 23:58:21392
393 // Cancel download and exit button text.
394 exitTitle =
[email protected]e8b5f7882009-09-14 20:59:13395 base::SysWideToNSString(l10n_util::GetString(
396 IDS_SINGLE_DOWNLOAD_REMOVE_CONFIRM_OK_BUTTON_LABEL));
[email protected]73f5b362009-08-10 23:58:21397
398 // Wait for download button text.
399 waitTitle =
[email protected]e8b5f7882009-09-14 20:59:13400 base::SysWideToNSString(l10n_util::GetString(
401 IDS_SINGLE_DOWNLOAD_REMOVE_CONFIRM_CANCEL_BUTTON_LABEL));
[email protected]73f5b362009-08-10 23:58:21402 } else {
[email protected]e8b5f7882009-09-14 20:59:13403 // Dialog text: warning and explanation.
404 warningText =
405 base::SysWideToNSString(l10n_util::GetStringF(
[email protected]9dcb59662009-09-23 01:15:50406 IDS_MULTIPLE_DOWNLOADS_REMOVE_CONFIRM_WARNING, product_name,
407 IntToWString(downloadCount)));
[email protected]e8b5f7882009-09-14 20:59:13408 explanationText =
[email protected]9dcb59662009-09-23 01:15:50409 base::SysWideToNSString(l10n_util::GetStringF(
410 IDS_MULTIPLE_DOWNLOADS_REMOVE_CONFIRM_EXPLANATION, product_name));
[email protected]73f5b362009-08-10 23:58:21411
412 // Cancel downloads and exit button text.
413 exitTitle =
[email protected]e8b5f7882009-09-14 20:59:13414 base::SysWideToNSString(l10n_util::GetString(
415 IDS_MULTIPLE_DOWNLOADS_REMOVE_CONFIRM_OK_BUTTON_LABEL));
[email protected]73f5b362009-08-10 23:58:21416
417 // Wait for downloads button text.
418 waitTitle =
[email protected]e8b5f7882009-09-14 20:59:13419 base::SysWideToNSString(l10n_util::GetString(
420 IDS_MULTIPLE_DOWNLOADS_REMOVE_CONFIRM_CANCEL_BUTTON_LABEL));
[email protected]73f5b362009-08-10 23:58:21421 }
422
423 // 'waitButton' is the default choice.
[email protected]e8b5f7882009-09-14 20:59:13424 int choice = NSRunAlertPanel(warningText, explanationText,
425 waitTitle, exitTitle, nil);
[email protected]73f5b362009-08-10 23:58:21426 return choice == NSAlertDefaultReturn ? YES : NO;
427}
428
429// Check all profiles for in progress downloads, and if we find any, prompt the
[email protected]09729a552009-08-03 23:21:41430// user to see if we should continue to exit (and thus cancel the downloads), or
431// if we should wait.
432- (BOOL)shouldQuitWithInProgressDownloads {
[email protected]73f5b362009-08-10 23:58:21433 ProfileManager* profile_manager = g_browser_process->profile_manager();
434 if (!profile_manager)
435 return YES;
[email protected]09729a552009-08-03 23:21:41436
[email protected]73f5b362009-08-10 23:58:21437 ProfileManager::const_iterator it = profile_manager->begin();
438 for (; it != profile_manager->end(); ++it) {
439 Profile* profile = *it;
[email protected]09729a552009-08-03 23:21:41440 DownloadManager* download_manager = profile->GetDownloadManager();
[email protected]73f5b362009-08-10 23:58:21441 if (download_manager && download_manager->in_progress_count() > 0) {
442 int downloadCount = download_manager->in_progress_count();
443 if ([self userWillWaitForInProgressDownloads:downloadCount]) {
444 // Create a new browser window (if necessary) and navigate to the
445 // downloads page if the user chooses to wait.
446 Browser* browser = BrowserList::FindBrowserWithProfile(profile);
447 if (!browser) {
448 browser = Browser::Create(profile);
449 browser->window()->Show();
450 }
451 DCHECK(browser);
452 browser->ShowDownloadsTab();
453 return NO;
454 }
[email protected]09729a552009-08-03 23:21:41455
[email protected]73f5b362009-08-10 23:58:21456 // User wants to exit.
457 return YES;
[email protected]09729a552009-08-03 23:21:41458 }
[email protected]09729a552009-08-03 23:21:41459 }
460
[email protected]73f5b362009-08-10 23:58:21461 // No profiles or active downloads found, okay to exit.
[email protected]09729a552009-08-03 23:21:41462 return YES;
463}
464
[email protected]fbc947b2009-06-19 13:28:24465// Called to determine if we should enable the "restore tab" menu item.
466// Checks with the TabRestoreService to see if there's anything there to
467// restore and returns YES if so.
468- (BOOL)canRestoreTab {
469 TabRestoreService* service = [self defaultProfile]->GetTabRestoreService();
470 return service && !service->entries().empty();
471}
472
[email protected]6a281332009-10-13 17:41:06473// Returns true if there is no browser window, or if the active window is
474// blocked by a modal dialog.
475- (BOOL)keyWindowIsMissingOrBlocked {
476 Browser* browser = BrowserList::GetLastActive();
477 return browser == NULL ||
478 ![[browser->window()->GetNativeHandle() attachedSheet]
479 isKindOfClass:[NSWindow class]];
480}
481
[email protected]88d74942009-01-21 22:04:44482// Called to validate menu items when there are no key windows. All the
483// items we care about have been set with the |commandDispatch:| action and
484// a target of FirstResponder in IB. If it's not one of those, let it
485// continue up the responder chain to be handled elsewhere. We pull out the
486// tag as the cross-platform constant to differentiate and dispatch the
487// various commands.
488- (BOOL)validateUserInterfaceItem:(id<NSValidatedUserInterfaceItem>)item {
489 SEL action = [item action];
490 BOOL enable = NO;
491 if (action == @selector(commandDispatch:)) {
492 NSInteger tag = [item tag];
[email protected]fbc947b2009-06-19 13:28:24493 if (menuState_->SupportsCommand(tag)) {
494 switch (tag) {
[email protected]419eb2a2009-11-11 16:26:26495 // The File Menu commands are not automatically disabled by Cocoa when a
496 // dialog sheet obscures the browser window, so we disable several of
497 // them here. We don't need to include IDC_CLOSE_WINDOW, because
498 // app_controller is only activated when there are no key windows (see
499 // function comment).
[email protected]fbc947b2009-06-19 13:28:24500 case IDC_RESTORE_TAB:
[email protected]6a281332009-10-13 17:41:06501 enable = [self keyWindowIsMissingOrBlocked] && [self canRestoreTab];
502 break;
[email protected]6a281332009-10-13 17:41:06503 case IDC_OPEN_FILE:
[email protected]6a281332009-10-13 17:41:06504 case IDC_NEW_TAB:
[email protected]6a281332009-10-13 17:41:06505 enable = [self keyWindowIsMissingOrBlocked];
[email protected]fbc947b2009-06-19 13:28:24506 break;
[email protected]f9bc9b92009-11-24 00:55:35507 case IDC_SYNC_BOOKMARKS:
508 enable = ProfileSyncService::IsSyncEnabled();
[email protected]40f047972009-11-25 03:54:40509 sync_ui_util::UpdateSyncItem(item, enable, [self defaultProfile]);
[email protected]f9bc9b92009-11-24 00:55:35510 break;
[email protected]fbc947b2009-06-19 13:28:24511 default:
512 enable = menuState_->IsCommandEnabled(tag) ? YES : NO;
513 }
514 }
[email protected]3b6aa8b62009-09-15 21:36:11515 } else if (action == @selector(terminate:)) {
[email protected]88d74942009-01-21 22:04:44516 enable = YES;
[email protected]3111f08b2009-04-30 16:01:52517 } else if (action == @selector(showPreferences:)) {
518 enable = YES;
[email protected]bde3dda2009-05-20 22:13:07519 } else if (action == @selector(orderFrontStandardAboutPanel:)) {
520 enable = YES;
[email protected]3d4bd23f2009-10-06 03:58:38521 } else if (action == @selector(newWindowFromDock:)) {
522 enable = YES;
[email protected]88d74942009-01-21 22:04:44523 }
524 return enable;
525}
526
[email protected]947fc0d2010-01-14 22:33:05527// Called when the user picks a menu item when there are no key windows, or when
528// there is no foreground browser window. Calls through to the browser object to
529// execute the command. This assumes that the command is supported and doesn't
530// check, otherwise it would have been disabled in the UI in
531// validateUserInterfaceItem:.
[email protected]88d74942009-01-21 22:04:44532- (void)commandDispatch:(id)sender {
[email protected]93e181762009-05-29 14:30:38533 Profile* defaultProfile = [self defaultProfile];
[email protected]f0a51fb52009-03-05 12:46:38534
[email protected]947fc0d2010-01-14 22:33:05535 // Handle the case where we're dispatching a command from a sender that's in a
536 // browser window. This means that the command came from a background window
537 // and is getting here because the foreground window is not a browser window.
538 if ([sender respondsToSelector:@selector(window)]) {
539 id delegate = [[sender window] windowController];
540 if ([delegate isKindOfClass:[BrowserWindowController class]]) {
541 [delegate commandDispatch:sender];
542 return;
543 }
544 }
545
[email protected]88d74942009-01-21 22:04:44546 NSInteger tag = [sender tag];
547 switch (tag) {
[email protected]fbc947b2009-06-19 13:28:24548 case IDC_NEW_TAB:
[email protected]88d74942009-01-21 22:04:44549 case IDC_NEW_WINDOW:
[email protected]91a5b3e2009-10-30 19:32:22550 case IDC_FOCUS_LOCATION:
[email protected]216e9042009-10-29 17:05:23551 g_is_opening_new_window = true;
[email protected]93e181762009-05-29 14:30:38552 Browser::OpenEmptyWindow(defaultProfile);
[email protected]216e9042009-10-29 17:05:23553 g_is_opening_new_window = false;
[email protected]88d74942009-01-21 22:04:44554 break;
[email protected]cddc5242009-12-07 18:54:33555 case IDC_FOCUS_SEARCH:
556 g_is_opening_new_window = true;
557 Browser::OpenEmptyWindow(defaultProfile);
558 g_is_opening_new_window = false;
559 BrowserList::GetLastActive()->FocusSearch();
560 break;
[email protected]863ff662009-01-26 20:18:18561 case IDC_NEW_INCOGNITO_WINDOW:
[email protected]e9e211272009-09-22 16:39:11562 Browser::OpenEmptyWindow(defaultProfile->GetOffTheRecordProfile());
[email protected]863ff662009-01-26 20:18:18563 break;
[email protected]fbc947b2009-06-19 13:28:24564 case IDC_RESTORE_TAB:
565 Browser::OpenWindowWithRestoredTabs(defaultProfile);
566 break;
[email protected]e19516d2009-04-28 17:15:19567 case IDC_OPEN_FILE:
[email protected]cddc5242009-12-07 18:54:33568 g_is_opening_new_window = true;
[email protected]93e181762009-05-29 14:30:38569 Browser::OpenEmptyWindow(defaultProfile);
[email protected]cddc5242009-12-07 18:54:33570 g_is_opening_new_window = false;
[email protected]e19516d2009-04-28 17:15:19571 BrowserList::GetLastActive()->
572 ExecuteCommandWithDisposition(IDC_OPEN_FILE, CURRENT_TAB);
573 break;
[email protected]1fdff702009-10-22 00:36:18574 case IDC_CLEAR_BROWSING_DATA: {
[email protected]93e181762009-05-29 14:30:38575 // There may not be a browser open, so use the default profile.
[email protected]049ac832009-12-15 16:26:54576 [ClearBrowsingDataController
577 showClearBrowsingDialogForProfile:defaultProfile];
[email protected]93e181762009-05-29 14:30:38578 break;
[email protected]1fdff702009-10-22 00:36:18579 }
[email protected]4aee5652009-11-19 18:59:21580 case IDC_IMPORT_SETTINGS: {
581 UserMetrics::RecordAction("Import_ShowDlg", defaultProfile);
582 // Note that this dialog controller cleans itself up when closed
583 // so auto-scoping it here is not necessary.
584 [[[ImportSettingsDialogController alloc]
585 initWithProfile:defaultProfile parentWindow:nil] runModalDialog];
586 break;
587 }
[email protected]91a5b3e2009-10-30 19:32:22588 case IDC_SHOW_HISTORY:
589 Browser::OpenHistoryWindow(defaultProfile);
590 break;
591 case IDC_SHOW_DOWNLOADS:
592 Browser::OpenDownloadsWindow(defaultProfile);
593 break;
[email protected]bb37e6ec2009-11-18 17:59:36594 case IDC_MANAGE_EXTENSIONS:
595 Browser::OpenExtensionsWindow(defaultProfile);
596 break;
[email protected]1fdff702009-10-22 00:36:18597 case IDC_HELP_PAGE:
598 Browser::OpenHelpWindow(defaultProfile);
599 break;
[email protected]3896b182009-11-03 16:15:32600 case IDC_REPORT_BUG: {
601 Browser* browser = BrowserList::GetLastActive();
602 TabContents* current_tab = (browser != NULL) ?
603 browser->GetSelectedTabContents() : NULL;
604 BugReportWindowController* controller =
605 [[BugReportWindowController alloc]
606 initWithTabContents:current_tab
607 profile:[self defaultProfile]];
608 [controller runModalDialog];
609 break;
610 }
[email protected]f9bc9b92009-11-24 00:55:35611 case IDC_SYNC_BOOKMARKS:
612 // TODO(akalin): Add a constant to denote starting sync from the
613 // main menu and use that instead of START_FROM_WRENCH.
[email protected]40f047972009-11-25 03:54:40614 sync_ui_util::OpenSyncMyBookmarksDialog(
[email protected]f9bc9b92009-11-24 00:55:35615 defaultProfile, ProfileSyncService::START_FROM_WRENCH);
616 break;
[email protected]ceaaf1812010-01-20 22:13:09617 case IDC_TASK_MANAGER:
618 UserMetrics::RecordAction("TaskManager", defaultProfile);
619 TaskManagerMac::Show();
620 break;
[email protected]88d74942009-01-21 22:04:44621 };
622}
623
[email protected]947fc0d2010-01-14 22:33:05624// Same as |-commandDispatch:|, but executes commands using a disposition
625// determined by the key flags. This will get called in the case where the
626// frontmost window is not a browser window, and the user has command-clicked
627// a button in a background browser window whose action is
628// |-commandDispatchUsingKeyModifiers:|
629- (void)commandDispatchUsingKeyModifiers:(id)sender {
630 DCHECK(sender);
631 if ([sender respondsToSelector:@selector(window)]) {
632 id delegate = [[sender window] windowController];
633 if ([delegate isKindOfClass:[BrowserWindowController class]]) {
634 [delegate commandDispatchUsingKeyModifiers:sender];
635 }
636 }
637}
638
[email protected]ff81e0a2009-04-13 14:58:54639// NSApplication delegate method called when someone clicks on the
640// dock icon and there are no open windows. To match standard mac
641// behavior, we should open a new window.
642- (BOOL)applicationShouldHandleReopen:(NSApplication*)theApplication
643 hasVisibleWindows:(BOOL)flag {
644 // Don't do anything if there are visible windows. This will cause
645 // AppKit to unminimize the most recently minimized window.
646 if (flag)
647 return YES;
648
649 // Otherwise open a new window.
[email protected]216e9042009-10-29 17:05:23650 g_is_opening_new_window = true;
[email protected]ff81e0a2009-04-13 14:58:54651 Browser::OpenEmptyWindow([self defaultProfile]);
[email protected]216e9042009-10-29 17:05:23652 g_is_opening_new_window = false;
[email protected]ff81e0a2009-04-13 14:58:54653
654 // We've handled the reopen event, so return NO to tell AppKit not
655 // to do anything.
656 return NO;
657}
658
[email protected]88d74942009-01-21 22:04:44659- (void)initMenuState {
[email protected]3111f08b2009-04-30 16:01:52660 menuState_.reset(new CommandUpdater(NULL));
[email protected]fbc947b2009-06-19 13:28:24661 menuState_->UpdateCommandEnabled(IDC_NEW_TAB, true);
[email protected]88d74942009-01-21 22:04:44662 menuState_->UpdateCommandEnabled(IDC_NEW_WINDOW, true);
[email protected]863ff662009-01-26 20:18:18663 menuState_->UpdateCommandEnabled(IDC_NEW_INCOGNITO_WINDOW, true);
[email protected]e19516d2009-04-28 17:15:19664 menuState_->UpdateCommandEnabled(IDC_OPEN_FILE, true);
[email protected]93e181762009-05-29 14:30:38665 menuState_->UpdateCommandEnabled(IDC_CLEAR_BROWSING_DATA, true);
[email protected]fbc947b2009-06-19 13:28:24666 menuState_->UpdateCommandEnabled(IDC_RESTORE_TAB, false);
[email protected]91a5b3e2009-10-30 19:32:22667 menuState_->UpdateCommandEnabled(IDC_FOCUS_LOCATION, true);
[email protected]cddc5242009-12-07 18:54:33668 menuState_->UpdateCommandEnabled(IDC_FOCUS_SEARCH, true);
[email protected]91a5b3e2009-10-30 19:32:22669 menuState_->UpdateCommandEnabled(IDC_SHOW_HISTORY, true);
670 menuState_->UpdateCommandEnabled(IDC_SHOW_DOWNLOADS, true);
[email protected]bb37e6ec2009-11-18 17:59:36671 menuState_->UpdateCommandEnabled(IDC_MANAGE_EXTENSIONS, true);
[email protected]1fdff702009-10-22 00:36:18672 menuState_->UpdateCommandEnabled(IDC_HELP_PAGE, true);
[email protected]4aee5652009-11-19 18:59:21673 menuState_->UpdateCommandEnabled(IDC_IMPORT_SETTINGS, true);
[email protected]3896b182009-11-03 16:15:32674 menuState_->UpdateCommandEnabled(IDC_REPORT_BUG, true);
[email protected]f9bc9b92009-11-24 00:55:35675 menuState_->UpdateCommandEnabled(IDC_SYNC_BOOKMARKS,
676 ProfileSyncService::IsSyncEnabled());
[email protected]ceaaf1812010-01-20 22:13:09677 menuState_->UpdateCommandEnabled(IDC_TASK_MANAGER, true);
[email protected]88d74942009-01-21 22:04:44678}
[email protected]1bcdb532009-01-16 17:47:57679
[email protected]3f34599d2009-03-25 22:11:43680- (Profile*)defaultProfile {
[email protected]3f34599d2009-03-25 22:11:43681 // TODO(jrg): Find a better way to get the "default" profile.
682 if (g_browser_process->profile_manager())
[email protected]065566b2010-01-20 20:38:26683 return *g_browser_process->profile_manager()->begin();
[email protected]3f34599d2009-03-25 22:11:43684
[email protected]f6314002009-04-23 01:18:13685 return NULL;
[email protected]3f34599d2009-03-25 22:11:43686}
687
[email protected]57750f822009-04-21 21:43:09688// Various methods to open URLs that we get in a native fashion. We use
689// BrowserInit here because on the other platforms, URLs to open come through
690// the ProcessSingleton, and it calls BrowserInit. It's best to bottleneck the
691// openings through that for uniform handling.
692
[email protected]136140c2009-05-19 13:58:25693- (void)openURLs:(const std::vector<GURL>&)urls {
[email protected]caadfca2010-01-22 21:51:21694 // If the browser hasn't started yet, just queue up the URLs.
695 if (!startupComplete_) {
696 startupURLs_.insert(startupURLs_.end(), urls.begin(), urls.end());
[email protected]136140c2009-05-19 13:58:25697 return;
698 }
[email protected]57750f822009-04-21 21:43:09699
[email protected]0e863512009-05-28 19:45:07700 Browser* browser = BrowserList::GetLastActive();
701 // if no browser window exists then create one with no tabs to be filled in
702 if (!browser) {
703 browser = Browser::Create([self defaultProfile]);
[email protected]ce560f82009-06-03 09:39:44704 browser->window()->Show();
[email protected]0e863512009-05-28 19:45:07705 }
706
[email protected]51343d5a2009-10-26 22:39:33707 CommandLine dummy(CommandLine::ARGUMENTS_ONLY);
[email protected]57750f822009-04-21 21:43:09708 BrowserInit::LaunchWithProfile launch(std::wstring(), dummy);
[email protected]0e863512009-05-28 19:45:07709 launch.OpenURLsInBrowser(browser, false, urls);
[email protected]57750f822009-04-21 21:43:09710}
711
[email protected]57750f822009-04-21 21:43:09712- (void)getUrl:(NSAppleEventDescriptor*)event
713 withReply:(NSAppleEventDescriptor*)reply {
714 NSString* urlStr = [[event paramDescriptorForKeyword:keyDirectObject]
715 stringValue];
716
717 GURL gurl(base::SysNSStringToUTF8(urlStr));
718 std::vector<GURL> gurlVector;
719 gurlVector.push_back(gurl);
720
[email protected]136140c2009-05-19 13:58:25721 [self openURLs:gurlVector];
[email protected]57750f822009-04-21 21:43:09722}
723
[email protected]caadfca2010-01-22 21:51:21724- (void)application:(NSApplication*)sender
725 openFiles:(NSArray*)filenames {
[email protected]57750f822009-04-21 21:43:09726 std::vector<GURL> gurlVector;
[email protected]caadfca2010-01-22 21:51:21727 for (NSString* file in filenames) {
728 GURL gurl = net::FilePathToFileURL(FilePath(base::SysNSStringToUTF8(file)));
[email protected]57750f822009-04-21 21:43:09729 gurlVector.push_back(gurl);
730 }
[email protected]caadfca2010-01-22 21:51:21731 if (!gurlVector.empty())
732 [self openURLs:gurlVector];
733 else
734 NOTREACHED() << "Nothing to open!";
[email protected]57750f822009-04-21 21:43:09735
[email protected]caadfca2010-01-22 21:51:21736 [sender replyToOpenOrPrint:NSApplicationDelegateReplySuccess];
[email protected]57750f822009-04-21 21:43:09737}
[email protected]3f34599d2009-03-25 22:11:43738
[email protected]767543d2009-04-30 19:23:58739// Called when the preferences window is closed. We use this to release the
740// window controller.
[email protected]d4e18652009-11-19 21:52:16741- (void)prefsWindowClosed:(NSNotification*)notification {
742 NSWindow* window = [prefsController_ window];
743 DCHECK([notification object] == window);
744 NSNotificationCenter* defaultCenter = [NSNotificationCenter defaultCenter];
745 [defaultCenter removeObserver:self
746 name:NSWindowWillCloseNotification
747 object:window];
748 // PreferencesWindowControllers are autoreleased in
749 // -[PreferencesWindowController windowWillClose:].
750 prefsController_ = nil;
[email protected]767543d2009-04-30 19:23:58751}
752
[email protected]3111f08b2009-04-30 16:01:52753// Show the preferences window, or bring it to the front if it's already
754// visible.
755- (IBAction)showPreferences:(id)sender {
[email protected]d989f07c2009-11-14 00:35:46756 [self showPreferencesWindow:sender
757 page:OPTIONS_PAGE_DEFAULT
758 profile:[self defaultProfile]];
759}
760
761- (void)showPreferencesWindow:(id)sender
762 page:(OptionsPage)page
763 profile:(Profile*)profile {
[email protected]d4e18652009-11-19 21:52:16764 if (prefsController_) {
[email protected]d989f07c2009-11-14 00:35:46765 [prefsController_ switchToPage:page animate:YES];
766 } else {
[email protected]d4e18652009-11-19 21:52:16767 prefsController_ =
768 [[PreferencesWindowController alloc] initWithProfile:profile
769 initialPage:page];
[email protected]767543d2009-04-30 19:23:58770 // Watch for a notification of when it goes away so that we can destroy
771 // the controller.
772 [[NSNotificationCenter defaultCenter]
773 addObserver:self
774 selector:@selector(prefsWindowClosed:)
[email protected]d4e18652009-11-19 21:52:16775 name:NSWindowWillCloseNotification
776 object:[prefsController_ window]];
[email protected]42404382009-04-30 17:59:24777 }
778 [prefsController_ showPreferences:sender];
[email protected]3111f08b2009-04-30 16:01:52779}
780
[email protected]bde3dda2009-05-20 22:13:07781// Called when the about window is closed. We use this to release the
782// window controller.
[email protected]d4e18652009-11-19 21:52:16783- (void)aboutWindowClosed:(NSNotification*)notification {
784 NSWindow* window = [aboutController_ window];
785 DCHECK(window == [notification object]);
[email protected]bde3dda2009-05-20 22:13:07786 [[NSNotificationCenter defaultCenter]
[email protected]49aeee52009-10-26 19:58:13787 removeObserver:self
[email protected]d4e18652009-11-19 21:52:16788 name:NSWindowWillCloseNotification
789 object:window];
790 // AboutWindowControllers are autoreleased in
791 // -[AboutWindowController windowWillClose:].
792 aboutController_ = nil;
[email protected]bde3dda2009-05-20 22:13:07793}
794
795- (IBAction)orderFrontStandardAboutPanel:(id)sender {
[email protected]bde3dda2009-05-20 22:13:07796 if (!aboutController_) {
[email protected]d4e18652009-11-19 21:52:16797 aboutController_ =
798 [[AboutWindowController alloc] initWithProfile:[self defaultProfile]];
[email protected]49aeee52009-10-26 19:58:13799
[email protected]bde3dda2009-05-20 22:13:07800 // Watch for a notification of when it goes away so that we can destroy
801 // the controller.
802 [[NSNotificationCenter defaultCenter]
803 addObserver:self
804 selector:@selector(aboutWindowClosed:)
[email protected]d4e18652009-11-19 21:52:16805 name:NSWindowWillCloseNotification
806 object:[aboutController_ window]];
[email protected]bde3dda2009-05-20 22:13:07807 }
[email protected]49aeee52009-10-26 19:58:13808
[email protected]bde3dda2009-05-20 22:13:07809 [aboutController_ showWindow:self];
[email protected]bde3dda2009-05-20 22:13:07810}
811
[email protected]3d4bd23f2009-10-06 03:58:38812// Explicitly bring to the foreground when creating new windows from the dock.
813- (void)newWindowFromDock:(id)sender {
814 [NSApp activateIgnoringOtherApps:YES];
815 [self commandDispatch:sender];
816}
817
[email protected]288bfcd32009-09-14 18:14:46818- (NSMenu*)applicationDockMenu:(id)sender {
[email protected]018a3962009-09-17 22:23:44819 NSMenu* dockMenu = [[[NSMenu alloc] initWithTitle: @""] autorelease];
820 NSString* titleStr = l10n_util::GetNSStringWithFixup(IDS_NEW_WINDOW_MAC);
821 scoped_nsobject<NSMenuItem> item([[NSMenuItem alloc]
822 initWithTitle:titleStr
[email protected]3d4bd23f2009-10-06 03:58:38823 action:@selector(newWindowFromDock:)
[email protected]018a3962009-09-17 22:23:44824 keyEquivalent:@""]);
[email protected]288bfcd32009-09-14 18:14:46825 [item setTarget:self];
826 [item setTag:IDC_NEW_WINDOW];
[email protected]018a3962009-09-17 22:23:44827 [dockMenu addItem:item];
[email protected]288bfcd32009-09-14 18:14:46828
829 titleStr = l10n_util::GetNSStringWithFixup(IDS_NEW_INCOGNITO_WINDOW_MAC);
[email protected]018a3962009-09-17 22:23:44830 item.reset([[NSMenuItem alloc] initWithTitle:titleStr
[email protected]3d4bd23f2009-10-06 03:58:38831 action:@selector(newWindowFromDock:)
[email protected]018a3962009-09-17 22:23:44832 keyEquivalent:@""]);
[email protected]288bfcd32009-09-14 18:14:46833 [item setTarget:self];
834 [item setTag:IDC_NEW_INCOGNITO_WINDOW];
[email protected]018a3962009-09-17 22:23:44835 [dockMenu addItem:item];
[email protected]288bfcd32009-09-14 18:14:46836
[email protected]018a3962009-09-17 22:23:44837 return dockMenu;
[email protected]288bfcd32009-09-14 18:14:46838}
839
[email protected]caadfca2010-01-22 21:51:21840- (const std::vector<GURL>&)startupURLs {
841 return startupURLs_;
842}
843
844- (void)clearStartupURLs {
845 startupURLs_.clear();
846}
847
[email protected]1bcdb532009-01-16 17:47:57848@end
[email protected]60ad3e22009-09-18 21:07:19849
850//---------------------------------------------------------------------------
851
[email protected]60ad3e22009-09-18 21:07:19852void ShowOptionsWindow(OptionsPage page,
853 OptionsGroup highlight_group,
854 Profile* profile) {
[email protected]d989f07c2009-11-14 00:35:46855 // TODO(akalin): Use highlight_group.
856 AppController* appController = [NSApp delegate];
857 [appController showPreferencesWindow:nil page:page profile:profile];
[email protected]60ad3e22009-09-18 21:07:19858}
[email protected]216e9042009-10-29 17:05:23859
860namespace app_controller_mac {
861
862bool IsOpeningNewWindow() {
863 return g_is_opening_new_window;
864}
865
866} // namespace app_controller_mac