1 // Copyright (c) 2011 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
5 #include "chrome/browser/ui/browser.h"
6
7 #if defined(OS_WIN)
8 #include <shellapi.h>
9 #include <windows.h>
10 #endif // OS_WIN
11
12 #include <algorithm>
13 #include <string>
14
15 #include "base/base_paths.h"
16 #include "base/command_line.h"
17 #include "base/logging.h"
18 #include "base/metrics/histogram.h"
19 #include "base/path_service.h"
20 #include "base/string_util.h"
21 #include "base/threading/thread.h"
22 #include "base/threading/thread_restrictions.h"
23 #include "base/time.h"
24 #include "base/utf_string_conversions.h"
25 #include "chrome/app/chrome_command_ids.h"
26 #include "chrome/browser/autofill/autofill_manager.h"
27 #include "chrome/browser/background_contents_service.h"
28 #include "chrome/browser/bookmarks/bookmark_model.h"
29 #include "chrome/browser/bookmarks/bookmark_utils.h"
30 #include "chrome/browser/browser_process.h"
31 #include "chrome/browser/browser_shutdown.h"
32 #include "chrome/browser/browser_url_handler.h"
33 #include "chrome/browser/character_encoding.h"
34 #include "chrome/browser/debugger/devtools_manager.h"
35 #include "chrome/browser/debugger/devtools_toggle_action.h"
36 #include "chrome/browser/debugger/devtools_window.h"
37 #include "chrome/browser/download/download_item.h"
38 #include "chrome/browser/download/download_item_model.h"
39 #include "chrome/browser/download/download_manager.h"
40 #include "chrome/browser/download/download_shelf.h"
41 #include "chrome/browser/download/download_started_animation.h"
42 #include "chrome/browser/download/save_package.h"
43 #include "chrome/browser/extensions/crx_installer.h"
44 #include "chrome/browser/extensions/extension_browser_event_router.h"
45 #include "chrome/browser/extensions/extension_disabled_infobar_delegate.h"
46 #include "chrome/browser/extensions/extension_host.h"
47 #include "chrome/browser/extensions/extension_prefs.h"
48 #include "chrome/browser/extensions/extension_service.h"
49 #include "chrome/browser/extensions/extension_tab_helper.h"
50 #include "chrome/browser/extensions/extension_tabs_module.h"
51 #include "chrome/browser/first_run/first_run.h"
52 #include "chrome/browser/google/google_url_tracker.h"
53 #include "chrome/browser/google/google_util.h"
54 #include "chrome/browser/instant/instant_controller.h"
55 #include "chrome/browser/instant/instant_unload_handler.h"
56 #include "chrome/browser/metrics/user_metrics.h"
57 #include "chrome/browser/net/browser_url_util.h"
58 #include "chrome/browser/net/url_fixer_upper.h"
59 #include "chrome/browser/notifications/notification_ui_manager.h"
60 #include "chrome/browser/platform_util.h"
61 #include "chrome/browser/prefs/pref_service.h"
62 #include "chrome/browser/printing/cloud_print/cloud_print_setup_flow.h"
63 #include "chrome/browser/printing/print_preview_tab_controller.h"
64 #include "chrome/browser/profiles/profile.h"
65 #include "chrome/browser/sessions/session_service.h"
66 #include "chrome/browser/sessions/session_types.h"
67 #include "chrome/browser/sessions/tab_restore_service.h"
68 #include "chrome/browser/sync/profile_sync_service.h"
69 #include "chrome/browser/sync/sync_ui_util.h"
70 #include "chrome/browser/tab_closeable_state_watcher.h"
71 #include "chrome/browser/tab_contents/background_contents.h"
72 #include "chrome/browser/tab_contents/simple_alert_infobar_delegate.h"
73 #include "chrome/browser/tabs/tab_finder.h"
74 #include "chrome/browser/tabs/tab_strip_model.h"
75 #include "chrome/browser/ui/browser_list.h"
76 #include "chrome/browser/ui/browser_tab_restore_service_delegate.h"
77 #include "chrome/browser/ui/browser_window.h"
78 #include "chrome/browser/ui/download/download_tab_helper.h"
79 #include "chrome/browser/ui/find_bar/find_bar.h"
80 #include "chrome/browser/ui/find_bar/find_bar_controller.h"
81 #include "chrome/browser/ui/find_bar/find_tab_helper.h"
82 #include "chrome/browser/ui/omnibox/location_bar.h"
83 #include "chrome/browser/ui/options/options_window.h"
84 #include "chrome/browser/ui/panels/panel.h"
85 #include "chrome/browser/ui/panels/panel_manager.h"
86 #include "chrome/browser/ui/search_engines/search_engine_tab_helper.h"
87 #include "chrome/browser/ui/status_bubble.h"
88 #include "chrome/browser/ui/tab_contents/tab_contents_wrapper.h"
89 #include "chrome/browser/ui/tabs/dock_info.h"
90 #include "chrome/browser/ui/tabs/tab_menu_model.h"
91 #include "chrome/browser/ui/web_applications/web_app_ui.h"
92 #include "chrome/browser/ui/webui/active_downloads_ui.h"
93 #include "chrome/browser/ui/webui/bug_report_ui.h"
94 #include "chrome/browser/ui/webui/options/content_settings_handler.h"
95 #include "chrome/browser/ui/window_sizer.h"
96 #include "chrome/browser/upgrade_detector.h"
97 #include "chrome/browser/web_applications/web_app.h"
98 #include "chrome/common/chrome_constants.h"
99 #include "chrome/common/chrome_switches.h"
100 #include "chrome/common/content_restriction.h"
101 #include "chrome/common/extensions/extension.h"
102 #include "chrome/common/extensions/extension_constants.h"
103 #include "chrome/common/pref_names.h"
104 #include "chrome/common/profiling.h"
105 #include "chrome/common/url_constants.h"
106 #include "chrome/common/web_apps.h"
107 #include "content/browser/host_zoom_map.h"
108 #include "content/browser/renderer_host/render_view_host.h"
109 #include "content/browser/site_instance.h"
110 #include "content/browser/tab_contents/interstitial_page.h"
111 #include "content/browser/tab_contents/navigation_controller.h"
112 #include "content/browser/tab_contents/navigation_entry.h"
113 #include "content/browser/tab_contents/tab_contents.h"
114 #include "content/browser/tab_contents/tab_contents_view.h"
115 #include "content/common/notification_service.h"
116 #include "content/common/page_transition_types.h"
117 #include "grit/chromium_strings.h"
118 #include "grit/generated_resources.h"
119 #include "grit/locale_settings.h"
120 #include "net/base/cookie_monster.h"
121 #include "net/base/net_util.h"
122 #include "net/base/registry_controlled_domain.h"
123 #include "net/base/static_cookie_policy.h"
124 #include "net/url_request/url_request_context.h"
125 #include "ui/base/animation/animation.h"
126 #include "ui/base/l10n/l10n_util.h"
127 #include "ui/gfx/point.h"
128 #include "webkit/glue/webkit_glue.h"
129 #include "webkit/glue/window_open_disposition.h"
130
131 #if defined(OS_WIN)
132 #include "app/win/shell.h"
133 #include "chrome/browser/autofill/autofill_ie_toolbar_import_win.h"
134 #include "chrome/browser/shell_integration.h"
135 #include "chrome/browser/ssl/ssl_error_info.h"
136 #include "chrome/browser/task_manager/task_manager.h"
137 #include "chrome/browser/ui/view_ids.h"
138 #include "chrome/browser/ui/views/location_bar/location_bar_view.h"
139 #endif // OS_WIN
140
141 #if defined(OS_MACOSX)
142 #include "chrome/browser/ui/cocoa/find_pasteboard.h"
143 #endif
144
145 #if defined(OS_CHROMEOS)
146 #include "chrome/browser/chromeos/boot_times_loader.h"
147 #include "chrome/browser/extensions/file_manager_util.h"
148 #endif
149
150 using base::TimeDelta;
151
152 ///////////////////////////////////////////////////////////////////////////////
153
154 namespace {
155
156 // The URL to be loaded to display Help.
157 const char kHelpContentUrl[] =
158 #if defined(OS_CHROMEOS)
159 #if defined(OFFICIAL_BUILD)
160 "chrome-extension://honijodknafkokifofgiaalefdiedpko/main.html";
161 #else
162 "https://www.google.com/support/chromeos/";
163 #endif
164 #else
165 "https://www.google.com/support/chrome/";
166 #endif
167
168 // The URL to be opened when the Help link on the Autofill dialog is clicked.
169 const char kAutofillHelpUrl[] =
170 #if defined(OS_CHROMEOS)
171 "https://www.google.com/support/chromeos/bin/answer.py?answer=142893";
172 #else
173 "https://www.google.com/support/chrome/bin/answer.py?answer=142893";
174 #endif
175
176 // The URL to be loaded to display the "Report a broken page" form.
177 const char kBrokenPageUrl[] =
178 "https://www.google.com/support/chrome/bin/request.py?contact_type="
179 "broken_website&format=inproduct&p.page_title=$1&p.page_url=$2";
180
181 // The URL for the privacy dashboard.
182 const char kPrivacyDashboardUrl[] = "https://www.google.com/dashboard";
183
184 // How long we wait before updating the browser chrome while loading a page.
185 const int kUIUpdateCoalescingTimeMS = 200;
186
187 const char kHashMark[] = "#";
188
189 #if defined(OS_CHROMEOS)
190 // If a popup window is bigger than this fraction of the screen on chrome os,
191 // turn it into a tab
192 const float kPopupMaxWidthFactor = 0.5;
193 const float kPopupMaxHeightFactor = 0.6;
194 #endif
195
196 } // namespace
197
198 extern bool g_log_bug53991;
199
200 ///////////////////////////////////////////////////////////////////////////////
201 // Browser, Constructors, Creation, Showing:
202
Browser(Type type,Profile * profile)203 Browser::Browser(Type type, Profile* profile)
204 : type_(type),
205 profile_(profile),
206 window_(NULL),
207 ALLOW_THIS_IN_INITIALIZER_LIST(
208 tab_handler_(TabHandler::CreateTabHandler(this))),
209 command_updater_(this),
210 toolbar_model_(this),
211 chrome_updater_factory_(this),
212 is_attempting_to_close_browser_(false),
213 cancel_download_confirmation_state_(NOT_PROMPTED),
214 maximized_state_(MAXIMIZED_STATE_DEFAULT),
215 method_factory_(this),
216 block_command_execution_(false),
217 last_blocked_command_id_(-1),
218 last_blocked_command_disposition_(CURRENT_TAB),
219 pending_web_app_action_(NONE),
220 ALLOW_THIS_IN_INITIALIZER_LIST(
221 tab_restore_service_delegate_(
222 new BrowserTabRestoreServiceDelegate(this))) {
223 registrar_.Add(this, NotificationType::SSL_VISIBLE_STATE_CHANGED,
224 NotificationService::AllSources());
225 registrar_.Add(this, NotificationType::EXTENSION_UPDATE_DISABLED,
226 NotificationService::AllSources());
227 registrar_.Add(this, NotificationType::EXTENSION_LOADED,
228 NotificationService::AllSources());
229 registrar_.Add(this, NotificationType::EXTENSION_UNLOADED,
230 NotificationService::AllSources());
231 registrar_.Add(this, NotificationType::EXTENSION_UNINSTALLED,
232 NotificationService::AllSources());
233 registrar_.Add(this, NotificationType::EXTENSION_PROCESS_TERMINATED,
234 NotificationService::AllSources());
235 registrar_.Add(this, NotificationType::BROWSER_THEME_CHANGED,
236 NotificationService::AllSources());
237
238 // Need to know when to alert the user of theme install delay.
239 registrar_.Add(this, NotificationType::EXTENSION_READY_FOR_INSTALL,
240 NotificationService::AllSources());
241
242 // NOTE: These prefs all need to be explicitly destroyed in the destructor
243 // or you'll get a nasty surprise when you run the incognito tests.
244 PrefService* local_state = g_browser_process->local_state();
245 if (local_state)
246 printing_enabled_.Init(prefs::kPrintingEnabled, local_state, this);
247 dev_tools_disabled_.Init(prefs::kDevToolsDisabled,
248 profile_->GetPrefs(), this);
249 incognito_mode_allowed_.Init(prefs::kIncognitoEnabled,
250 profile_->GetPrefs(), this);
251 edit_bookmarks_enabled_.Init(prefs::kEditBookmarksEnabled,
252 profile_->GetPrefs(), this);
253
254 InitCommandState();
255 BrowserList::AddBrowser(this);
256
257 encoding_auto_detect_.Init(prefs::kWebKitUsesUniversalDetector,
258 profile_->GetPrefs(), NULL);
259 use_vertical_tabs_.Init(prefs::kUseVerticalTabs, profile_->GetPrefs(), this);
260 instant_enabled_.Init(prefs::kInstantEnabled, profile_->GetPrefs(), this);
261 if (!TabMenuModel::AreVerticalTabsEnabled()) {
262 // If vertical tabs aren't enabled, explicitly turn them off. Otherwise we
263 // might show vertical tabs but not show an option to turn them off.
264 use_vertical_tabs_.SetValue(false);
265 }
266 UpdateTabStripModelInsertionPolicy();
267
268 tab_restore_service_ = profile->GetTabRestoreService();
269 if (tab_restore_service_) {
270 tab_restore_service_->AddObserver(this);
271 TabRestoreServiceChanged(tab_restore_service_);
272 }
273
274 if (profile_->GetProfileSyncService())
275 profile_->GetProfileSyncService()->AddObserver(this);
276
277 CreateInstantIfNecessary();
278
279 // Make sure TabFinder has been created. This does nothing if TabFinder is
280 // not enabled.
281 TabFinder::GetInstance();
282 }
283
~Browser()284 Browser::~Browser() {
285 VLOG_IF(1, g_log_bug53991) << "~Browser: " << profile_->IsOffTheRecord()
286 << "; stillActive="
287 << BrowserList::IsOffTheRecordSessionActive();
288
289 if (profile_->GetProfileSyncService())
290 profile_->GetProfileSyncService()->RemoveObserver(this);
291
292 BrowserList::RemoveBrowser(this);
293
294 #if defined(OS_WIN) || defined(OS_LINUX)
295 if (!BrowserList::HasBrowserWithProfile(profile_)) {
296 // We're the last browser window with this profile. We need to nuke the
297 // TabRestoreService, which will start the shutdown of the
298 // NavigationControllers and allow for proper shutdown. If we don't do this
299 // chrome won't shutdown cleanly, and may end up crashing when some
300 // thread tries to use the IO thread (or another thread) that is no longer
301 // valid.
302 // This isn't a valid assumption for Mac OS, as it stays running after
303 // the last browser has closed. The Mac equivalent is in its app
304 // controller.
305 profile_->ResetTabRestoreService();
306 }
307 #endif
308
309 SessionService* session_service = profile_->GetSessionService();
310 if (session_service)
311 session_service->WindowClosed(session_id_);
312
313 TabRestoreService* tab_restore_service = profile()->GetTabRestoreService();
314 if (tab_restore_service)
315 tab_restore_service->BrowserClosed(tab_restore_service_delegate());
316
317 encoding_auto_detect_.Destroy();
318 printing_enabled_.Destroy();
319 dev_tools_disabled_.Destroy();
320 incognito_mode_allowed_.Destroy();
321 instant_enabled_.Destroy();
322 use_vertical_tabs_.Destroy();
323 edit_bookmarks_enabled_.Destroy();
324
325 if (profile_->IsOffTheRecord() &&
326 !BrowserList::IsOffTheRecordSessionActive()) {
327 // An incognito profile is no longer needed, this indirectly
328 // frees its cache and cookies.
329 profile_->GetOriginalProfile()->DestroyOffTheRecordProfile();
330 }
331
332 // There may be pending file dialogs, we need to tell them that we've gone
333 // away so they don't try and call back to us.
334 if (select_file_dialog_.get())
335 select_file_dialog_->ListenerDestroyed();
336
337 TabRestoreServiceDestroyed(tab_restore_service_);
338 }
339
340 // static
Create(Profile * profile)341 Browser* Browser::Create(Profile* profile) {
342 Browser* browser = new Browser(TYPE_NORMAL, profile);
343 browser->InitBrowserWindow();
344 return browser;
345 }
346
347 // static
CreateForPopup(Type type,Profile * profile,TabContents * new_contents,const gfx::Rect & initial_bounds)348 Browser* Browser::CreateForPopup(Type type,
349 Profile* profile,
350 TabContents* new_contents,
351 const gfx::Rect& initial_bounds) {
352 DCHECK(type & TYPE_POPUP);
353 Browser* browser = new Browser(type, profile);
354 browser->set_override_bounds(initial_bounds);
355 browser->InitBrowserWindow();
356 TabContentsWrapper* wrapper = new TabContentsWrapper(new_contents);
357 browser->tabstrip_model()->AppendTabContents(wrapper, true);
358 return browser;
359 }
360
361 // static
CreateForType(Type type,Profile * profile)362 Browser* Browser::CreateForType(Type type, Profile* profile) {
363 Browser* browser = new Browser(type, profile);
364 browser->InitBrowserWindow();
365 return browser;
366 }
367
368 // static
CreateForApp(const std::string & app_name,const gfx::Size & window_size,Profile * profile,bool is_panel)369 Browser* Browser::CreateForApp(const std::string& app_name,
370 const gfx::Size& window_size,
371 Profile* profile,
372 bool is_panel) {
373 Browser::Type type = TYPE_APP;
374
375 if (is_panel) {
376 if (CommandLine::ForCurrentProcess()->HasSwitch(switches::kEnablePanels)) {
377 type = TYPE_APP_PANEL;
378 } else {
379 // TYPE_APP_PANEL is the logical choice. However, the panel UI
380 // is not fully implemented. See crbug/55943.
381 type = TYPE_APP_POPUP;
382 }
383 }
384
385 Browser* browser = new Browser(type, profile);
386 browser->app_name_ = app_name;
387
388 if (!window_size.IsEmpty()) {
389 gfx::Rect initial_pos(window_size);
390 browser->set_override_bounds(initial_pos);
391 }
392
393 browser->InitBrowserWindow();
394
395 return browser;
396 }
397
398 // static
CreateForDevTools(Profile * profile)399 Browser* Browser::CreateForDevTools(Profile* profile) {
400 Browser* browser = new Browser(TYPE_DEVTOOLS, profile);
401 browser->app_name_ = DevToolsWindow::kDevToolsApp;
402 browser->InitBrowserWindow();
403 return browser;
404 }
405
InitBrowserWindow()406 void Browser::InitBrowserWindow() {
407 DCHECK(!window_);
408
409 window_ = CreateBrowserWindow();
410
411 #if defined(OS_WIN)
412 {
413 // TODO: This might hit the disk
414 // http://code.google.com/p/chromium/issues/detail?id=61638
415 base::ThreadRestrictions::ScopedAllowIO allow_io;
416
417 // Set the app user model id for this application to that of the application
418 // name. See http://crbug.com/7028.
419 app::win::SetAppIdForWindow(
420 type_ & TYPE_APP ?
421 ShellIntegration::GetAppId(UTF8ToWide(app_name_), profile_->GetPath()) :
422 ShellIntegration::GetChromiumAppId(profile_->GetPath()),
423 window()->GetNativeHandle());
424 }
425 #endif
426
427 NotificationService::current()->Notify(
428 NotificationType::BROWSER_WINDOW_READY,
429 Source<Browser>(this),
430 NotificationService::NoDetails());
431
432 // Show the First Run information bubble if we've been told to.
433 PrefService* local_state = g_browser_process->local_state();
434 if (!local_state)
435 return;
436 if (local_state->FindPreference(prefs::kShouldShowFirstRunBubble) &&
437 local_state->GetBoolean(prefs::kShouldShowFirstRunBubble)) {
438 FirstRun::BubbleType bubble_type = FirstRun::LARGE_BUBBLE;
439 if (local_state->
440 FindPreference(prefs::kShouldUseOEMFirstRunBubble) &&
441 local_state->GetBoolean(prefs::kShouldUseOEMFirstRunBubble)) {
442 bubble_type = FirstRun::OEM_BUBBLE;
443 } else if (local_state->
444 FindPreference(prefs::kShouldUseMinimalFirstRunBubble) &&
445 local_state->GetBoolean(prefs::kShouldUseMinimalFirstRunBubble)) {
446 bubble_type = FirstRun::MINIMAL_BUBBLE;
447 }
448 // Reset the preference so we don't show the bubble for subsequent windows.
449 local_state->ClearPref(prefs::kShouldShowFirstRunBubble);
450 window_->GetLocationBar()->ShowFirstRunBubble(bubble_type);
451 }
452 if (local_state->FindPreference(
453 prefs::kAutofillPersonalDataManagerFirstRun) &&
454 local_state->GetBoolean(prefs::kAutofillPersonalDataManagerFirstRun)) {
455 // Notify PDM that this is a first run.
456 #if defined(OS_WIN)
457 ImportAutofillDataWin(profile_->GetPersonalDataManager());
458 #endif // defined(OS_WIN)
459 // Reset the preference so we don't call it again for subsequent windows.
460 local_state->ClearPref(prefs::kAutofillPersonalDataManagerFirstRun);
461 }
462 }
463
464 ///////////////////////////////////////////////////////////////////////////////
465 // Getters & Setters
466
user_data_dir_profiles() const467 const std::vector<std::wstring>& Browser::user_data_dir_profiles() const {
468 return g_browser_process->user_data_dir_profiles();
469 }
470
set_user_data_dir_profiles(const std::vector<std::wstring> & profiles)471 void Browser::set_user_data_dir_profiles(
472 const std::vector<std::wstring>& profiles) {
473 g_browser_process->user_data_dir_profiles() = profiles;
474 }
475
GetFindBarController()476 FindBarController* Browser::GetFindBarController() {
477 if (!find_bar_controller_.get()) {
478 FindBar* find_bar = BrowserWindow::CreateFindBar(this);
479 find_bar_controller_.reset(new FindBarController(find_bar));
480 find_bar->SetFindBarController(find_bar_controller_.get());
481 find_bar_controller_->ChangeTabContents(GetSelectedTabContentsWrapper());
482 find_bar_controller_->find_bar()->MoveWindowIfNecessary(gfx::Rect(), true);
483 }
484 return find_bar_controller_.get();
485 }
486
HasFindBarController() const487 bool Browser::HasFindBarController() const {
488 return find_bar_controller_.get() != NULL;
489 }
490
491 ///////////////////////////////////////////////////////////////////////////////
492 // Browser, Creation Helpers:
493
494 // static
OpenEmptyWindow(Profile * profile)495 void Browser::OpenEmptyWindow(Profile* profile) {
496 Browser* browser = Browser::Create(profile);
497 browser->AddBlankTab(true);
498 browser->window()->Show();
499 }
500
501 // static
OpenWindowWithRestoredTabs(Profile * profile)502 void Browser::OpenWindowWithRestoredTabs(Profile* profile) {
503 TabRestoreService* service = profile->GetTabRestoreService();
504 if (service)
505 service->RestoreMostRecentEntry(NULL);
506 }
507
508 // static
OpenURLOffTheRecord(Profile * profile,const GURL & url)509 void Browser::OpenURLOffTheRecord(Profile* profile, const GURL& url) {
510 Browser* browser = GetOrCreateTabbedBrowser(
511 profile->GetOffTheRecordProfile());
512 browser->AddSelectedTabWithURL(url, PageTransition::LINK);
513 browser->window()->Show();
514 }
515
516 // static
OpenApplication(Profile * profile,const Extension * extension,extension_misc::LaunchContainer container,TabContents * existing_tab)517 TabContents* Browser::OpenApplication(
518 Profile* profile,
519 const Extension* extension,
520 extension_misc::LaunchContainer container,
521 TabContents* existing_tab) {
522 TabContents* tab = NULL;
523 ExtensionPrefs* prefs = profile->GetExtensionService()->extension_prefs();
524 prefs->SetActiveBit(extension->id(), true);
525
526 UMA_HISTOGRAM_ENUMERATION("Extensions.AppLaunchContainer", container, 100);
527
528 switch (container) {
529 case extension_misc::LAUNCH_WINDOW:
530 case extension_misc::LAUNCH_PANEL:
531 tab = Browser::OpenApplicationWindow(profile, extension, container,
532 GURL(), NULL);
533 break;
534 case extension_misc::LAUNCH_TAB: {
535 tab = Browser::OpenApplicationTab(profile, extension, existing_tab);
536 break;
537 }
538 default:
539 NOTREACHED();
540 break;
541 }
542 return tab;
543 }
544
545 // static
OpenApplicationWindow(Profile * profile,const Extension * extension,extension_misc::LaunchContainer container,const GURL & url_input,Browser ** app_browser)546 TabContents* Browser::OpenApplicationWindow(
547 Profile* profile,
548 const Extension* extension,
549 extension_misc::LaunchContainer container,
550 const GURL& url_input,
551 Browser** app_browser) {
552 GURL url;
553 if (!url_input.is_empty()) {
554 if (extension)
555 DCHECK(extension->web_extent().ContainsURL(url_input));
556 url = url_input;
557 } else {
558 DCHECK(extension); // Empty url and no extension. Nothing to open.
559 url = extension->GetFullLaunchURL();
560 }
561
562 std::string app_name;
563 if (extension)
564 app_name =
565 web_app::GenerateApplicationNameFromExtensionId(extension->id());
566 else
567 app_name = web_app::GenerateApplicationNameFromURL(url);
568
569 RegisterAppPrefs(app_name, profile);
570
571 bool as_panel = extension && (container == extension_misc::LAUNCH_PANEL);
572
573 gfx::Size window_size;
574 if (extension)
575 window_size.SetSize(extension->launch_width(),
576 extension->launch_height());
577
578 Browser* browser = Browser::CreateForApp(app_name, window_size, profile,
579 as_panel);
580
581 if (app_browser)
582 *app_browser = browser;
583
584 TabContentsWrapper* wrapper =
585 browser->AddSelectedTabWithURL(url, PageTransition::START_PAGE);
586 TabContents* contents = wrapper->tab_contents();
587 contents->GetMutableRendererPrefs()->can_accept_load_drops = false;
588 contents->render_view_host()->SyncRendererPrefs();
589 browser->window()->Show();
590
591 // TODO(jcampan): http://crbug.com/8123 we should not need to set the initial
592 // focus explicitly.
593 contents->view()->SetInitialFocus();
594 return contents;
595 }
596
OpenAppShortcutWindow(Profile * profile,const GURL & url,bool update_shortcut)597 TabContents* Browser::OpenAppShortcutWindow(Profile* profile,
598 const GURL& url,
599 bool update_shortcut) {
600 Browser* app_browser;
601 TabContents* tab = OpenApplicationWindow(
602 profile,
603 NULL, // this is a URL app. No extension.
604 extension_misc::LAUNCH_WINDOW,
605 url,
606 &app_browser);
607
608 if (!tab)
609 return NULL;
610
611 if (update_shortcut) {
612 // Set UPDATE_SHORTCUT as the pending web app action. This action is picked
613 // up in LoadingStateChanged to schedule a GetApplicationInfo. And when
614 // the web app info is available, TabContents notifies Browser via
615 // OnDidGetApplicationInfo, which calls
616 // web_app::UpdateShortcutForTabContents when it sees UPDATE_SHORTCUT as
617 // pending web app action.
618 app_browser->pending_web_app_action_ = UPDATE_SHORTCUT;
619 }
620 return tab;
621 }
622
623 // static
OpenApplicationTab(Profile * profile,const Extension * extension,TabContents * existing_tab)624 TabContents* Browser::OpenApplicationTab(Profile* profile,
625 const Extension* extension,
626 TabContents* existing_tab) {
627 Browser* browser =
628 BrowserList::FindBrowserWithType(profile, Browser::TYPE_NORMAL, false);
629 TabContents* contents = NULL;
630 if (!browser)
631 return contents;
632
633 // Check the prefs for overridden mode.
634 ExtensionService* extensions_service = profile->GetExtensionService();
635 DCHECK(extensions_service);
636
637 ExtensionPrefs::LaunchType launch_type =
638 extensions_service->extension_prefs()->GetLaunchType(
639 extension->id(), ExtensionPrefs::LAUNCH_DEFAULT);
640 UMA_HISTOGRAM_ENUMERATION("Extensions.AppTabLaunchType", launch_type, 100);
641 int add_type = TabStripModel::ADD_ACTIVE;
642 if (launch_type == ExtensionPrefs::LAUNCH_PINNED)
643 add_type |= TabStripModel::ADD_PINNED;
644
645 // For extensions lacking launch urls, determine a reasonable fallback.
646 GURL extension_url = extension->GetFullLaunchURL();
647 if (!extension_url.is_valid()) {
648 extension_url = extension->options_url();
649 if (!extension_url.is_valid())
650 extension_url = GURL(chrome::kChromeUIExtensionsURL);
651 }
652
653 // TODO(erikkay): START_PAGE doesn't seem like the right transition in all
654 // cases.
655 browser::NavigateParams params(browser, extension_url,
656 PageTransition::START_PAGE);
657 params.tabstrip_add_types = add_type;
658
659 // Launch the application in the existing TabContents, if it was supplied.
660 if (existing_tab) {
661 TabStripModel* model = browser->tabstrip_model();
662 int tab_index = model->GetWrapperIndex(existing_tab);
663
664 existing_tab->OpenURL(extension->GetFullLaunchURL(), existing_tab->GetURL(),
665 CURRENT_TAB, PageTransition::LINK);
666 if (params.tabstrip_add_types & TabStripModel::ADD_PINNED) {
667 model->SetTabPinned(tab_index, true);
668 tab_index = model->GetWrapperIndex(existing_tab);
669 }
670 if (params.tabstrip_add_types & TabStripModel::ADD_ACTIVE)
671 model->ActivateTabAt(tab_index, true);
672
673 contents = existing_tab;
674 } else {
675 params.disposition = NEW_FOREGROUND_TAB;
676 browser::Navigate(¶ms);
677 contents = params.target_contents->tab_contents();
678 }
679
680 // TODO(skerner): If we are already in full screen mode, and the user
681 // set the app to open as a regular or pinned tab, what should happen?
682 // Today we open the tab, but stay in full screen mode. Should we leave
683 // full screen mode in this case?
684 if (launch_type == ExtensionPrefs::LAUNCH_FULLSCREEN &&
685 !browser->window()->IsFullscreen())
686 browser->ToggleFullscreenMode();
687
688 return contents;
689 }
690
691 // static
OpenBookmarkManagerWindow(Profile * profile)692 void Browser::OpenBookmarkManagerWindow(Profile* profile) {
693 Browser* browser = Browser::Create(profile);
694 browser->ShowBookmarkManagerTab();
695 browser->window()->Show();
696 }
697
698 #if defined(OS_MACOSX)
699 // static
OpenHistoryWindow(Profile * profile)700 void Browser::OpenHistoryWindow(Profile* profile) {
701 Browser* browser = Browser::Create(profile);
702 browser->ShowHistoryTab();
703 browser->window()->Show();
704 }
705
706 // static
OpenDownloadsWindow(Profile * profile)707 void Browser::OpenDownloadsWindow(Profile* profile) {
708 Browser* browser = Browser::Create(profile);
709 browser->ShowDownloadsTab();
710 browser->window()->Show();
711 }
712
713 // static
OpenHelpWindow(Profile * profile)714 void Browser::OpenHelpWindow(Profile* profile) {
715 Browser* browser = Browser::Create(profile);
716 browser->OpenHelpTab();
717 browser->window()->Show();
718 }
719
720 // static
OpenOptionsWindow(Profile * profile)721 void Browser::OpenOptionsWindow(Profile* profile) {
722 Browser* browser = Browser::Create(profile);
723 browser->OpenOptionsDialog();
724 browser->window()->Show();
725 }
726
727 // static
OpenClearBrowingDataDialogWindow(Profile * profile)728 void Browser::OpenClearBrowingDataDialogWindow(Profile* profile) {
729 Browser* browser = Browser::Create(profile);
730 browser->OpenClearBrowsingDataDialog();
731 browser->window()->Show();
732 }
733
734 // static
OpenImportSettingsDialogWindow(Profile * profile)735 void Browser::OpenImportSettingsDialogWindow(Profile* profile) {
736 Browser* browser = Browser::Create(profile);
737 browser->OpenImportSettingsDialog();
738 browser->window()->Show();
739 }
740
741 // static
OpenInstantConfirmDialogWindow(Profile * profile)742 void Browser::OpenInstantConfirmDialogWindow(Profile* profile) {
743 Browser* browser = Browser::Create(profile);
744 browser->OpenInstantConfirmDialog();
745 browser->window()->Show();
746 }
747 #endif
748
749 // static
OpenExtensionsWindow(Profile * profile)750 void Browser::OpenExtensionsWindow(Profile* profile) {
751 Browser* browser = Browser::Create(profile);
752 browser->ShowExtensionsTab();
753 browser->window()->Show();
754 }
755
756
757 ///////////////////////////////////////////////////////////////////////////////
758 // Browser, State Storage and Retrieval for UI:
759
GetWindowPlacementKey() const760 std::string Browser::GetWindowPlacementKey() const {
761 std::string name(prefs::kBrowserWindowPlacement);
762 if (!app_name_.empty()) {
763 name.append("_");
764 name.append(app_name_);
765 }
766 return name;
767 }
768
ShouldSaveWindowPlacement() const769 bool Browser::ShouldSaveWindowPlacement() const {
770 // Only save the window placement of popups if they are restored.
771 return (type() & TYPE_POPUP) == 0 || browser_defaults::kRestorePopups;
772 }
773
SaveWindowPlacement(const gfx::Rect & bounds,bool maximized)774 void Browser::SaveWindowPlacement(const gfx::Rect& bounds, bool maximized) {
775 // Save to the session storage service, used when reloading a past session.
776 // Note that we don't want to be the ones who cause lazy initialization of
777 // the session service. This function gets called during initial window
778 // showing, and we don't want to bring in the session service this early.
779 if (profile()->HasSessionService()) {
780 SessionService* session_service = profile()->GetSessionService();
781 if (session_service)
782 session_service->SetWindowBounds(session_id_, bounds, maximized);
783 }
784 }
785
GetSavedWindowBounds() const786 gfx::Rect Browser::GetSavedWindowBounds() const {
787 const CommandLine& parsed_command_line = *CommandLine::ForCurrentProcess();
788 bool record_mode = parsed_command_line.HasSwitch(switches::kRecordMode);
789 bool playback_mode = parsed_command_line.HasSwitch(switches::kPlaybackMode);
790 if (record_mode || playback_mode) {
791 // In playback/record mode we always fix the size of the browser and
792 // move it to (0,0). The reason for this is two reasons: First we want
793 // resize/moves in the playback to still work, and Second we want
794 // playbacks to work (as much as possible) on machines w/ different
795 // screen sizes.
796 return gfx::Rect(0, 0, 800, 600);
797 }
798
799 gfx::Rect restored_bounds = override_bounds_;
800 bool maximized;
801 WindowSizer::GetBrowserWindowBounds(app_name_, restored_bounds, this,
802 &restored_bounds, &maximized);
803 return restored_bounds;
804 }
805
806 // TODO(beng): obtain maximized state some other way so we don't need to go
807 // through all this hassle.
GetSavedMaximizedState() const808 bool Browser::GetSavedMaximizedState() const {
809 if (CommandLine::ForCurrentProcess()->HasSwitch(switches::kStartMaximized))
810 return true;
811
812 if (maximized_state_ == MAXIMIZED_STATE_MAXIMIZED)
813 return true;
814 if (maximized_state_ == MAXIMIZED_STATE_UNMAXIMIZED)
815 return false;
816
817 // An explicit maximized state was not set. Query the window sizer.
818 gfx::Rect restored_bounds;
819 bool maximized = false;
820 WindowSizer::GetBrowserWindowBounds(app_name_, restored_bounds, this,
821 &restored_bounds, &maximized);
822 return maximized;
823 }
824
GetCurrentPageIcon() const825 SkBitmap Browser::GetCurrentPageIcon() const {
826 TabContents* contents = GetSelectedTabContents();
827 // |contents| can be NULL since GetCurrentPageIcon() is called by the window
828 // during the window's creation (before tabs have been added).
829 return contents ? contents->GetFavicon() : SkBitmap();
830 }
831
GetWindowTitleForCurrentTab() const832 string16 Browser::GetWindowTitleForCurrentTab() const {
833 TabContents* contents = GetSelectedTabContents();
834 string16 title;
835
836 // |contents| can be NULL because GetWindowTitleForCurrentTab is called by the
837 // window during the window's creation (before tabs have been added).
838 if (contents) {
839 title = contents->GetTitle();
840 FormatTitleForDisplay(&title);
841 }
842 if (title.empty())
843 title = TabContentsWrapper::GetDefaultTitle();
844
845 #if defined(OS_MACOSX) || defined(OS_CHROMEOS)
846 // On Mac or ChromeOS, we don't want to suffix the page title with
847 // the application name.
848 return title;
849 #elif defined(OS_WIN) || defined(OS_LINUX)
850 int string_id = IDS_BROWSER_WINDOW_TITLE_FORMAT;
851 // Don't append the app name to window titles on app frames and app popups
852 if (type_ & TYPE_APP)
853 string_id = IDS_BROWSER_WINDOW_TITLE_FORMAT_NO_LOGO;
854 return l10n_util::GetStringFUTF16(string_id, title);
855 #endif
856 }
857
858 // static
FormatTitleForDisplay(string16 * title)859 void Browser::FormatTitleForDisplay(string16* title) {
860 size_t current_index = 0;
861 size_t match_index;
862 while ((match_index = title->find(L'\n', current_index)) != string16::npos) {
863 title->replace(match_index, 1, string16());
864 current_index = match_index;
865 }
866 }
867
868 ///////////////////////////////////////////////////////////////////////////////
869 // Browser, OnBeforeUnload handling:
870
TabsNeedBeforeUnloadFired()871 bool Browser::TabsNeedBeforeUnloadFired() {
872 if (tabs_needing_before_unload_fired_.empty()) {
873 for (int i = 0; i < tab_count(); ++i) {
874 TabContents* contents = GetTabContentsAt(i);
875 if (contents->NeedToFireBeforeUnload())
876 tabs_needing_before_unload_fired_.insert(contents);
877 }
878 }
879 return !tabs_needing_before_unload_fired_.empty();
880 }
881
ShouldCloseWindow()882 bool Browser::ShouldCloseWindow() {
883 if (!CanCloseWithInProgressDownloads())
884 return false;
885
886 if (HasCompletedUnloadProcessing())
887 return IsClosingPermitted();
888
889 is_attempting_to_close_browser_ = true;
890
891 if (!TabsNeedBeforeUnloadFired())
892 return IsClosingPermitted();
893
894 ProcessPendingTabs();
895 return false;
896 }
897
OnWindowClosing()898 void Browser::OnWindowClosing() {
899 if (!ShouldCloseWindow())
900 return;
901
902 bool exiting = false;
903
904 // Application should shutdown on last window close if the user is explicitly
905 // trying to quit, or if there is nothing keeping the browser alive (such as
906 // AppController on the Mac, or BackgroundContentsService for background
907 // pages).
908 bool should_quit_if_last_browser =
909 browser_shutdown::IsTryingToQuit() || !BrowserList::WillKeepAlive();
910
911 if (should_quit_if_last_browser && BrowserList::size() == 1) {
912 browser_shutdown::OnShutdownStarting(browser_shutdown::WINDOW_CLOSE);
913 exiting = true;
914 }
915
916 // Don't use HasSessionService here, we want to force creation of the
917 // session service so that user can restore what was open.
918 SessionService* session_service = profile()->GetSessionService();
919 if (session_service)
920 session_service->WindowClosing(session_id());
921
922 TabRestoreService* tab_restore_service = profile()->GetTabRestoreService();
923 if (tab_restore_service && type() == TYPE_NORMAL && tab_count())
924 tab_restore_service->BrowserClosing(tab_restore_service_delegate());
925
926 // TODO(sky): convert session/tab restore to use notification.
927 NotificationService::current()->Notify(
928 NotificationType::BROWSER_CLOSING,
929 Source<Browser>(this),
930 Details<bool>(&exiting));
931
932 CloseAllTabs();
933 }
934
935 ////////////////////////////////////////////////////////////////////////////////
936 // In-progress download termination handling:
937
InProgressDownloadResponse(bool cancel_downloads)938 void Browser::InProgressDownloadResponse(bool cancel_downloads) {
939 if (cancel_downloads) {
940 cancel_download_confirmation_state_ = RESPONSE_RECEIVED;
941 CloseWindow();
942 return;
943 }
944
945 // Sets the confirmation state to NOT_PROMPTED so that if the user tries to
946 // close again we'll show the warning again.
947 cancel_download_confirmation_state_ = NOT_PROMPTED;
948
949 // Show the download page so the user can figure-out what downloads are still
950 // in-progress.
951 ShowDownloadsTab();
952 }
953
954 ////////////////////////////////////////////////////////////////////////////////
955 // Browser, TabStripModel pass-thrus:
956
tab_count() const957 int Browser::tab_count() const {
958 return tab_handler_->GetTabStripModel()->count();
959 }
960
active_index() const961 int Browser::active_index() const {
962 return tab_handler_->GetTabStripModel()->active_index();
963 }
964
GetIndexOfController(const NavigationController * controller) const965 int Browser::GetIndexOfController(
966 const NavigationController* controller) const {
967 return tab_handler_->GetTabStripModel()->GetIndexOfController(controller);
968 }
969
GetSelectedTabContentsWrapper() const970 TabContentsWrapper* Browser::GetSelectedTabContentsWrapper() const {
971 return tabstrip_model()->GetSelectedTabContents();
972 }
GetTabContentsWrapperAt(int index) const973 TabContentsWrapper* Browser::GetTabContentsWrapperAt(int index) const {
974 return tabstrip_model()->GetTabContentsAt(index);
975 }
976
GetSelectedTabContents() const977 TabContents* Browser::GetSelectedTabContents() const {
978 TabContentsWrapper* wrapper = GetSelectedTabContentsWrapper();
979 if (wrapper)
980 return wrapper->tab_contents();
981 return NULL;
982 }
983
GetTabContentsAt(int index) const984 TabContents* Browser::GetTabContentsAt(int index) const {
985 TabContentsWrapper* wrapper = tabstrip_model()->GetTabContentsAt(index);
986 if (wrapper)
987 return wrapper->tab_contents();
988 return NULL;
989 }
990
ActivateTabAt(int index,bool user_gesture)991 void Browser::ActivateTabAt(int index, bool user_gesture) {
992 tab_handler_->GetTabStripModel()->ActivateTabAt(index, user_gesture);
993 }
994
IsTabPinned(int index) const995 bool Browser::IsTabPinned(int index) const {
996 return tabstrip_model()->IsTabPinned(index);
997 }
998
CloseAllTabs()999 void Browser::CloseAllTabs() {
1000 tab_handler_->GetTabStripModel()->CloseAllTabs();
1001 }
1002
1003 ////////////////////////////////////////////////////////////////////////////////
1004 // Browser, Tab adding/showing functions:
1005
IsTabStripEditable() const1006 bool Browser::IsTabStripEditable() const {
1007 return window()->IsTabStripEditable();
1008 }
1009
GetIndexForInsertionDuringRestore(int relative_index)1010 int Browser::GetIndexForInsertionDuringRestore(int relative_index) {
1011 return (tab_handler_->GetTabStripModel()->insertion_policy() ==
1012 TabStripModel::INSERT_AFTER) ? tab_count() : relative_index;
1013 }
1014
AddSelectedTabWithURL(const GURL & url,PageTransition::Type transition)1015 TabContentsWrapper* Browser::AddSelectedTabWithURL(const GURL& url,
1016 PageTransition::Type transition) {
1017 browser::NavigateParams params(this, url, transition);
1018 params.disposition = NEW_FOREGROUND_TAB;
1019 browser::Navigate(¶ms);
1020 return params.target_contents;
1021 }
1022
AddTab(TabContentsWrapper * tab_contents,PageTransition::Type type)1023 TabContents* Browser::AddTab(TabContentsWrapper* tab_contents,
1024 PageTransition::Type type) {
1025 tab_handler_->GetTabStripModel()->AddTabContents(
1026 tab_contents, -1, type, TabStripModel::ADD_ACTIVE);
1027 return tab_contents->tab_contents();
1028 }
1029
AddTabContents(TabContents * new_contents,WindowOpenDisposition disposition,const gfx::Rect & initial_pos,bool user_gesture)1030 void Browser::AddTabContents(TabContents* new_contents,
1031 WindowOpenDisposition disposition,
1032 const gfx::Rect& initial_pos,
1033 bool user_gesture) {
1034 AddNewContents(NULL, new_contents, disposition, initial_pos, user_gesture);
1035 }
1036
CloseTabContents(TabContents * contents)1037 void Browser::CloseTabContents(TabContents* contents) {
1038 CloseContents(contents);
1039 }
1040
BrowserShowHtmlDialog(HtmlDialogUIDelegate * delegate,gfx::NativeWindow parent_window)1041 void Browser::BrowserShowHtmlDialog(HtmlDialogUIDelegate* delegate,
1042 gfx::NativeWindow parent_window) {
1043 ShowHtmlDialog(delegate, parent_window);
1044 }
1045
BrowserRenderWidgetShowing()1046 void Browser::BrowserRenderWidgetShowing() {
1047 RenderWidgetShowing();
1048 }
1049
BookmarkBarSizeChanged(bool is_animating)1050 void Browser::BookmarkBarSizeChanged(bool is_animating) {
1051 window_->ToolbarSizeChanged(is_animating);
1052 }
1053
AddRestoredTab(const std::vector<TabNavigation> & navigations,int tab_index,int selected_navigation,const std::string & extension_app_id,bool select,bool pin,bool from_last_session,SessionStorageNamespace * session_storage_namespace)1054 TabContents* Browser::AddRestoredTab(
1055 const std::vector<TabNavigation>& navigations,
1056 int tab_index,
1057 int selected_navigation,
1058 const std::string& extension_app_id,
1059 bool select,
1060 bool pin,
1061 bool from_last_session,
1062 SessionStorageNamespace* session_storage_namespace) {
1063 TabContentsWrapper* wrapper = TabContentsFactory(profile(), NULL,
1064 MSG_ROUTING_NONE,
1065 GetSelectedTabContents(),
1066 session_storage_namespace);
1067 TabContents* new_tab = wrapper->tab_contents();
1068 wrapper->extension_tab_helper()->SetExtensionAppById(extension_app_id);
1069 new_tab->controller().RestoreFromState(navigations, selected_navigation,
1070 from_last_session);
1071
1072 int add_types = select ? TabStripModel::ADD_ACTIVE :
1073 TabStripModel::ADD_NONE;
1074 if (pin) {
1075 tab_index = std::min(tab_index, tabstrip_model()->IndexOfFirstNonMiniTab());
1076 add_types |= TabStripModel::ADD_PINNED;
1077 }
1078 tab_handler_->GetTabStripModel()->InsertTabContentsAt(tab_index, wrapper,
1079 add_types);
1080 if (select) {
1081 window_->Activate();
1082 } else {
1083 // We set the size of the view here, before WebKit does its initial
1084 // layout. If we don't, the initial layout of background tabs will be
1085 // performed with a view width of 0, which may cause script outputs and
1086 // anchor link location calculations to be incorrect even after a new
1087 // layout with proper view dimensions. TabStripModel::AddTabContents()
1088 // contains similar logic.
1089 new_tab->view()->SizeContents(window_->GetRestoredBounds().size());
1090 new_tab->HideContents();
1091 }
1092 if (profile_->HasSessionService()) {
1093 SessionService* session_service = profile_->GetSessionService();
1094 if (session_service)
1095 session_service->TabRestored(&new_tab->controller(), pin);
1096 }
1097 return new_tab;
1098 }
1099
ReplaceRestoredTab(const std::vector<TabNavigation> & navigations,int selected_navigation,bool from_last_session,const std::string & extension_app_id,SessionStorageNamespace * session_storage_namespace)1100 void Browser::ReplaceRestoredTab(
1101 const std::vector<TabNavigation>& navigations,
1102 int selected_navigation,
1103 bool from_last_session,
1104 const std::string& extension_app_id,
1105 SessionStorageNamespace* session_storage_namespace) {
1106 TabContentsWrapper* wrapper = TabContentsFactory(profile(), NULL,
1107 MSG_ROUTING_NONE,
1108 GetSelectedTabContents(),
1109 session_storage_namespace);
1110 wrapper->extension_tab_helper()->SetExtensionAppById(extension_app_id);
1111 TabContents* replacement = wrapper->tab_contents();
1112 replacement->controller().RestoreFromState(navigations, selected_navigation,
1113 from_last_session);
1114
1115 tab_handler_->GetTabStripModel()->ReplaceNavigationControllerAt(
1116 tab_handler_->GetTabStripModel()->active_index(),
1117 wrapper);
1118 }
1119
CanRestoreTab()1120 bool Browser::CanRestoreTab() {
1121 return command_updater_.IsCommandEnabled(IDC_RESTORE_TAB);
1122 }
1123
NavigateToIndexWithDisposition(int index,WindowOpenDisposition disp)1124 bool Browser::NavigateToIndexWithDisposition(int index,
1125 WindowOpenDisposition disp) {
1126 NavigationController& controller =
1127 GetOrCloneTabForDisposition(disp)->controller();
1128 if (index < 0 || index >= controller.entry_count())
1129 return false;
1130 controller.GoToIndex(index);
1131 return true;
1132 }
1133
GetSingletonTabNavigateParams(const GURL & url)1134 browser::NavigateParams Browser::GetSingletonTabNavigateParams(
1135 const GURL& url) {
1136 browser::NavigateParams params(this, url, PageTransition::AUTO_BOOKMARK);
1137 params.disposition = SINGLETON_TAB;
1138 params.window_action = browser::NavigateParams::SHOW_WINDOW;
1139 return params;
1140 }
1141
ShowSingletonTab(const GURL & url)1142 void Browser::ShowSingletonTab(const GURL& url) {
1143 browser::NavigateParams params(GetSingletonTabNavigateParams(url));
1144 browser::Navigate(¶ms);
1145 }
1146
UpdateCommandsForFullscreenMode(bool is_fullscreen)1147 void Browser::UpdateCommandsForFullscreenMode(bool is_fullscreen) {
1148 #if !defined(OS_MACOSX)
1149 const bool show_main_ui = (type() == TYPE_NORMAL) && !is_fullscreen;
1150 #else
1151 const bool show_main_ui = (type() == TYPE_NORMAL);
1152 #endif
1153
1154 bool main_not_fullscreen_or_popup =
1155 show_main_ui && !is_fullscreen && (type() & TYPE_POPUP) == 0;
1156
1157 // Navigation commands
1158 command_updater_.UpdateCommandEnabled(IDC_OPEN_CURRENT_URL, show_main_ui);
1159
1160 // Window management commands
1161 command_updater_.UpdateCommandEnabled(IDC_SHOW_AS_TAB,
1162 (type() & TYPE_POPUP) && !is_fullscreen);
1163
1164 // Focus various bits of UI
1165 command_updater_.UpdateCommandEnabled(IDC_FOCUS_TOOLBAR, show_main_ui);
1166 command_updater_.UpdateCommandEnabled(IDC_FOCUS_LOCATION, show_main_ui);
1167 command_updater_.UpdateCommandEnabled(IDC_FOCUS_SEARCH, show_main_ui);
1168 command_updater_.UpdateCommandEnabled(
1169 IDC_FOCUS_MENU_BAR, main_not_fullscreen_or_popup);
1170 command_updater_.UpdateCommandEnabled(
1171 IDC_FOCUS_NEXT_PANE, main_not_fullscreen_or_popup);
1172 command_updater_.UpdateCommandEnabled(
1173 IDC_FOCUS_PREVIOUS_PANE, main_not_fullscreen_or_popup);
1174 command_updater_.UpdateCommandEnabled(
1175 IDC_FOCUS_BOOKMARKS, main_not_fullscreen_or_popup);
1176 command_updater_.UpdateCommandEnabled(
1177 IDC_FOCUS_CHROMEOS_STATUS, main_not_fullscreen_or_popup);
1178
1179 // Show various bits of UI
1180 command_updater_.UpdateCommandEnabled(IDC_DEVELOPER_MENU, show_main_ui);
1181 command_updater_.UpdateCommandEnabled(IDC_FEEDBACK, show_main_ui);
1182 command_updater_.UpdateCommandEnabled(IDC_SHOW_BOOKMARK_BAR,
1183 browser_defaults::bookmarks_enabled && show_main_ui);
1184 command_updater_.UpdateCommandEnabled(IDC_IMPORT_SETTINGS, show_main_ui);
1185 command_updater_.UpdateCommandEnabled(IDC_SYNC_BOOKMARKS,
1186 show_main_ui && profile_->IsSyncAccessible());
1187
1188 command_updater_.UpdateCommandEnabled(IDC_OPTIONS, show_main_ui);
1189 command_updater_.UpdateCommandEnabled(IDC_EDIT_SEARCH_ENGINES, show_main_ui);
1190 command_updater_.UpdateCommandEnabled(IDC_VIEW_PASSWORDS, show_main_ui);
1191 command_updater_.UpdateCommandEnabled(IDC_ABOUT, show_main_ui);
1192 command_updater_.UpdateCommandEnabled(IDC_SHOW_APP_MENU, show_main_ui);
1193 command_updater_.UpdateCommandEnabled(IDC_TOGGLE_VERTICAL_TABS, show_main_ui);
1194 #if defined (ENABLE_PROFILING) && !defined(NO_TCMALLOC)
1195 command_updater_.UpdateCommandEnabled(IDC_PROFILING_ENABLED, show_main_ui);
1196 #endif
1197 }
1198
1199 ///////////////////////////////////////////////////////////////////////////////
1200 // Browser, Assorted browser commands:
1201
ShouldOpenNewTabForWindowDisposition(WindowOpenDisposition disposition)1202 bool Browser::ShouldOpenNewTabForWindowDisposition(
1203 WindowOpenDisposition disposition) {
1204 return (disposition == NEW_FOREGROUND_TAB ||
1205 disposition == NEW_BACKGROUND_TAB);
1206 }
1207
GetOrCloneTabForDisposition(WindowOpenDisposition disposition)1208 TabContents* Browser::GetOrCloneTabForDisposition(
1209 WindowOpenDisposition disposition) {
1210 TabContentsWrapper* current_tab = GetSelectedTabContentsWrapper();
1211 if (ShouldOpenNewTabForWindowDisposition(disposition)) {
1212 current_tab = current_tab->Clone();
1213 tab_handler_->GetTabStripModel()->AddTabContents(
1214 current_tab, -1, PageTransition::LINK,
1215 disposition == NEW_FOREGROUND_TAB ? TabStripModel::ADD_ACTIVE :
1216 TabStripModel::ADD_NONE);
1217 }
1218 return current_tab->tab_contents();
1219 }
1220
UpdateTabStripModelInsertionPolicy()1221 void Browser::UpdateTabStripModelInsertionPolicy() {
1222 tab_handler_->GetTabStripModel()->SetInsertionPolicy(UseVerticalTabs() ?
1223 TabStripModel::INSERT_BEFORE : TabStripModel::INSERT_AFTER);
1224 }
1225
UseVerticalTabsChanged()1226 void Browser::UseVerticalTabsChanged() {
1227 UpdateTabStripModelInsertionPolicy();
1228 window()->ToggleTabStripMode();
1229 }
1230
SupportsWindowFeatureImpl(WindowFeature feature,bool check_fullscreen) const1231 bool Browser::SupportsWindowFeatureImpl(WindowFeature feature,
1232 bool check_fullscreen) const {
1233 // On Mac, fullscreen mode has most normal things (in a slide-down panel). On
1234 // other platforms, we hide some controls when in fullscreen mode.
1235 bool hide_ui_for_fullscreen = false;
1236 #if !defined(OS_MACOSX)
1237 hide_ui_for_fullscreen = check_fullscreen && window_ &&
1238 window_->IsFullscreen();
1239 #endif
1240
1241 unsigned int features = FEATURE_INFOBAR | FEATURE_SIDEBAR;
1242
1243 #if !defined(OS_CHROMEOS)
1244 // Chrome OS opens a FileBrowse pop up instead of using download shelf.
1245 // So FEATURE_DOWNLOADSHELF is only added for non-chromeos platforms.
1246 features |= FEATURE_DOWNLOADSHELF;
1247 #endif // !defined(OS_CHROMEOS)
1248
1249 if (type() == TYPE_NORMAL) {
1250 features |= FEATURE_BOOKMARKBAR;
1251 }
1252
1253 if (!hide_ui_for_fullscreen) {
1254 if (type() != TYPE_NORMAL)
1255 features |= FEATURE_TITLEBAR;
1256
1257 if (type() == TYPE_NORMAL)
1258 features |= FEATURE_TABSTRIP;
1259
1260 if (type() == TYPE_NORMAL)
1261 features |= FEATURE_TOOLBAR;
1262
1263 if ((type() & Browser::TYPE_APP) == 0)
1264 features |= FEATURE_LOCATIONBAR;
1265 }
1266 return !!(features & feature);
1267 }
1268
IsClosingPermitted()1269 bool Browser::IsClosingPermitted() {
1270 TabCloseableStateWatcher* watcher =
1271 g_browser_process->tab_closeable_state_watcher();
1272 bool can_close = !watcher || watcher->CanCloseBrowser(this);
1273 if (!can_close && is_attempting_to_close_browser_)
1274 CancelWindowClose();
1275 return can_close;
1276 }
1277
GoBack(WindowOpenDisposition disposition)1278 void Browser::GoBack(WindowOpenDisposition disposition) {
1279 UserMetrics::RecordAction(UserMetricsAction("Back"), profile_);
1280
1281 TabContentsWrapper* current_tab = GetSelectedTabContentsWrapper();
1282 if (current_tab->controller().CanGoBack()) {
1283 TabContents* new_tab = GetOrCloneTabForDisposition(disposition);
1284 // If we are on an interstitial page and clone the tab, it won't be copied
1285 // to the new tab, so we don't need to go back.
1286 if (current_tab->tab_contents()->showing_interstitial_page() &&
1287 (new_tab != current_tab->tab_contents()))
1288 return;
1289 new_tab->controller().GoBack();
1290 }
1291 }
1292
GoForward(WindowOpenDisposition disposition)1293 void Browser::GoForward(WindowOpenDisposition disposition) {
1294 UserMetrics::RecordAction(UserMetricsAction("Forward"), profile_);
1295 if (GetSelectedTabContentsWrapper()->controller().CanGoForward())
1296 GetOrCloneTabForDisposition(disposition)->controller().GoForward();
1297 }
1298
Reload(WindowOpenDisposition disposition)1299 void Browser::Reload(WindowOpenDisposition disposition) {
1300 UserMetrics::RecordAction(UserMetricsAction("Reload"), profile_);
1301 ReloadInternal(disposition, false);
1302 }
1303
ReloadIgnoringCache(WindowOpenDisposition disposition)1304 void Browser::ReloadIgnoringCache(WindowOpenDisposition disposition) {
1305 UserMetrics::RecordAction(UserMetricsAction("ReloadIgnoringCache"), profile_);
1306 ReloadInternal(disposition, true);
1307 }
1308
ReloadInternal(WindowOpenDisposition disposition,bool ignore_cache)1309 void Browser::ReloadInternal(WindowOpenDisposition disposition,
1310 bool ignore_cache) {
1311 // If we are showing an interstitial, treat this as an OpenURL.
1312 TabContents* current_tab = GetSelectedTabContents();
1313 if (current_tab && current_tab->showing_interstitial_page()) {
1314 NavigationEntry* entry = current_tab->controller().GetActiveEntry();
1315 DCHECK(entry); // Should exist if interstitial is showing.
1316 OpenURL(entry->url(), GURL(), disposition, PageTransition::RELOAD);
1317 return;
1318 }
1319
1320 // As this is caused by a user action, give the focus to the page.
1321 TabContents* tab = GetOrCloneTabForDisposition(disposition);
1322 if (!tab->FocusLocationBarByDefault())
1323 tab->Focus();
1324 if (ignore_cache)
1325 tab->controller().ReloadIgnoringCache(true);
1326 else
1327 tab->controller().Reload(true);
1328 }
1329
Home(WindowOpenDisposition disposition)1330 void Browser::Home(WindowOpenDisposition disposition) {
1331 UserMetrics::RecordAction(UserMetricsAction("Home"), profile_);
1332 OpenURL(GetHomePage(), GURL(), disposition, PageTransition::AUTO_BOOKMARK);
1333 }
1334
OpenCurrentURL()1335 void Browser::OpenCurrentURL() {
1336 UserMetrics::RecordAction(UserMetricsAction("LoadURL"), profile_);
1337 LocationBar* location_bar = window_->GetLocationBar();
1338 if (!location_bar)
1339 return;
1340
1341 WindowOpenDisposition open_disposition =
1342 location_bar->GetWindowOpenDisposition();
1343 if (OpenInstant(open_disposition))
1344 return;
1345
1346 GURL url(WideToUTF8(location_bar->GetInputString()));
1347
1348 if (open_disposition == CURRENT_TAB && TabFinder::IsEnabled()) {
1349 Browser* existing_browser = NULL;
1350 TabContents* existing_tab = TabFinder::GetInstance()->FindTab(
1351 this, url, &existing_browser);
1352 if (existing_tab) {
1353 existing_browser->ActivateContents(existing_tab);
1354 return;
1355 }
1356 }
1357
1358 browser::NavigateParams params(this, url, location_bar->GetPageTransition());
1359 params.disposition = open_disposition;
1360 // Use ADD_INHERIT_OPENER so that all pages opened by the omnibox at least
1361 // inherit the opener. In some cases the tabstrip will determine the group
1362 // should be inherited, in which case the group is inherited instead of the
1363 // opener.
1364 params.tabstrip_add_types =
1365 TabStripModel::ADD_FORCE_INDEX | TabStripModel::ADD_INHERIT_OPENER;
1366 browser::Navigate(¶ms);
1367
1368 DCHECK(profile_->GetExtensionService());
1369 if (profile_->GetExtensionService()->IsInstalledApp(url)) {
1370 UMA_HISTOGRAM_ENUMERATION(extension_misc::kAppLaunchHistogram,
1371 extension_misc::APP_LAUNCH_OMNIBOX_LOCATION,
1372 extension_misc::APP_LAUNCH_BUCKET_BOUNDARY);
1373 }
1374 }
1375
Stop()1376 void Browser::Stop() {
1377 UserMetrics::RecordAction(UserMetricsAction("Stop"), profile_);
1378 GetSelectedTabContentsWrapper()->tab_contents()->Stop();
1379 }
1380
NewWindow()1381 void Browser::NewWindow() {
1382 if (browser_defaults::kAlwaysOpenIncognitoWindow &&
1383 CommandLine::ForCurrentProcess()->HasSwitch(switches::kIncognito) &&
1384 incognito_mode_allowed_.GetValue()) {
1385 NewIncognitoWindow();
1386 return;
1387 }
1388 UserMetrics::RecordAction(UserMetricsAction("NewWindow"), profile_);
1389 SessionService* session_service =
1390 profile_->GetOriginalProfile()->GetSessionService();
1391 if (!session_service ||
1392 !session_service->RestoreIfNecessary(std::vector<GURL>())) {
1393 Browser::OpenEmptyWindow(profile_->GetOriginalProfile());
1394 }
1395 }
1396
NewIncognitoWindow()1397 void Browser::NewIncognitoWindow() {
1398 if (!incognito_mode_allowed_.GetValue()) {
1399 NewWindow();
1400 return;
1401 }
1402
1403 UserMetrics::RecordAction(UserMetricsAction("NewIncognitoWindow"), profile_);
1404 Browser::OpenEmptyWindow(profile_->GetOffTheRecordProfile());
1405 }
1406
CloseWindow()1407 void Browser::CloseWindow() {
1408 UserMetrics::RecordAction(UserMetricsAction("CloseWindow"), profile_);
1409 window_->Close();
1410 }
1411
NewTab()1412 void Browser::NewTab() {
1413 UserMetrics::RecordAction(UserMetricsAction("NewTab"), profile_);
1414
1415 if (type() == TYPE_NORMAL) {
1416 AddBlankTab(true);
1417 GetSelectedTabContentsWrapper()->view()->RestoreFocus();
1418 } else {
1419 Browser* b = GetOrCreateTabbedBrowser(profile_);
1420 b->AddBlankTab(true);
1421 b->window()->Show();
1422 // The call to AddBlankTab above did not set the focus to the tab as its
1423 // window was not active, so we have to do it explicitly.
1424 // See http://crbug.com/6380.
1425 b->GetSelectedTabContentsWrapper()->view()->RestoreFocus();
1426 }
1427 }
1428
CloseTab()1429 void Browser::CloseTab() {
1430 UserMetrics::RecordAction(UserMetricsAction("CloseTab_Accelerator"),
1431 profile_);
1432 if (CanCloseTab())
1433 tab_handler_->GetTabStripModel()->CloseSelectedTabs();
1434 }
1435
SelectNextTab()1436 void Browser::SelectNextTab() {
1437 UserMetrics::RecordAction(UserMetricsAction("SelectNextTab"), profile_);
1438 tab_handler_->GetTabStripModel()->SelectNextTab();
1439 }
1440
SelectPreviousTab()1441 void Browser::SelectPreviousTab() {
1442 UserMetrics::RecordAction(UserMetricsAction("SelectPrevTab"), profile_);
1443 tab_handler_->GetTabStripModel()->SelectPreviousTab();
1444 }
1445
OpenTabpose()1446 void Browser::OpenTabpose() {
1447 #if defined(OS_MACOSX)
1448 if (!CommandLine::ForCurrentProcess()->HasSwitch(
1449 switches::kEnableExposeForTabs)) {
1450 return;
1451 }
1452
1453 UserMetrics::RecordAction(UserMetricsAction("OpenTabpose"), profile_);
1454 window()->OpenTabpose();
1455 #else
1456 NOTREACHED();
1457 #endif
1458 }
1459
MoveTabNext()1460 void Browser::MoveTabNext() {
1461 UserMetrics::RecordAction(UserMetricsAction("MoveTabNext"), profile_);
1462 tab_handler_->GetTabStripModel()->MoveTabNext();
1463 }
1464
MoveTabPrevious()1465 void Browser::MoveTabPrevious() {
1466 UserMetrics::RecordAction(UserMetricsAction("MoveTabPrevious"), profile_);
1467 tab_handler_->GetTabStripModel()->MoveTabPrevious();
1468 }
1469
SelectNumberedTab(int index)1470 void Browser::SelectNumberedTab(int index) {
1471 if (index < tab_count()) {
1472 UserMetrics::RecordAction(UserMetricsAction("SelectNumberedTab"),
1473 profile_);
1474 tab_handler_->GetTabStripModel()->ActivateTabAt(index, true);
1475 }
1476 }
1477
SelectLastTab()1478 void Browser::SelectLastTab() {
1479 UserMetrics::RecordAction(UserMetricsAction("SelectLastTab"), profile_);
1480 tab_handler_->GetTabStripModel()->SelectLastTab();
1481 }
1482
DuplicateTab()1483 void Browser::DuplicateTab() {
1484 UserMetrics::RecordAction(UserMetricsAction("Duplicate"), profile_);
1485 DuplicateContentsAt(active_index());
1486 }
1487
RestoreTab()1488 void Browser::RestoreTab() {
1489 UserMetrics::RecordAction(UserMetricsAction("RestoreTab"), profile_);
1490 TabRestoreService* service = profile_->GetTabRestoreService();
1491 if (!service)
1492 return;
1493
1494 service->RestoreMostRecentEntry(tab_restore_service_delegate());
1495 }
1496
WriteCurrentURLToClipboard()1497 void Browser::WriteCurrentURLToClipboard() {
1498 // TODO(ericu): There isn't currently a metric for this. Should there be?
1499 // We don't appear to track the action when it comes from the
1500 // RenderContextViewMenu.
1501
1502 TabContents* contents = GetSelectedTabContents();
1503 if (!contents->ShouldDisplayURL())
1504 return;
1505
1506 chrome_browser_net::WriteURLToClipboard(
1507 contents->GetURL(),
1508 profile_->GetPrefs()->GetString(prefs::kAcceptLanguages),
1509 g_browser_process->clipboard());
1510 }
1511
ConvertPopupToTabbedBrowser()1512 void Browser::ConvertPopupToTabbedBrowser() {
1513 UserMetrics::RecordAction(UserMetricsAction("ShowAsTab"), profile_);
1514 int tab_strip_index = tab_handler_->GetTabStripModel()->active_index();
1515 TabContentsWrapper* contents =
1516 tab_handler_->GetTabStripModel()->DetachTabContentsAt(tab_strip_index);
1517 Browser* browser = Browser::Create(profile_);
1518 browser->tabstrip_model()->AppendTabContents(contents, true);
1519 browser->window()->Show();
1520 }
1521
ToggleFullscreenMode()1522 void Browser::ToggleFullscreenMode() {
1523 #if !defined(OS_MACOSX)
1524 // In kiosk mode, we always want to be fullscreen. When the browser first
1525 // starts we're not yet fullscreen, so let the initial toggle go through.
1526 if (CommandLine::ForCurrentProcess()->HasSwitch(switches::kKioskMode) &&
1527 window_->IsFullscreen())
1528 return;
1529 #endif
1530
1531 UserMetrics::RecordAction(UserMetricsAction("ToggleFullscreen"), profile_);
1532 window_->SetFullscreen(!window_->IsFullscreen());
1533 // On Linux, setting fullscreen mode is an async call to the X server, which
1534 // may or may not support fullscreen mode.
1535 #if !defined(OS_LINUX)
1536 UpdateCommandsForFullscreenMode(window_->IsFullscreen());
1537 #endif
1538 }
1539
1540 #if defined(OS_CHROMEOS)
Search()1541 void Browser::Search() {
1542 // If the NTP is showing, close it.
1543 if (StartsWithASCII(GetSelectedTabContents()->GetURL().spec(),
1544 chrome::kChromeUINewTabURL, true)) {
1545 CloseTab();
1546 return;
1547 }
1548
1549 // Exit fullscreen to show omnibox.
1550 if (window_->IsFullscreen()) {
1551 ToggleFullscreenMode();
1552 // ToggleFullscreenMode is asynchronous, so we don't have omnibox
1553 // visible at this point. Wait for next event cycle which toggles
1554 // the visibility of omnibox before creating new tab.
1555 MessageLoop::current()->PostTask(
1556 FROM_HERE, method_factory_.NewRunnableMethod(&Browser::Search));
1557 return;
1558 }
1559
1560 // Otherwise just open it.
1561 NewTab();
1562 }
1563
ShowKeyboardOverlay()1564 void Browser::ShowKeyboardOverlay() {
1565 window_->ShowKeyboardOverlay(window_->GetNativeHandle());
1566 }
1567 #endif
1568
Exit()1569 void Browser::Exit() {
1570 UserMetrics::RecordAction(UserMetricsAction("Exit"), profile_);
1571 #if defined(OS_CHROMEOS)
1572 chromeos::BootTimesLoader::Get()->AddLogoutTimeMarker("LogoutStarted", false);
1573 // Write /tmp/uptime-logout-started as well.
1574 const char kLogoutStarted[] = "logout-started";
1575 chromeos::BootTimesLoader::Get()->RecordCurrentStats(kLogoutStarted);
1576
1577 // Login screen should show up in owner's locale.
1578 PrefService* state = g_browser_process->local_state();
1579 if (state) {
1580 std::string owner_locale = state->GetString(prefs::kOwnerLocale);
1581 if (!owner_locale.empty() &&
1582 state->GetString(prefs::kApplicationLocale) != owner_locale &&
1583 !state->IsManagedPreference(prefs::kApplicationLocale)) {
1584 state->SetString(prefs::kApplicationLocale, owner_locale);
1585 state->ScheduleSavePersistentPrefs();
1586 }
1587 }
1588 #endif
1589 BrowserList::Exit();
1590 }
1591
BookmarkCurrentPage()1592 void Browser::BookmarkCurrentPage() {
1593 UserMetrics::RecordAction(UserMetricsAction("Star"), profile_);
1594
1595 BookmarkModel* model = profile()->GetBookmarkModel();
1596 if (!model || !model->IsLoaded())
1597 return; // Ignore requests until bookmarks are loaded.
1598
1599 GURL url;
1600 string16 title;
1601 TabContents* tab = GetSelectedTabContents();
1602 bookmark_utils::GetURLAndTitleToBookmark(tab, &url, &title);
1603 bool was_bookmarked = model->IsBookmarked(url);
1604 if (!was_bookmarked && profile_->IsOffTheRecord()) {
1605 // If we're incognito the favicon may not have been saved. Save it now
1606 // so that bookmarks have an icon for the page.
1607 tab->SaveFavicon();
1608 }
1609 model->SetURLStarred(url, title, true);
1610 // Make sure the model actually added a bookmark before showing the star. A
1611 // bookmark isn't created if the url is invalid.
1612 if (window_->IsActive() && model->IsBookmarked(url)) {
1613 // Only show the bubble if the window is active, otherwise we may get into
1614 // weird situations were the bubble is deleted as soon as it is shown.
1615 window_->ShowBookmarkBubble(url, was_bookmarked);
1616 }
1617 }
1618
SavePage()1619 void Browser::SavePage() {
1620 UserMetrics::RecordAction(UserMetricsAction("SavePage"), profile_);
1621 TabContents* current_tab = GetSelectedTabContents();
1622 if (current_tab && current_tab->contents_mime_type() == "application/pdf")
1623 UserMetrics::RecordAction(UserMetricsAction("PDF.SavePage"), profile_);
1624 GetSelectedTabContentsWrapper()->download_tab_helper()->OnSavePage();
1625 }
1626
ViewSelectedSource()1627 void Browser::ViewSelectedSource() {
1628 ViewSource(GetSelectedTabContentsWrapper());
1629 }
1630
ShowFindBar()1631 void Browser::ShowFindBar() {
1632 GetFindBarController()->Show();
1633 }
1634
SupportsWindowFeature(WindowFeature feature) const1635 bool Browser::SupportsWindowFeature(WindowFeature feature) const {
1636 return SupportsWindowFeatureImpl(feature, true);
1637 }
1638
CanSupportWindowFeature(WindowFeature feature) const1639 bool Browser::CanSupportWindowFeature(WindowFeature feature) const {
1640 return SupportsWindowFeatureImpl(feature, false);
1641 }
1642
EmailPageLocation()1643 void Browser::EmailPageLocation() {
1644 UserMetrics::RecordAction(UserMetricsAction("EmailPageLocation"), profile_);
1645 GetSelectedTabContents()->EmailPageLocation();
1646 }
1647
Print()1648 void Browser::Print() {
1649 UserMetrics::RecordAction(UserMetricsAction("PrintPreview"), profile_);
1650 if (CommandLine::ForCurrentProcess()->HasSwitch(
1651 switches::kEnablePrintPreview)) {
1652 printing::PrintPreviewTabController::PrintPreview(
1653 GetSelectedTabContents());
1654 } else {
1655 GetSelectedTabContentsWrapper()->print_view_manager()->PrintNow();
1656 }
1657 }
1658
ToggleEncodingAutoDetect()1659 void Browser::ToggleEncodingAutoDetect() {
1660 UserMetrics::RecordAction(UserMetricsAction("AutoDetectChange"), profile_);
1661 encoding_auto_detect_.SetValue(!encoding_auto_detect_.GetValue());
1662 // If "auto detect" is turned on, then any current override encoding
1663 // is cleared. This also implicitly performs a reload.
1664 // OTOH, if "auto detect" is turned off, we don't change the currently
1665 // active encoding.
1666 if (encoding_auto_detect_.GetValue()) {
1667 TabContents* contents = GetSelectedTabContents();
1668 if (contents)
1669 contents->ResetOverrideEncoding();
1670 }
1671 }
1672
OverrideEncoding(int encoding_id)1673 void Browser::OverrideEncoding(int encoding_id) {
1674 UserMetrics::RecordAction(UserMetricsAction("OverrideEncoding"), profile_);
1675 const std::string selected_encoding =
1676 CharacterEncoding::GetCanonicalEncodingNameByCommandId(encoding_id);
1677 TabContents* contents = GetSelectedTabContents();
1678 if (!selected_encoding.empty() && contents)
1679 contents->SetOverrideEncoding(selected_encoding);
1680 // Update the list of recently selected encodings.
1681 std::string new_selected_encoding_list;
1682 if (CharacterEncoding::UpdateRecentlySelectedEncoding(
1683 profile_->GetPrefs()->GetString(prefs::kRecentlySelectedEncoding),
1684 encoding_id,
1685 &new_selected_encoding_list)) {
1686 profile_->GetPrefs()->SetString(prefs::kRecentlySelectedEncoding,
1687 new_selected_encoding_list);
1688 }
1689 }
1690
Cut()1691 void Browser::Cut() {
1692 UserMetrics::RecordAction(UserMetricsAction("Cut"), profile_);
1693 window()->Cut();
1694 }
1695
Copy()1696 void Browser::Copy() {
1697 UserMetrics::RecordAction(UserMetricsAction("Copy"), profile_);
1698 window()->Copy();
1699 }
1700
Paste()1701 void Browser::Paste() {
1702 UserMetrics::RecordAction(UserMetricsAction("Paste"), profile_);
1703 window()->Paste();
1704 }
1705
Find()1706 void Browser::Find() {
1707 UserMetrics::RecordAction(UserMetricsAction("Find"), profile_);
1708 FindInPage(false, false);
1709 }
1710
FindNext()1711 void Browser::FindNext() {
1712 UserMetrics::RecordAction(UserMetricsAction("FindNext"), profile_);
1713 FindInPage(true, true);
1714 }
1715
FindPrevious()1716 void Browser::FindPrevious() {
1717 UserMetrics::RecordAction(UserMetricsAction("FindPrevious"), profile_);
1718 FindInPage(true, false);
1719 }
1720
Zoom(PageZoom::Function zoom_function)1721 void Browser::Zoom(PageZoom::Function zoom_function) {
1722 static const UserMetricsAction kActions[] = {
1723 UserMetricsAction("ZoomMinus"),
1724 UserMetricsAction("ZoomNormal"),
1725 UserMetricsAction("ZoomPlus")
1726 };
1727
1728 UserMetrics::RecordAction(kActions[zoom_function - PageZoom::ZOOM_OUT],
1729 profile_);
1730 TabContentsWrapper* tab_contents = GetSelectedTabContentsWrapper();
1731 tab_contents->render_view_host()->Zoom(zoom_function);
1732 }
1733
FocusToolbar()1734 void Browser::FocusToolbar() {
1735 UserMetrics::RecordAction(UserMetricsAction("FocusToolbar"), profile_);
1736 window_->FocusToolbar();
1737 }
1738
FocusAppMenu()1739 void Browser::FocusAppMenu() {
1740 UserMetrics::RecordAction(UserMetricsAction("FocusAppMenu"), profile_);
1741 window_->FocusAppMenu();
1742 }
1743
FocusLocationBar()1744 void Browser::FocusLocationBar() {
1745 UserMetrics::RecordAction(UserMetricsAction("FocusLocation"), profile_);
1746 window_->SetFocusToLocationBar(true);
1747 }
1748
FocusBookmarksToolbar()1749 void Browser::FocusBookmarksToolbar() {
1750 UserMetrics::RecordAction(UserMetricsAction("FocusBookmarksToolbar"),
1751 profile_);
1752 window_->FocusBookmarksToolbar();
1753 }
1754
FocusChromeOSStatus()1755 void Browser::FocusChromeOSStatus() {
1756 UserMetrics::RecordAction(UserMetricsAction("FocusChromeOSStatus"), profile_);
1757 window_->FocusChromeOSStatus();
1758 }
1759
FocusNextPane()1760 void Browser::FocusNextPane() {
1761 UserMetrics::RecordAction(UserMetricsAction("FocusNextPane"), profile_);
1762 window_->RotatePaneFocus(true);
1763 }
1764
FocusPreviousPane()1765 void Browser::FocusPreviousPane() {
1766 UserMetrics::RecordAction(UserMetricsAction("FocusPreviousPane"), profile_);
1767 window_->RotatePaneFocus(false);
1768 }
1769
FocusSearch()1770 void Browser::FocusSearch() {
1771 // TODO(beng): replace this with FocusLocationBar
1772 UserMetrics::RecordAction(UserMetricsAction("FocusSearch"), profile_);
1773 window_->GetLocationBar()->FocusSearch();
1774 }
1775
OpenFile()1776 void Browser::OpenFile() {
1777 UserMetrics::RecordAction(UserMetricsAction("OpenFile"), profile_);
1778 #if defined(OS_CHROMEOS) && !defined(FILE_MANAGER_EXTENSION)
1779 FileBrowseUI::OpenPopup(profile_,
1780 "",
1781 FileBrowseUI::kPopupWidth,
1782 FileBrowseUI::kPopupHeight);
1783 #else
1784 if (!select_file_dialog_.get())
1785 select_file_dialog_ = SelectFileDialog::Create(this);
1786
1787 const FilePath directory = profile_->last_selected_directory();
1788
1789 // TODO(beng): figure out how to juggle this.
1790 gfx::NativeWindow parent_window = window_->GetNativeHandle();
1791 select_file_dialog_->SelectFile(SelectFileDialog::SELECT_OPEN_FILE,
1792 string16(), directory,
1793 NULL, 0, FILE_PATH_LITERAL(""),
1794 GetSelectedTabContents(),
1795 parent_window, NULL);
1796 #endif
1797 }
1798
OpenCreateShortcutsDialog()1799 void Browser::OpenCreateShortcutsDialog() {
1800 UserMetrics::RecordAction(UserMetricsAction("CreateShortcut"), profile_);
1801 #if defined(OS_WIN) || defined(OS_LINUX)
1802 TabContentsWrapper* current_tab = GetSelectedTabContentsWrapper();
1803 DCHECK(current_tab &&
1804 web_app::IsValidUrl(current_tab->tab_contents()->GetURL())) <<
1805 "Menu item should be disabled.";
1806
1807 NavigationEntry* entry = current_tab->controller().GetLastCommittedEntry();
1808 if (!entry)
1809 return;
1810
1811 // RVH's GetApplicationInfo should not be called before it returns.
1812 DCHECK(pending_web_app_action_ == NONE);
1813 pending_web_app_action_ = CREATE_SHORTCUT;
1814
1815 // Start fetching web app info for CreateApplicationShortcut dialog and show
1816 // the dialog when the data is available in OnDidGetApplicationInfo.
1817 current_tab->extension_tab_helper()->GetApplicationInfo(entry->page_id());
1818 #else
1819 NOTIMPLEMENTED();
1820 #endif
1821 }
1822
ToggleDevToolsWindow(DevToolsToggleAction action)1823 void Browser::ToggleDevToolsWindow(DevToolsToggleAction action) {
1824 std::string uma_string;
1825 switch (action) {
1826 case DEVTOOLS_TOGGLE_ACTION_SHOW_CONSOLE:
1827 uma_string = "DevTools_ToggleConsole";
1828 break;
1829 case DEVTOOLS_TOGGLE_ACTION_NONE:
1830 case DEVTOOLS_TOGGLE_ACTION_INSPECT:
1831 default:
1832 uma_string = "DevTools_ToggleWindow";
1833 break;
1834 }
1835 UserMetrics::RecordAction(UserMetricsAction(uma_string.c_str()), profile_);
1836 DevToolsManager::GetInstance()->ToggleDevToolsWindow(
1837 GetSelectedTabContentsWrapper()->render_view_host(), action);
1838 }
1839
OpenTaskManager(bool highlight_background_resources)1840 void Browser::OpenTaskManager(bool highlight_background_resources) {
1841 UserMetrics::RecordAction(UserMetricsAction("TaskManager"), profile_);
1842 if (highlight_background_resources)
1843 window_->ShowBackgroundPages();
1844 else
1845 window_->ShowTaskManager();
1846 }
1847
OpenBugReportDialog()1848 void Browser::OpenBugReportDialog() {
1849 UserMetrics::RecordAction(UserMetricsAction("ReportBug"), profile_);
1850 browser::ShowHtmlBugReportView(this);
1851 }
1852
ToggleBookmarkBar()1853 void Browser::ToggleBookmarkBar() {
1854 UserMetrics::RecordAction(UserMetricsAction("ShowBookmarksBar"), profile_);
1855 window_->ToggleBookmarkBar();
1856 }
1857
OpenBookmarkManager()1858 void Browser::OpenBookmarkManager() {
1859 UserMetrics::RecordAction(UserMetricsAction("ShowBookmarkManager"), profile_);
1860 ShowBookmarkManagerTab();
1861 }
1862
ShowAppMenu()1863 void Browser::ShowAppMenu() {
1864 // We record the user metric for this event in WrenchMenu::RunMenu.
1865 window_->ShowAppMenu();
1866 }
1867
ShowBookmarkManagerTab()1868 void Browser::ShowBookmarkManagerTab() {
1869 UserMetrics::RecordAction(UserMetricsAction("ShowBookmarks"), profile_);
1870 ShowSingletonTab(GURL(chrome::kChromeUIBookmarksURL));
1871 }
1872
ShowHistoryTab()1873 void Browser::ShowHistoryTab() {
1874 UserMetrics::RecordAction(UserMetricsAction("ShowHistory"), profile_);
1875 ShowSingletonTab(GURL(chrome::kChromeUIHistoryURL));
1876 }
1877
ShowDownloadsTab()1878 void Browser::ShowDownloadsTab() {
1879 UserMetrics::RecordAction(UserMetricsAction("ShowDownloads"), profile_);
1880 if (window()) {
1881 DownloadShelf* shelf = window()->GetDownloadShelf();
1882 if (shelf->IsShowing())
1883 shelf->Close();
1884 }
1885 ShowSingletonTab(GURL(chrome::kChromeUIDownloadsURL));
1886 }
1887
ShowExtensionsTab()1888 void Browser::ShowExtensionsTab() {
1889 UserMetrics::RecordAction(UserMetricsAction("ShowExtensions"), profile_);
1890 ShowSingletonTab(GURL(chrome::kChromeUIExtensionsURL));
1891 }
1892
ShowAboutConflictsTab()1893 void Browser::ShowAboutConflictsTab() {
1894 UserMetrics::RecordAction(UserMetricsAction("AboutConflicts"), profile_);
1895 ShowSingletonTab(GURL(chrome::kChromeUIConflictsURL));
1896 }
1897
ShowBrokenPageTab(TabContents * contents)1898 void Browser::ShowBrokenPageTab(TabContents* contents) {
1899 UserMetrics::RecordAction(UserMetricsAction("ReportBug"), profile_);
1900 string16 page_title = contents->GetTitle();
1901 NavigationEntry* entry = contents->controller().GetActiveEntry();
1902 if (!entry)
1903 return;
1904 std::string page_url = entry->url().spec();
1905 std::vector<std::string> subst;
1906 subst.push_back(UTF16ToASCII(page_title));
1907 subst.push_back(page_url);
1908 std::string report_page_url =
1909 ReplaceStringPlaceholders(kBrokenPageUrl, subst, NULL);
1910 ShowSingletonTab(GURL(report_page_url));
1911 }
1912
ShowOptionsTab(const std::string & sub_page)1913 void Browser::ShowOptionsTab(const std::string& sub_page) {
1914 GURL url(chrome::kChromeUISettingsURL + sub_page);
1915 browser::NavigateParams params(GetSingletonTabNavigateParams(url));
1916 params.path_behavior = browser::NavigateParams::IGNORE_AND_NAVIGATE;
1917 browser::Navigate(¶ms);
1918 }
1919
OpenClearBrowsingDataDialog()1920 void Browser::OpenClearBrowsingDataDialog() {
1921 UserMetrics::RecordAction(UserMetricsAction("ClearBrowsingData_ShowDlg"),
1922 profile_);
1923 ShowOptionsTab(chrome::kClearBrowserDataSubPage);
1924 }
1925
OpenOptionsDialog()1926 void Browser::OpenOptionsDialog() {
1927 UserMetrics::RecordAction(UserMetricsAction("ShowOptions"), profile_);
1928 GURL url(chrome::kChromeUISettingsURL);
1929 browser::NavigateParams params(GetSingletonTabNavigateParams(url));
1930 params.path_behavior = browser::NavigateParams::IGNORE_AND_STAY_PUT;
1931 browser::Navigate(¶ms);
1932 }
1933
OpenPasswordManager()1934 void Browser::OpenPasswordManager() {
1935 UserMetrics::RecordAction(UserMetricsAction("Options_ShowPasswordManager"),
1936 profile_);
1937 ShowOptionsTab(chrome::kPasswordManagerSubPage);
1938 }
1939
OpenImportSettingsDialog()1940 void Browser::OpenImportSettingsDialog() {
1941 UserMetrics::RecordAction(UserMetricsAction("Import_ShowDlg"), profile_);
1942 ShowOptionsTab(chrome::kImportDataSubPage);
1943 }
1944
OpenInstantConfirmDialog()1945 void Browser::OpenInstantConfirmDialog() {
1946 ShowOptionsTab(chrome::kInstantConfirmPage);
1947 }
1948
OpenSyncMyBookmarksDialog()1949 void Browser::OpenSyncMyBookmarksDialog() {
1950 sync_ui_util::OpenSyncMyBookmarksDialog(
1951 profile_, this, ProfileSyncService::START_FROM_WRENCH);
1952 }
1953
OpenAboutChromeDialog()1954 void Browser::OpenAboutChromeDialog() {
1955 UserMetrics::RecordAction(UserMetricsAction("AboutChrome"), profile_);
1956 #if defined(OS_CHROMEOS)
1957 ShowSingletonTab(GURL(chrome::kChromeUIAboutURL));
1958 #else
1959 window_->ShowAboutChromeDialog();
1960 #endif
1961 }
1962
OpenUpdateChromeDialog()1963 void Browser::OpenUpdateChromeDialog() {
1964 UserMetrics::RecordAction(UserMetricsAction("UpdateChrome"), profile_);
1965 window_->ShowUpdateChromeDialog();
1966 }
1967
OpenHelpTab()1968 void Browser::OpenHelpTab() {
1969 GURL help_url(kHelpContentUrl);
1970 GURL localized_help_url = google_util::AppendGoogleLocaleParam(help_url);
1971 AddSelectedTabWithURL(localized_help_url, PageTransition::AUTO_BOOKMARK);
1972 }
1973
OpenThemeGalleryTabAndActivate()1974 void Browser::OpenThemeGalleryTabAndActivate() {
1975 AddSelectedTabWithURL(GURL(l10n_util::GetStringUTF8(IDS_THEMES_GALLERY_URL)),
1976 PageTransition::LINK);
1977 }
1978
OpenPrivacyDashboardTabAndActivate()1979 void Browser::OpenPrivacyDashboardTabAndActivate() {
1980 OpenURL(GURL(kPrivacyDashboardUrl), GURL(),
1981 NEW_FOREGROUND_TAB, PageTransition::LINK);
1982 window_->Activate();
1983 }
1984
OpenAutofillHelpTabAndActivate()1985 void Browser::OpenAutofillHelpTabAndActivate() {
1986 GURL help_url = google_util::AppendGoogleLocaleParam(GURL(kAutofillHelpUrl));
1987 AddSelectedTabWithURL(help_url, PageTransition::LINK);
1988 }
1989
OpenSearchEngineOptionsDialog()1990 void Browser::OpenSearchEngineOptionsDialog() {
1991 UserMetrics::RecordAction(UserMetricsAction("EditSearchEngines"), profile_);
1992 ShowOptionsTab(chrome::kSearchEnginesSubPage);
1993 }
1994
1995 #if defined(OS_CHROMEOS)
OpenFileManager()1996 void Browser::OpenFileManager() {
1997 UserMetrics::RecordAction(UserMetricsAction("OpenFileManager"));
1998 ShowSingletonTab(FileManagerUtil::GetFileBrowserUrl());
1999 }
2000
OpenSystemOptionsDialog()2001 void Browser::OpenSystemOptionsDialog() {
2002 UserMetrics::RecordAction(UserMetricsAction("OpenSystemOptionsDialog"),
2003 profile_);
2004 ShowOptionsTab(chrome::kSystemOptionsSubPage);
2005 }
2006
OpenInternetOptionsDialog()2007 void Browser::OpenInternetOptionsDialog() {
2008 UserMetrics::RecordAction(UserMetricsAction("OpenInternetOptionsDialog"),
2009 profile_);
2010 ShowOptionsTab(chrome::kInternetOptionsSubPage);
2011 }
2012
OpenLanguageOptionsDialog()2013 void Browser::OpenLanguageOptionsDialog() {
2014 UserMetrics::RecordAction(UserMetricsAction("OpenLanguageOptionsDialog"),
2015 profile_);
2016 ShowOptionsTab(chrome::kLanguageOptionsSubPage);
2017 }
2018
OpenSystemTabAndActivate()2019 void Browser::OpenSystemTabAndActivate() {
2020 OpenURL(GURL(chrome::kChromeUISystemInfoURL), GURL(),
2021 NEW_FOREGROUND_TAB, PageTransition::LINK);
2022 window_->Activate();
2023 }
2024
OpenMobilePlanTabAndActivate()2025 void Browser::OpenMobilePlanTabAndActivate() {
2026 OpenURL(GURL(chrome::kChromeUIMobileSetupURL), GURL(),
2027 NEW_FOREGROUND_TAB, PageTransition::LINK);
2028 window_->Activate();
2029 }
2030 #endif
2031
OpenPluginsTabAndActivate()2032 void Browser::OpenPluginsTabAndActivate() {
2033 OpenURL(GURL(chrome::kAboutPluginsURL), GURL(),
2034 NEW_FOREGROUND_TAB, PageTransition::LINK);
2035 window_->Activate();
2036 }
2037
2038 ///////////////////////////////////////////////////////////////////////////////
2039
2040 // static
SetNewHomePagePrefs(PrefService * prefs)2041 void Browser::SetNewHomePagePrefs(PrefService* prefs) {
2042 const PrefService::Preference* home_page_pref =
2043 prefs->FindPreference(prefs::kHomePage);
2044 if (home_page_pref &&
2045 !home_page_pref->IsManaged() &&
2046 !prefs->HasPrefPath(prefs::kHomePage)) {
2047 prefs->SetString(prefs::kHomePage,
2048 GoogleURLTracker::kDefaultGoogleHomepage);
2049 }
2050 const PrefService::Preference* home_page_is_new_tab_page_pref =
2051 prefs->FindPreference(prefs::kHomePageIsNewTabPage);
2052 if (home_page_is_new_tab_page_pref &&
2053 !home_page_is_new_tab_page_pref->IsManaged() &&
2054 !prefs->HasPrefPath(prefs::kHomePageIsNewTabPage))
2055 prefs->SetBoolean(prefs::kHomePageIsNewTabPage, false);
2056 }
2057
2058 // static
RegisterPrefs(PrefService * prefs)2059 void Browser::RegisterPrefs(PrefService* prefs) {
2060 prefs->RegisterIntegerPref(prefs::kOptionsWindowLastTabIndex, 0);
2061 prefs->RegisterIntegerPref(prefs::kExtensionSidebarWidth, -1);
2062 prefs->RegisterIntegerPref(prefs::kMultipleProfilePrefMigration, 0);
2063 prefs->RegisterBooleanPref(prefs::kAllowFileSelectionDialogs, true);
2064 // Educated guess: Chrome has a bundled Flash version supporting
2065 // clearing LSO data, Chromium hasn't.
2066 #if defined(GOOGLE_CHROME_BUILD)
2067 prefs->RegisterBooleanPref(prefs::kClearPluginLSODataEnabled, true);
2068 #else
2069 prefs->RegisterBooleanPref(prefs::kClearPluginLSODataEnabled, false);
2070 #endif
2071 }
2072
2073 // static
RegisterUserPrefs(PrefService * prefs)2074 void Browser::RegisterUserPrefs(PrefService* prefs) {
2075 prefs->RegisterStringPref(prefs::kHomePage,
2076 chrome::kChromeUINewTabURL);
2077 prefs->RegisterBooleanPref(prefs::kHomePageIsNewTabPage, true);
2078 prefs->RegisterBooleanPref(prefs::kShowHomeButton, false);
2079 #if defined(OS_MACOSX)
2080 // This really belongs in platform code, but there's no good place to
2081 // initialize it between the time when the AppController is created
2082 // (where there's no profile) and the time the controller gets another
2083 // crack at the start of the main event loop. By that time, BrowserInit
2084 // has already created the browser window, and it's too late: we need the
2085 // pref to be already initialized. Doing it here also saves us from having
2086 // to hard-code pref registration in the several unit tests that use
2087 // this preference.
2088 prefs->RegisterBooleanPref(prefs::kConfirmToQuitEnabled, false);
2089 prefs->RegisterBooleanPref(prefs::kShowUpdatePromotionInfoBar, true);
2090 #endif
2091 prefs->RegisterBooleanPref(prefs::kDeleteBrowsingHistory, true);
2092 prefs->RegisterBooleanPref(prefs::kDeleteDownloadHistory, true);
2093 prefs->RegisterBooleanPref(prefs::kDeleteCache, true);
2094 prefs->RegisterBooleanPref(prefs::kDeleteCookies, true);
2095 prefs->RegisterBooleanPref(prefs::kDeletePasswords, false);
2096 prefs->RegisterBooleanPref(prefs::kDeleteFormData, false);
2097 prefs->RegisterIntegerPref(prefs::kDeleteTimePeriod, 0);
2098 prefs->RegisterBooleanPref(prefs::kCheckDefaultBrowser, true);
2099 prefs->RegisterBooleanPref(prefs::kShowOmniboxSearchHint, true);
2100 prefs->RegisterBooleanPref(prefs::kWebAppCreateOnDesktop, true);
2101 prefs->RegisterBooleanPref(prefs::kWebAppCreateInAppsMenu, true);
2102 prefs->RegisterBooleanPref(prefs::kWebAppCreateInQuickLaunchBar, true);
2103 prefs->RegisterBooleanPref(prefs::kUseVerticalTabs, false);
2104 prefs->RegisterBooleanPref(prefs::kEnableTranslate, true);
2105 prefs->RegisterBooleanPref(prefs::kEnableBookmarkBar, true);
2106 prefs->RegisterBooleanPref(prefs::kRemotingHasSetupCompleted, false);
2107 prefs->RegisterStringPref(prefs::kCloudPrintEmail, std::string());
2108 prefs->RegisterBooleanPref(prefs::kCloudPrintProxyEnabled, true);
2109 prefs->RegisterBooleanPref(prefs::kDevToolsDisabled, false);
2110 prefs->RegisterBooleanPref(prefs::kIncognitoEnabled, true);
2111 prefs->RegisterIntegerPref(prefs::kDevToolsSplitLocation, -1);
2112 prefs->RegisterDictionaryPref(prefs::kBrowserWindowPlacement);
2113 prefs->RegisterDictionaryPref(prefs::kPreferencesWindowPlacement);
2114 // We need to register the type of these preferences in order to query
2115 // them even though they're typically only controlled via policy or command
2116 // line switches.
2117 prefs->RegisterBooleanPref(prefs::kDisable3DAPIs, false);
2118 prefs->RegisterBooleanPref(prefs::kPluginsAllowOutdated, false);
2119 prefs->RegisterBooleanPref(prefs::kEnableHyperlinkAuditing, true);
2120 prefs->RegisterBooleanPref(prefs::kEnableReferrers, true);
2121 }
2122
2123 // static
RunUnloadEventsHelper(TabContents * contents)2124 bool Browser::RunUnloadEventsHelper(TabContents* contents) {
2125 // If the TabContents is not connected yet, then there's no unload
2126 // handler we can fire even if the TabContents has an unload listener.
2127 // One case where we hit this is in a tab that has an infinite loop
2128 // before load.
2129 if (contents->NeedToFireBeforeUnload()) {
2130 // If the page has unload listeners, then we tell the renderer to fire
2131 // them. Once they have fired, we'll get a message back saying whether
2132 // to proceed closing the page or not, which sends us back to this method
2133 // with the NeedToFireBeforeUnload bit cleared.
2134 contents->render_view_host()->FirePageBeforeUnload(false);
2135 return true;
2136 }
2137 return false;
2138 }
2139
2140 // static
GetBrowserForController(const NavigationController * controller,int * index_result)2141 Browser* Browser::GetBrowserForController(
2142 const NavigationController* controller, int* index_result) {
2143 BrowserList::const_iterator it;
2144 for (it = BrowserList::begin(); it != BrowserList::end(); ++it) {
2145 int index = (*it)->tab_handler_->GetTabStripModel()->GetIndexOfController(
2146 controller);
2147 if (index != TabStripModel::kNoTab) {
2148 if (index_result)
2149 *index_result = index;
2150 return *it;
2151 }
2152 }
2153
2154 return NULL;
2155 }
2156
ExecuteCommandWithDisposition(int id,WindowOpenDisposition disposition)2157 void Browser::ExecuteCommandWithDisposition(
2158 int id, WindowOpenDisposition disposition) {
2159 // No commands are enabled if there is not yet any selected tab.
2160 // TODO(pkasting): It seems like we should not need this, because either
2161 // most/all commands should not have been enabled yet anyway or the ones that
2162 // are enabled should be global, or safe themselves against having no selected
2163 // tab. However, Ben says he tried removing this before and got lots of
2164 // crashes, e.g. from Windows sending WM_COMMANDs at random times during
2165 // window construction. This probably could use closer examination someday.
2166 if (!GetSelectedTabContentsWrapper())
2167 return;
2168
2169 DCHECK(command_updater_.IsCommandEnabled(id)) << "Invalid/disabled command "
2170 << id;
2171
2172 // If command execution is blocked then just record the command and return.
2173 if (block_command_execution_) {
2174 // We actually only allow no more than one blocked command, otherwise some
2175 // commands maybe lost.
2176 DCHECK_EQ(last_blocked_command_id_, -1);
2177 last_blocked_command_id_ = id;
2178 last_blocked_command_disposition_ = disposition;
2179 return;
2180 }
2181
2182 // The order of commands in this switch statement must match the function
2183 // declaration order in browser.h!
2184 switch (id) {
2185 // Navigation commands
2186 case IDC_BACK: GoBack(disposition); break;
2187 case IDC_FORWARD: GoForward(disposition); break;
2188 case IDC_RELOAD: Reload(disposition); break;
2189 case IDC_RELOAD_IGNORING_CACHE: ReloadIgnoringCache(disposition); break;
2190 case IDC_HOME: Home(disposition); break;
2191 case IDC_OPEN_CURRENT_URL: OpenCurrentURL(); break;
2192 case IDC_STOP: Stop(); break;
2193
2194 // Window management commands
2195 case IDC_NEW_WINDOW: NewWindow(); break;
2196 case IDC_NEW_INCOGNITO_WINDOW: NewIncognitoWindow(); break;
2197 case IDC_CLOSE_WINDOW: CloseWindow(); break;
2198 case IDC_NEW_TAB: NewTab(); break;
2199 case IDC_CLOSE_TAB: CloseTab(); break;
2200 case IDC_SELECT_NEXT_TAB: SelectNextTab(); break;
2201 case IDC_SELECT_PREVIOUS_TAB: SelectPreviousTab(); break;
2202 case IDC_TABPOSE: OpenTabpose(); break;
2203 case IDC_MOVE_TAB_NEXT: MoveTabNext(); break;
2204 case IDC_MOVE_TAB_PREVIOUS: MoveTabPrevious(); break;
2205 case IDC_SELECT_TAB_0:
2206 case IDC_SELECT_TAB_1:
2207 case IDC_SELECT_TAB_2:
2208 case IDC_SELECT_TAB_3:
2209 case IDC_SELECT_TAB_4:
2210 case IDC_SELECT_TAB_5:
2211 case IDC_SELECT_TAB_6:
2212 case IDC_SELECT_TAB_7: SelectNumberedTab(id - IDC_SELECT_TAB_0);
2213 break;
2214 case IDC_SELECT_LAST_TAB: SelectLastTab(); break;
2215 case IDC_DUPLICATE_TAB: DuplicateTab(); break;
2216 case IDC_RESTORE_TAB: RestoreTab(); break;
2217 case IDC_COPY_URL: WriteCurrentURLToClipboard(); break;
2218 case IDC_SHOW_AS_TAB: ConvertPopupToTabbedBrowser(); break;
2219 case IDC_FULLSCREEN: ToggleFullscreenMode(); break;
2220 case IDC_EXIT: Exit(); break;
2221 case IDC_TOGGLE_VERTICAL_TABS: ToggleUseVerticalTabs(); break;
2222 #if defined(OS_CHROMEOS)
2223 case IDC_SEARCH: Search(); break;
2224 case IDC_SHOW_KEYBOARD_OVERLAY: ShowKeyboardOverlay(); break;
2225 #endif
2226
2227 // Page-related commands
2228 case IDC_SAVE_PAGE: SavePage(); break;
2229 case IDC_BOOKMARK_PAGE: BookmarkCurrentPage(); break;
2230 case IDC_BOOKMARK_ALL_TABS: BookmarkAllTabs(); break;
2231 case IDC_VIEW_SOURCE: ViewSelectedSource(); break;
2232 case IDC_EMAIL_PAGE_LOCATION: EmailPageLocation(); break;
2233 case IDC_PRINT: Print(); break;
2234 case IDC_ENCODING_AUTO_DETECT: ToggleEncodingAutoDetect(); break;
2235 case IDC_ENCODING_UTF8:
2236 case IDC_ENCODING_UTF16LE:
2237 case IDC_ENCODING_ISO88591:
2238 case IDC_ENCODING_WINDOWS1252:
2239 case IDC_ENCODING_GBK:
2240 case IDC_ENCODING_GB18030:
2241 case IDC_ENCODING_BIG5HKSCS:
2242 case IDC_ENCODING_BIG5:
2243 case IDC_ENCODING_KOREAN:
2244 case IDC_ENCODING_SHIFTJIS:
2245 case IDC_ENCODING_ISO2022JP:
2246 case IDC_ENCODING_EUCJP:
2247 case IDC_ENCODING_THAI:
2248 case IDC_ENCODING_ISO885915:
2249 case IDC_ENCODING_MACINTOSH:
2250 case IDC_ENCODING_ISO88592:
2251 case IDC_ENCODING_WINDOWS1250:
2252 case IDC_ENCODING_ISO88595:
2253 case IDC_ENCODING_WINDOWS1251:
2254 case IDC_ENCODING_KOI8R:
2255 case IDC_ENCODING_KOI8U:
2256 case IDC_ENCODING_ISO88597:
2257 case IDC_ENCODING_WINDOWS1253:
2258 case IDC_ENCODING_ISO88594:
2259 case IDC_ENCODING_ISO885913:
2260 case IDC_ENCODING_WINDOWS1257:
2261 case IDC_ENCODING_ISO88593:
2262 case IDC_ENCODING_ISO885910:
2263 case IDC_ENCODING_ISO885914:
2264 case IDC_ENCODING_ISO885916:
2265 case IDC_ENCODING_WINDOWS1254:
2266 case IDC_ENCODING_ISO88596:
2267 case IDC_ENCODING_WINDOWS1256:
2268 case IDC_ENCODING_ISO88598:
2269 case IDC_ENCODING_ISO88598I:
2270 case IDC_ENCODING_WINDOWS1255:
2271 case IDC_ENCODING_WINDOWS1258: OverrideEncoding(id); break;
2272
2273 // Clipboard commands
2274 case IDC_CUT: Cut(); break;
2275 case IDC_COPY: Copy(); break;
2276 case IDC_PASTE: Paste(); break;
2277
2278 // Find-in-page
2279 case IDC_FIND: Find(); break;
2280 case IDC_FIND_NEXT: FindNext(); break;
2281 case IDC_FIND_PREVIOUS: FindPrevious(); break;
2282
2283 // Zoom
2284 case IDC_ZOOM_PLUS: Zoom(PageZoom::ZOOM_IN); break;
2285 case IDC_ZOOM_NORMAL: Zoom(PageZoom::RESET); break;
2286 case IDC_ZOOM_MINUS: Zoom(PageZoom::ZOOM_OUT); break;
2287
2288 // Focus various bits of UI
2289 case IDC_FOCUS_TOOLBAR: FocusToolbar(); break;
2290 case IDC_FOCUS_LOCATION: FocusLocationBar(); break;
2291 case IDC_FOCUS_SEARCH: FocusSearch(); break;
2292 case IDC_FOCUS_MENU_BAR: FocusAppMenu(); break;
2293 case IDC_FOCUS_BOOKMARKS: FocusBookmarksToolbar(); break;
2294 case IDC_FOCUS_CHROMEOS_STATUS: FocusChromeOSStatus(); break;
2295 case IDC_FOCUS_NEXT_PANE: FocusNextPane(); break;
2296 case IDC_FOCUS_PREVIOUS_PANE: FocusPreviousPane(); break;
2297
2298 // Show various bits of UI
2299 case IDC_OPEN_FILE: OpenFile(); break;
2300 case IDC_CREATE_SHORTCUTS: OpenCreateShortcutsDialog(); break;
2301 case IDC_DEV_TOOLS: ToggleDevToolsWindow(
2302 DEVTOOLS_TOGGLE_ACTION_NONE);
2303 break;
2304 case IDC_DEV_TOOLS_CONSOLE: ToggleDevToolsWindow(
2305 DEVTOOLS_TOGGLE_ACTION_SHOW_CONSOLE);
2306 break;
2307 case IDC_DEV_TOOLS_INSPECT: ToggleDevToolsWindow(
2308 DEVTOOLS_TOGGLE_ACTION_INSPECT);
2309 break;
2310 case IDC_TASK_MANAGER: OpenTaskManager(false); break;
2311 case IDC_VIEW_BACKGROUND_PAGES: OpenTaskManager(true); break;
2312 case IDC_FEEDBACK: OpenBugReportDialog(); break;
2313
2314 case IDC_SHOW_BOOKMARK_BAR: ToggleBookmarkBar(); break;
2315 case IDC_PROFILING_ENABLED: Profiling::Toggle(); break;
2316
2317 case IDC_SHOW_BOOKMARK_MANAGER: OpenBookmarkManager(); break;
2318 case IDC_SHOW_APP_MENU: ShowAppMenu(); break;
2319 case IDC_SHOW_HISTORY: ShowHistoryTab(); break;
2320 case IDC_SHOW_DOWNLOADS: ShowDownloadsTab(); break;
2321 case IDC_MANAGE_EXTENSIONS: ShowExtensionsTab(); break;
2322 case IDC_SYNC_BOOKMARKS: OpenSyncMyBookmarksDialog(); break;
2323 case IDC_OPTIONS: OpenOptionsDialog(); break;
2324 case IDC_EDIT_SEARCH_ENGINES: OpenSearchEngineOptionsDialog(); break;
2325 case IDC_VIEW_PASSWORDS: OpenPasswordManager(); break;
2326 case IDC_CLEAR_BROWSING_DATA: OpenClearBrowsingDataDialog(); break;
2327 case IDC_IMPORT_SETTINGS: OpenImportSettingsDialog(); break;
2328 case IDC_ABOUT: OpenAboutChromeDialog(); break;
2329 case IDC_UPGRADE_DIALOG: OpenUpdateChromeDialog(); break;
2330 case IDC_VIEW_INCOMPATIBILITIES: ShowAboutConflictsTab(); break;
2331 case IDC_HELP_PAGE: OpenHelpTab(); break;
2332 #if defined(OS_CHROMEOS)
2333 case IDC_FILE_MANAGER: OpenFileManager(); break;
2334 case IDC_SYSTEM_OPTIONS: OpenSystemOptionsDialog(); break;
2335 case IDC_INTERNET_OPTIONS: OpenInternetOptionsDialog(); break;
2336 case IDC_LANGUAGE_OPTIONS: OpenLanguageOptionsDialog(); break;
2337 #endif
2338
2339 default:
2340 LOG(WARNING) << "Received Unimplemented Command: " << id;
2341 break;
2342 }
2343 }
2344
ExecuteCommandIfEnabled(int id)2345 bool Browser::ExecuteCommandIfEnabled(int id) {
2346 if (command_updater_.SupportsCommand(id) &&
2347 command_updater_.IsCommandEnabled(id)) {
2348 ExecuteCommand(id);
2349 return true;
2350 }
2351 return false;
2352 }
2353
IsReservedCommandOrKey(int command_id,const NativeWebKeyboardEvent & event)2354 bool Browser::IsReservedCommandOrKey(int command_id,
2355 const NativeWebKeyboardEvent& event) {
2356 #if defined(OS_CHROMEOS)
2357 // Chrome OS's top row of keys produces F1-10. Make sure that web pages
2358 // aren't able to block Chrome from performing the standard actions for F1-F4
2359 // (F5-7 are grabbed by other X clients and hence don't need this protection,
2360 // and F8-10 are handled separately in Chrome via a GDK event filter, but
2361 // let's future-proof this).
2362 ui::KeyboardCode key_code =
2363 static_cast<ui::KeyboardCode>(event.windowsKeyCode);
2364 if (key_code == ui::VKEY_F1 ||
2365 key_code == ui::VKEY_F2 ||
2366 key_code == ui::VKEY_F3 ||
2367 key_code == ui::VKEY_F4 ||
2368 key_code == ui::VKEY_F5 ||
2369 key_code == ui::VKEY_F6 ||
2370 key_code == ui::VKEY_F7 ||
2371 key_code == ui::VKEY_F8 ||
2372 key_code == ui::VKEY_F9 ||
2373 key_code == ui::VKEY_F10) {
2374 return true;
2375 }
2376 #endif
2377
2378 return command_id == IDC_CLOSE_TAB ||
2379 command_id == IDC_CLOSE_WINDOW ||
2380 command_id == IDC_NEW_INCOGNITO_WINDOW ||
2381 command_id == IDC_NEW_TAB ||
2382 command_id == IDC_NEW_WINDOW ||
2383 command_id == IDC_RESTORE_TAB ||
2384 command_id == IDC_SELECT_NEXT_TAB ||
2385 command_id == IDC_SELECT_PREVIOUS_TAB ||
2386 command_id == IDC_TABPOSE ||
2387 command_id == IDC_EXIT ||
2388 command_id == IDC_SEARCH;
2389 }
2390
SetBlockCommandExecution(bool block)2391 void Browser::SetBlockCommandExecution(bool block) {
2392 block_command_execution_ = block;
2393 if (block) {
2394 last_blocked_command_id_ = -1;
2395 last_blocked_command_disposition_ = CURRENT_TAB;
2396 }
2397 }
2398
GetLastBlockedCommand(WindowOpenDisposition * disposition)2399 int Browser::GetLastBlockedCommand(WindowOpenDisposition* disposition) {
2400 if (disposition)
2401 *disposition = last_blocked_command_disposition_;
2402 return last_blocked_command_id_;
2403 }
2404
UpdateUIForNavigationInTab(TabContentsWrapper * contents,PageTransition::Type transition,bool user_initiated)2405 void Browser::UpdateUIForNavigationInTab(TabContentsWrapper* contents,
2406 PageTransition::Type transition,
2407 bool user_initiated) {
2408 tabstrip_model()->TabNavigating(contents, transition);
2409
2410 bool contents_is_selected = contents == GetSelectedTabContentsWrapper();
2411 if (user_initiated && contents_is_selected && window()->GetLocationBar()) {
2412 // Forcibly reset the location bar if the url is going to change in the
2413 // current tab, since otherwise it won't discard any ongoing user edits,
2414 // since it doesn't realize this is a user-initiated action.
2415 window()->GetLocationBar()->Revert();
2416 }
2417
2418 if (GetStatusBubble())
2419 GetStatusBubble()->Hide();
2420
2421 // Update the location bar. This is synchronous. We specifically don't
2422 // update the load state since the load hasn't started yet and updating it
2423 // will put it out of sync with the actual state like whether we're
2424 // displaying a favicon, which controls the throbber. If we updated it here,
2425 // the throbber will show the default favicon for a split second when
2426 // navigating away from the new tab page.
2427 ScheduleUIUpdate(contents->tab_contents(), TabContents::INVALIDATE_URL);
2428
2429 if (contents_is_selected)
2430 contents->tab_contents()->Focus();
2431 }
2432
GetHomePage() const2433 GURL Browser::GetHomePage() const {
2434 // --homepage overrides any preferences.
2435 const CommandLine& command_line = *CommandLine::ForCurrentProcess();
2436 if (command_line.HasSwitch(switches::kHomePage)) {
2437 // TODO(evanm): clean up usage of DIR_CURRENT.
2438 // http://code.google.com/p/chromium/issues/detail?id=60630
2439 // For now, allow this code to call getcwd().
2440 base::ThreadRestrictions::ScopedAllowIO allow_io;
2441
2442 FilePath browser_directory;
2443 PathService::Get(base::DIR_CURRENT, &browser_directory);
2444 GURL home_page(URLFixerUpper::FixupRelativeFile(browser_directory,
2445 command_line.GetSwitchValuePath(switches::kHomePage)));
2446 if (home_page.is_valid())
2447 return home_page;
2448 }
2449
2450 if (profile_->GetPrefs()->GetBoolean(prefs::kHomePageIsNewTabPage))
2451 return GURL(chrome::kChromeUINewTabURL);
2452 GURL home_page(URLFixerUpper::FixupURL(
2453 profile_->GetPrefs()->GetString(prefs::kHomePage),
2454 std::string()));
2455 if (!home_page.is_valid())
2456 return GURL(chrome::kChromeUINewTabURL);
2457 return home_page;
2458 }
2459
2460 ///////////////////////////////////////////////////////////////////////////////
2461 // Browser, PageNavigator implementation:
2462
OpenURL(const GURL & url,const GURL & referrer,WindowOpenDisposition disposition,PageTransition::Type transition)2463 void Browser::OpenURL(const GURL& url, const GURL& referrer,
2464 WindowOpenDisposition disposition,
2465 PageTransition::Type transition) {
2466 OpenURLFromTab(NULL, url, referrer, disposition, transition);
2467 }
2468
2469 ///////////////////////////////////////////////////////////////////////////////
2470 // Browser, CommandUpdater::CommandUpdaterDelegate implementation:
2471
ExecuteCommand(int id)2472 void Browser::ExecuteCommand(int id) {
2473 ExecuteCommandWithDisposition(id, CURRENT_TAB);
2474 }
2475
2476 ///////////////////////////////////////////////////////////////////////////////
2477 // Browser, TabHandlerDelegate implementation:
2478
GetProfile() const2479 Profile* Browser::GetProfile() const {
2480 return profile();
2481 }
2482
AsBrowser()2483 Browser* Browser::AsBrowser() {
2484 return this;
2485 }
2486
2487 ///////////////////////////////////////////////////////////////////////////////
2488 // Browser, TabStripModelDelegate implementation:
2489
AddBlankTab(bool foreground)2490 TabContentsWrapper* Browser::AddBlankTab(bool foreground) {
2491 return AddBlankTabAt(-1, foreground);
2492 }
2493
AddBlankTabAt(int index,bool foreground)2494 TabContentsWrapper* Browser::AddBlankTabAt(int index, bool foreground) {
2495 // Time new tab page creation time. We keep track of the timing data in
2496 // TabContents, but we want to include the time it takes to create the
2497 // TabContents object too.
2498 base::TimeTicks new_tab_start_time = base::TimeTicks::Now();
2499 browser::NavigateParams params(this, GURL(chrome::kChromeUINewTabURL),
2500 PageTransition::TYPED);
2501 params.disposition = foreground ? NEW_FOREGROUND_TAB : NEW_BACKGROUND_TAB;
2502 params.tabstrip_index = index;
2503 browser::Navigate(¶ms);
2504 params.target_contents->tab_contents()->set_new_tab_start_time(
2505 new_tab_start_time);
2506 return params.target_contents;
2507 }
2508
CreateNewStripWithContents(TabContentsWrapper * detached_contents,const gfx::Rect & window_bounds,const DockInfo & dock_info,bool maximize)2509 Browser* Browser::CreateNewStripWithContents(
2510 TabContentsWrapper* detached_contents,
2511 const gfx::Rect& window_bounds,
2512 const DockInfo& dock_info,
2513 bool maximize) {
2514 DCHECK(CanSupportWindowFeature(FEATURE_TABSTRIP));
2515
2516 gfx::Rect new_window_bounds = window_bounds;
2517 if (dock_info.GetNewWindowBounds(&new_window_bounds, &maximize))
2518 dock_info.AdjustOtherWindowBounds();
2519
2520 // Create an empty new browser window the same size as the old one.
2521 Browser* browser = new Browser(TYPE_NORMAL, profile_);
2522 browser->set_override_bounds(new_window_bounds);
2523 browser->set_maximized_state(
2524 maximize ? MAXIMIZED_STATE_MAXIMIZED : MAXIMIZED_STATE_UNMAXIMIZED);
2525 browser->InitBrowserWindow();
2526 browser->tabstrip_model()->AppendTabContents(detached_contents, true);
2527 // Make sure the loading state is updated correctly, otherwise the throbber
2528 // won't start if the page is loading.
2529 browser->LoadingStateChanged(detached_contents->tab_contents());
2530 return browser;
2531 }
2532
GetDragActions() const2533 int Browser::GetDragActions() const {
2534 return TabStripModelDelegate::TAB_TEAROFF_ACTION | (tab_count() > 1 ?
2535 TabStripModelDelegate::TAB_MOVE_ACTION : 0);
2536 }
2537
CreateTabContentsForURL(const GURL & url,const GURL & referrer,Profile * profile,PageTransition::Type transition,bool defer_load,SiteInstance * instance) const2538 TabContentsWrapper* Browser::CreateTabContentsForURL(
2539 const GURL& url, const GURL& referrer, Profile* profile,
2540 PageTransition::Type transition, bool defer_load,
2541 SiteInstance* instance) const {
2542 TabContentsWrapper* contents = TabContentsFactory(profile, instance,
2543 MSG_ROUTING_NONE,
2544 GetSelectedTabContents(), NULL);
2545 if (!defer_load) {
2546 // Load the initial URL before adding the new tab contents to the tab strip
2547 // so that the tab contents has navigation state.
2548 contents->controller().LoadURL(url, referrer, transition);
2549 }
2550
2551 return contents;
2552 }
2553
CanDuplicateContentsAt(int index)2554 bool Browser::CanDuplicateContentsAt(int index) {
2555 NavigationController& nc = GetTabContentsAt(index)->controller();
2556 return nc.tab_contents() && nc.GetLastCommittedEntry();
2557 }
2558
DuplicateContentsAt(int index)2559 void Browser::DuplicateContentsAt(int index) {
2560 TabContentsWrapper* contents = GetTabContentsWrapperAt(index);
2561 CHECK(contents);
2562 TabContentsWrapper* contents_dupe = contents->Clone();
2563 TabContents* new_contents = contents_dupe->tab_contents();
2564
2565 bool pinned = false;
2566 if (CanSupportWindowFeature(FEATURE_TABSTRIP)) {
2567 // If this is a tabbed browser, just create a duplicate tab inside the same
2568 // window next to the tab being duplicated.
2569 int index = tab_handler_->GetTabStripModel()->
2570 GetIndexOfTabContents(contents);
2571 pinned = tab_handler_->GetTabStripModel()->IsTabPinned(index);
2572 int add_types = TabStripModel::ADD_ACTIVE |
2573 TabStripModel::ADD_INHERIT_GROUP |
2574 (pinned ? TabStripModel::ADD_PINNED : 0);
2575 tab_handler_->GetTabStripModel()->InsertTabContentsAt(index + 1,
2576 contents_dupe,
2577 add_types);
2578 } else {
2579 Browser* browser = NULL;
2580 if (type_ & TYPE_APP) {
2581 CHECK_EQ((type_ & TYPE_POPUP), 0);
2582 CHECK_NE(type_, TYPE_APP_PANEL);
2583 browser = Browser::CreateForApp(app_name_, gfx::Size(), profile_,
2584 false);
2585 } else if (type_ == TYPE_POPUP) {
2586 browser = Browser::CreateForType(TYPE_POPUP, profile_);
2587 }
2588
2589 // Preserve the size of the original window. The new window has already
2590 // been given an offset by the OS, so we shouldn't copy the old bounds.
2591 BrowserWindow* new_window = browser->window();
2592 new_window->SetBounds(gfx::Rect(new_window->GetRestoredBounds().origin(),
2593 window()->GetRestoredBounds().size()));
2594
2595 // We need to show the browser now. Otherwise ContainerWin assumes the
2596 // TabContents is invisible and won't size it.
2597 browser->window()->Show();
2598
2599 // The page transition below is only for the purpose of inserting the tab.
2600 browser->AddTab(contents_dupe, PageTransition::LINK);
2601 }
2602
2603 if (profile_->HasSessionService()) {
2604 SessionService* session_service = profile_->GetSessionService();
2605 if (session_service)
2606 session_service->TabRestored(&new_contents->controller(), pinned);
2607 }
2608 }
2609
CloseFrameAfterDragSession()2610 void Browser::CloseFrameAfterDragSession() {
2611 #if defined(OS_WIN) || defined(OS_LINUX)
2612 // This is scheduled to run after we return to the message loop because
2613 // otherwise the frame will think the drag session is still active and ignore
2614 // the request.
2615 // TODO(port): figure out what is required here in a cross-platform world
2616 MessageLoop::current()->PostTask(
2617 FROM_HERE, method_factory_.NewRunnableMethod(&Browser::CloseFrame));
2618 #endif
2619 }
2620
CreateHistoricalTab(TabContentsWrapper * contents)2621 void Browser::CreateHistoricalTab(TabContentsWrapper* contents) {
2622 // We don't create historical tabs for incognito windows or windows without
2623 // profiles.
2624 if (!profile() || profile()->IsOffTheRecord() ||
2625 !profile()->GetTabRestoreService()) {
2626 return;
2627 }
2628
2629 // We only create historical tab entries for tabbed browser windows.
2630 if (CanSupportWindowFeature(FEATURE_TABSTRIP)) {
2631 profile()->GetTabRestoreService()->CreateHistoricalTab(
2632 &contents->controller(),
2633 tab_handler_->GetTabStripModel()->GetIndexOfTabContents(contents));
2634 }
2635 }
2636
RunUnloadListenerBeforeClosing(TabContentsWrapper * contents)2637 bool Browser::RunUnloadListenerBeforeClosing(TabContentsWrapper* contents) {
2638 return Browser::RunUnloadEventsHelper(contents->tab_contents());
2639 }
2640
CanReloadContents(TabContents * source) const2641 bool Browser::CanReloadContents(TabContents* source) const {
2642 return type() != TYPE_DEVTOOLS;
2643 }
2644
CanCloseContentsAt(int index)2645 bool Browser::CanCloseContentsAt(int index) {
2646 if (!CanCloseTab())
2647 return false;
2648 if (tab_handler_->GetTabStripModel()->count() > 1)
2649 return true;
2650 // We are closing the last tab for this browser. Make sure to check for
2651 // in-progress downloads.
2652 // Note that the next call when it returns false will ask the user for
2653 // confirmation before closing the browser if the user decides so.
2654 return CanCloseWithInProgressDownloads();
2655 }
2656
CanBookmarkAllTabs() const2657 bool Browser::CanBookmarkAllTabs() const {
2658 BookmarkModel* model = profile()->GetBookmarkModel();
2659 return (model && model->IsLoaded()) &&
2660 tab_count() > 1 &&
2661 edit_bookmarks_enabled_.GetValue();
2662 }
2663
BookmarkAllTabs()2664 void Browser::BookmarkAllTabs() {
2665 BookmarkModel* model = profile()->GetBookmarkModel();
2666 DCHECK(model && model->IsLoaded());
2667
2668 BookmarkEditor::EditDetails details;
2669 details.type = BookmarkEditor::EditDetails::NEW_FOLDER;
2670 bookmark_utils::GetURLsForOpenTabs(this, &(details.urls));
2671 DCHECK(!details.urls.empty());
2672
2673 BookmarkEditor::Show(window()->GetNativeHandle(), profile_,
2674 model->GetParentForNewNodes(), details,
2675 BookmarkEditor::SHOW_TREE);
2676 }
2677
CanCloseTab() const2678 bool Browser::CanCloseTab() const {
2679 TabCloseableStateWatcher* watcher =
2680 g_browser_process->tab_closeable_state_watcher();
2681 return !watcher || watcher->CanCloseTab(this);
2682 }
2683
ToggleUseVerticalTabs()2684 void Browser::ToggleUseVerticalTabs() {
2685 use_vertical_tabs_.SetValue(!UseVerticalTabs());
2686 UseVerticalTabsChanged();
2687 }
2688
LargeIconsPermitted() const2689 bool Browser::LargeIconsPermitted() const {
2690 // We don't show the big icons in tabs for TYPE_EXTENSION_APP windows because
2691 // for those windows, we already have a big icon in the top-left outside any
2692 // tab. Having big tab icons too looks kinda redonk.
2693 return true;
2694 }
2695
2696 ///////////////////////////////////////////////////////////////////////////////
2697 // Browser, TabStripModelObserver implementation:
2698
TabInsertedAt(TabContentsWrapper * contents,int index,bool foreground)2699 void Browser::TabInsertedAt(TabContentsWrapper* contents,
2700 int index,
2701 bool foreground) {
2702 SetAsDelegate(contents, this);
2703 contents->controller().SetWindowID(session_id());
2704
2705 // Each renderer holds the ID of the window that hosts it. Notify the
2706 // renderer that the window ID changed.
2707 contents->render_view_host()->UpdateBrowserWindowId(
2708 contents->controller().window_id().id());
2709
2710 SyncHistoryWithTabs(index);
2711
2712 // Make sure the loading state is updated correctly, otherwise the throbber
2713 // won't start if the page is loading.
2714 LoadingStateChanged(contents->tab_contents());
2715
2716 // If the tab crashes in the beforeunload or unload handler, it won't be
2717 // able to ack. But we know we can close it.
2718 registrar_.Add(this, NotificationType::TAB_CONTENTS_DISCONNECTED,
2719 Source<TabContentsWrapper>(contents));
2720 }
2721
TabClosingAt(TabStripModel * tab_strip_model,TabContentsWrapper * contents,int index)2722 void Browser::TabClosingAt(TabStripModel* tab_strip_model,
2723 TabContentsWrapper* contents,
2724 int index) {
2725 NotificationService::current()->Notify(
2726 NotificationType::TAB_CLOSING,
2727 Source<NavigationController>(&contents->controller()),
2728 NotificationService::NoDetails());
2729
2730 // Sever the TabContents' connection back to us.
2731 SetAsDelegate(contents, NULL);
2732 }
2733
TabDetachedAt(TabContentsWrapper * contents,int index)2734 void Browser::TabDetachedAt(TabContentsWrapper* contents, int index) {
2735 TabDetachedAtImpl(contents, index, DETACH_TYPE_DETACH);
2736 }
2737
TabDeselected(TabContentsWrapper * contents)2738 void Browser::TabDeselected(TabContentsWrapper* contents) {
2739 if (instant())
2740 instant()->DestroyPreviewContents();
2741
2742 // Save what the user's currently typing, so it can be restored when we
2743 // switch back to this tab.
2744 window_->GetLocationBar()->SaveStateToContents(contents->tab_contents());
2745 }
2746
TabSelectedAt(TabContentsWrapper * old_contents,TabContentsWrapper * new_contents,int index,bool user_gesture)2747 void Browser::TabSelectedAt(TabContentsWrapper* old_contents,
2748 TabContentsWrapper* new_contents,
2749 int index,
2750 bool user_gesture) {
2751 if (old_contents == new_contents)
2752 return;
2753
2754 // On some platforms we want to automatically reload tabs that are
2755 // killed when the user selects them.
2756 if (user_gesture && new_contents->tab_contents()->crashed_status() ==
2757 base::TERMINATION_STATUS_PROCESS_WAS_KILLED) {
2758 const CommandLine& parsed_command_line = *CommandLine::ForCurrentProcess();
2759 if (parsed_command_line.HasSwitch(switches::kReloadKilledTabs)) {
2760 Reload(CURRENT_TAB);
2761 return;
2762 }
2763 }
2764
2765 // If we have any update pending, do it now.
2766 if (!chrome_updater_factory_.empty() && old_contents)
2767 ProcessPendingUIUpdates();
2768
2769 // Propagate the profile to the location bar.
2770 UpdateToolbar(true);
2771
2772 // Update reload/stop state.
2773 UpdateReloadStopState(new_contents->tab_contents()->is_loading(), true);
2774
2775 // Update commands to reflect current state.
2776 UpdateCommandsForTabState();
2777
2778 // Reset the status bubble.
2779 StatusBubble* status_bubble = GetStatusBubble();
2780 if (status_bubble) {
2781 status_bubble->Hide();
2782
2783 // Show the loading state (if any).
2784 status_bubble->SetStatus(GetSelectedTabContentsWrapper()->GetStatusText());
2785 }
2786
2787 if (HasFindBarController()) {
2788 find_bar_controller_->ChangeTabContents(new_contents);
2789 find_bar_controller_->find_bar()->MoveWindowIfNecessary(gfx::Rect(), true);
2790 }
2791
2792 // Update sessions. Don't force creation of sessions. If sessions doesn't
2793 // exist, the change will be picked up by sessions when created.
2794 if (profile_->HasSessionService()) {
2795 SessionService* session_service = profile_->GetSessionService();
2796 if (session_service && !tab_handler_->GetTabStripModel()->closing_all()) {
2797 session_service->SetSelectedTabInWindow(
2798 session_id(), tab_handler_->GetTabStripModel()->active_index());
2799 }
2800 }
2801 }
2802
TabMoved(TabContentsWrapper * contents,int from_index,int to_index)2803 void Browser::TabMoved(TabContentsWrapper* contents,
2804 int from_index,
2805 int to_index) {
2806 DCHECK(from_index >= 0 && to_index >= 0);
2807 // Notify the history service.
2808 SyncHistoryWithTabs(std::min(from_index, to_index));
2809 }
2810
TabReplacedAt(TabStripModel * tab_strip_model,TabContentsWrapper * old_contents,TabContentsWrapper * new_contents,int index)2811 void Browser::TabReplacedAt(TabStripModel* tab_strip_model,
2812 TabContentsWrapper* old_contents,
2813 TabContentsWrapper* new_contents,
2814 int index) {
2815 TabDetachedAtImpl(old_contents, index, DETACH_TYPE_REPLACE);
2816 TabInsertedAt(new_contents, index,
2817 (index == tab_handler_->GetTabStripModel()->active_index()));
2818
2819 int entry_count = new_contents->controller().entry_count();
2820 if (entry_count > 0) {
2821 // Send out notification so that observers are updated appropriately.
2822 new_contents->controller().NotifyEntryChanged(
2823 new_contents->controller().GetEntryAtIndex(entry_count - 1),
2824 entry_count - 1);
2825 }
2826
2827 SessionService* session_service = profile()->GetSessionService();
2828 if (session_service) {
2829 // The new_contents may end up with a different navigation stack. Force
2830 // the session service to update itself.
2831 session_service->TabRestored(
2832 &new_contents->controller(),
2833 tab_handler_->GetTabStripModel()->IsTabPinned(index));
2834 }
2835
2836 DevToolsManager* devtools_manager = DevToolsManager::GetInstance();
2837 if (devtools_manager) // NULL in unit tests.
2838 devtools_manager->TabReplaced(old_contents, new_contents);
2839 }
2840
TabPinnedStateChanged(TabContentsWrapper * contents,int index)2841 void Browser::TabPinnedStateChanged(TabContentsWrapper* contents, int index) {
2842 if (!profile()->HasSessionService())
2843 return;
2844 SessionService* session_service = profile()->GetSessionService();
2845 if (session_service) {
2846 session_service->SetPinnedState(
2847 session_id(),
2848 GetTabContentsAt(index)->controller().session_id(),
2849 tab_handler_->GetTabStripModel()->IsTabPinned(index));
2850 }
2851 }
2852
TabStripEmpty()2853 void Browser::TabStripEmpty() {
2854 // Close the frame after we return to the message loop (not immediately,
2855 // otherwise it will destroy this object before the stack has a chance to
2856 // cleanly unwind.)
2857 // Note: This will be called several times if TabStripEmpty is called several
2858 // times. This is because it does not close the window if tabs are
2859 // still present.
2860 // NOTE: If you change to be immediate (no invokeLater) then you'll need to
2861 // update BrowserList::CloseAllBrowsers.
2862 MessageLoop::current()->PostTask(
2863 FROM_HERE, method_factory_.NewRunnableMethod(&Browser::CloseFrame));
2864 }
2865
2866 ///////////////////////////////////////////////////////////////////////////////
2867 // Browser, TabContentsDelegate implementation:
2868
OpenURLFromTab(TabContents * source,const GURL & url,const GURL & referrer,WindowOpenDisposition disposition,PageTransition::Type transition)2869 void Browser::OpenURLFromTab(TabContents* source,
2870 const GURL& url,
2871 const GURL& referrer,
2872 WindowOpenDisposition disposition,
2873 PageTransition::Type transition) {
2874 browser::NavigateParams params(this, url, transition);
2875 params.source_contents =
2876 tabstrip_model()->GetTabContentsAt(
2877 tabstrip_model()->GetWrapperIndex(source));
2878 params.referrer = referrer;
2879 params.disposition = disposition;
2880 params.tabstrip_add_types = TabStripModel::ADD_NONE;
2881 params.window_action = browser::NavigateParams::SHOW_WINDOW;
2882 browser::Navigate(¶ms);
2883 }
2884
NavigationStateChanged(const TabContents * source,unsigned changed_flags)2885 void Browser::NavigationStateChanged(const TabContents* source,
2886 unsigned changed_flags) {
2887 // Only update the UI when something visible has changed.
2888 if (changed_flags)
2889 ScheduleUIUpdate(source, changed_flags);
2890
2891 // We don't schedule updates to commands since they will only change once per
2892 // navigation, so we don't have to worry about flickering.
2893 if (changed_flags & TabContents::INVALIDATE_URL)
2894 UpdateCommandsForTabState();
2895 }
2896
AddNewContents(TabContents * source,TabContents * new_contents,WindowOpenDisposition disposition,const gfx::Rect & initial_pos,bool user_gesture)2897 void Browser::AddNewContents(TabContents* source,
2898 TabContents* new_contents,
2899 WindowOpenDisposition disposition,
2900 const gfx::Rect& initial_pos,
2901 bool user_gesture) {
2902 // No code for this yet
2903 DCHECK(disposition != SAVE_TO_DISK);
2904 // Can't create a new contents for the current tab - invalid case.
2905 DCHECK(disposition != CURRENT_TAB);
2906
2907 // TODO(beng): This belongs behind the platform-specific View interface.
2908 // That's why it's there. http://crbug.com/78853
2909 #if defined(OS_CHROMEOS)
2910 if (disposition == NEW_POPUP) {
2911 // If the popup is bigger than a given factor of the screen, then
2912 // turn it into a foreground tab (on chrome os only)
2913 // Also check for width or height == 0, which would otherwise indicate
2914 // a tab sized popup window.
2915 GdkScreen* screen = gdk_screen_get_default();
2916 int max_width = gdk_screen_get_width(screen) * kPopupMaxWidthFactor;
2917 int max_height = gdk_screen_get_height(screen) * kPopupMaxHeightFactor;
2918 if (initial_pos.width() > max_width || initial_pos.width() == 0 ||
2919 initial_pos.height() > max_height || initial_pos.height() == 0) {
2920 disposition = NEW_FOREGROUND_TAB;
2921 }
2922 }
2923 #endif
2924
2925 TabContentsWrapper* wrapper = new TabContentsWrapper(new_contents);
2926 browser::NavigateParams params(this, wrapper);
2927 params.source_contents =
2928 tabstrip_model()->GetTabContentsAt(
2929 tabstrip_model()->GetWrapperIndex(source));
2930 params.disposition = disposition;
2931 params.window_bounds = initial_pos;
2932 // If we create a popup or panel from a non user-gesture, don't activate
2933 // the new window / panel.
2934 if (disposition == NEW_POPUP && !user_gesture)
2935 params.window_action = browser::NavigateParams::SHOW_WINDOW_INACTIVE;
2936 else
2937 params.window_action = browser::NavigateParams::SHOW_WINDOW;
2938 browser::Navigate(¶ms);
2939 }
2940
ActivateContents(TabContents * contents)2941 void Browser::ActivateContents(TabContents* contents) {
2942 tab_handler_->GetTabStripModel()->ActivateTabAt(
2943 tab_handler_->GetTabStripModel()->GetWrapperIndex(contents), false);
2944 window_->Activate();
2945 }
2946
DeactivateContents(TabContents * contents)2947 void Browser::DeactivateContents(TabContents* contents) {
2948 window_->Deactivate();
2949 }
2950
LoadingStateChanged(TabContents * source)2951 void Browser::LoadingStateChanged(TabContents* source) {
2952 window_->UpdateLoadingAnimations(
2953 tab_handler_->GetTabStripModel()->TabsAreLoading());
2954 window_->UpdateTitleBar();
2955
2956 TabContents* selected_contents = GetSelectedTabContents();
2957 if (source == selected_contents) {
2958 UpdateReloadStopState(source->is_loading(), false);
2959 if (GetStatusBubble()) {
2960 GetStatusBubble()->SetStatus(
2961 GetSelectedTabContentsWrapper()->GetStatusText());
2962 }
2963
2964 if (!source->is_loading() &&
2965 pending_web_app_action_ == UPDATE_SHORTCUT) {
2966 // Schedule a shortcut update when web application info is available if
2967 // last committed entry is not NULL. Last committed entry could be NULL
2968 // when an interstitial page is injected (e.g. bad https certificate,
2969 // malware site etc). When this happens, we abort the shortcut update.
2970 NavigationEntry* entry = source->controller().GetLastCommittedEntry();
2971 if (entry) {
2972 TabContentsWrapper::GetCurrentWrapperForContents(source)->
2973 extension_tab_helper()->GetApplicationInfo(entry->page_id());
2974 } else {
2975 pending_web_app_action_ = NONE;
2976 }
2977 }
2978 }
2979 }
2980
CloseContents(TabContents * source)2981 void Browser::CloseContents(TabContents* source) {
2982 if (is_attempting_to_close_browser_) {
2983 // If we're trying to close the browser, just clear the state related to
2984 // waiting for unload to fire. Don't actually try to close the tab as it
2985 // will go down the slow shutdown path instead of the fast path of killing
2986 // all the renderer processes.
2987 ClearUnloadState(source, true);
2988 return;
2989 }
2990
2991 int index = tab_handler_->GetTabStripModel()->GetWrapperIndex(source);
2992 if (index == TabStripModel::kNoTab) {
2993 NOTREACHED() << "CloseContents called for tab not in our strip";
2994 return;
2995 }
2996 tab_handler_->GetTabStripModel()->CloseTabContentsAt(
2997 index,
2998 TabStripModel::CLOSE_CREATE_HISTORICAL_TAB);
2999 }
3000
MoveContents(TabContents * source,const gfx::Rect & pos)3001 void Browser::MoveContents(TabContents* source, const gfx::Rect& pos) {
3002 if ((type() & TYPE_POPUP) == 0) {
3003 NOTREACHED() << "moving invalid browser type";
3004 return;
3005 }
3006 window_->SetBounds(pos);
3007 }
3008
DetachContents(TabContents * source)3009 void Browser::DetachContents(TabContents* source) {
3010 int index = tab_handler_->GetTabStripModel()->GetWrapperIndex(source);
3011 if (index >= 0)
3012 tab_handler_->GetTabStripModel()->DetachTabContentsAt(index);
3013 }
3014
IsPopup(const TabContents * source) const3015 bool Browser::IsPopup(const TabContents* source) const {
3016 // A non-tabbed BROWSER is an unconstrained popup.
3017 return !!(type() & TYPE_POPUP);
3018 }
3019
ContentsMouseEvent(TabContents * source,const gfx::Point & location,bool motion)3020 void Browser::ContentsMouseEvent(
3021 TabContents* source, const gfx::Point& location, bool motion) {
3022 if (!GetStatusBubble())
3023 return;
3024
3025 if (source == GetSelectedTabContents()) {
3026 GetStatusBubble()->MouseMoved(location, !motion);
3027 if (!motion)
3028 GetStatusBubble()->SetURL(GURL(), string16());
3029 }
3030 }
3031
UpdateTargetURL(TabContents * source,const GURL & url)3032 void Browser::UpdateTargetURL(TabContents* source, const GURL& url) {
3033 if (!GetStatusBubble())
3034 return;
3035
3036 if (source == GetSelectedTabContents()) {
3037 PrefService* prefs = profile_->GetPrefs();
3038 GetStatusBubble()->SetURL(
3039 url, UTF8ToUTF16(prefs->GetString(prefs::kAcceptLanguages)));
3040 }
3041 }
3042
UpdateDownloadShelfVisibility(bool visible)3043 void Browser::UpdateDownloadShelfVisibility(bool visible) {
3044 if (GetStatusBubble())
3045 GetStatusBubble()->UpdateDownloadShelfVisibility(visible);
3046 }
3047
UseVerticalTabs() const3048 bool Browser::UseVerticalTabs() const {
3049 return use_vertical_tabs_.GetValue();
3050 }
3051
ContentsZoomChange(bool zoom_in)3052 void Browser::ContentsZoomChange(bool zoom_in) {
3053 ExecuteCommand(zoom_in ? IDC_ZOOM_PLUS : IDC_ZOOM_MINUS);
3054 }
3055
OnContentSettingsChange(TabContents * source)3056 void Browser::OnContentSettingsChange(TabContents* source) {
3057 if (source == GetSelectedTabContents()) {
3058 LocationBar* location_bar = window()->GetLocationBar();
3059 if (location_bar)
3060 location_bar->UpdateContentSettingsIcons();
3061 }
3062 }
3063
SetTabContentBlocked(TabContents * contents,bool blocked)3064 void Browser::SetTabContentBlocked(TabContents* contents, bool blocked) {
3065 int index = tabstrip_model()->GetWrapperIndex(contents);
3066 if (index == TabStripModel::kNoTab) {
3067 NOTREACHED();
3068 return;
3069 }
3070 tabstrip_model()->SetTabBlocked(index, blocked);
3071 }
3072
TabContentsFocused(TabContents * tab_content)3073 void Browser::TabContentsFocused(TabContents* tab_content) {
3074 window_->TabContentsFocused(tab_content);
3075 }
3076
TakeFocus(bool reverse)3077 bool Browser::TakeFocus(bool reverse) {
3078 NotificationService::current()->Notify(
3079 NotificationType::FOCUS_RETURNED_TO_BROWSER,
3080 Source<Browser>(this),
3081 NotificationService::NoDetails());
3082 return false;
3083 }
3084
IsApplication() const3085 bool Browser::IsApplication() const {
3086 return (type_ & TYPE_APP) != 0;
3087 }
3088
ConvertContentsToApplication(TabContents * contents)3089 void Browser::ConvertContentsToApplication(TabContents* contents) {
3090 const GURL& url = contents->controller().GetActiveEntry()->url();
3091 std::string app_name = web_app::GenerateApplicationNameFromURL(url);
3092 RegisterAppPrefs(app_name, contents->profile());
3093
3094 DetachContents(contents);
3095 Browser* app_browser = Browser::CreateForApp(
3096 app_name, gfx::Size(), profile_, false);
3097 TabContentsWrapper* wrapper = new TabContentsWrapper(contents);
3098 app_browser->tabstrip_model()->AppendTabContents(wrapper, true);
3099
3100 contents->GetMutableRendererPrefs()->can_accept_load_drops = false;
3101 contents->render_view_host()->SyncRendererPrefs();
3102 app_browser->window()->Show();
3103 }
3104
ShouldDisplayURLField()3105 bool Browser::ShouldDisplayURLField() {
3106 return !IsApplication();
3107 }
3108
BeforeUnloadFired(TabContents * tab,bool proceed,bool * proceed_to_fire_unload)3109 void Browser::BeforeUnloadFired(TabContents* tab,
3110 bool proceed,
3111 bool* proceed_to_fire_unload) {
3112 if (!is_attempting_to_close_browser_) {
3113 *proceed_to_fire_unload = proceed;
3114 if (!proceed)
3115 tab->set_closed_by_user_gesture(false);
3116 return;
3117 }
3118
3119 if (!proceed) {
3120 CancelWindowClose();
3121 *proceed_to_fire_unload = false;
3122 tab->set_closed_by_user_gesture(false);
3123 return;
3124 }
3125
3126 if (RemoveFromSet(&tabs_needing_before_unload_fired_, tab)) {
3127 // Now that beforeunload has fired, put the tab on the queue to fire
3128 // unload.
3129 tabs_needing_unload_fired_.insert(tab);
3130 ProcessPendingTabs();
3131 // We want to handle firing the unload event ourselves since we want to
3132 // fire all the beforeunload events before attempting to fire the unload
3133 // events should the user cancel closing the browser.
3134 *proceed_to_fire_unload = false;
3135 return;
3136 }
3137
3138 *proceed_to_fire_unload = true;
3139 }
3140
ShowHtmlDialog(HtmlDialogUIDelegate * delegate,gfx::NativeWindow parent_window)3141 void Browser::ShowHtmlDialog(HtmlDialogUIDelegate* delegate,
3142 gfx::NativeWindow parent_window) {
3143 window_->ShowHTMLDialog(delegate, parent_window);
3144 }
3145
SetFocusToLocationBar(bool select_all)3146 void Browser::SetFocusToLocationBar(bool select_all) {
3147 // Two differences between this and FocusLocationBar():
3148 // (1) This doesn't get recorded in user metrics, since it's called
3149 // internally.
3150 // (2) This checks whether the location bar can be focused, and if not, clears
3151 // the focus. FocusLocationBar() is only reached when the location bar is
3152 // focusable, but this may be reached at other times, e.g. while in
3153 // fullscreen mode, where we need to leave focus in a consistent state.
3154 window_->SetFocusToLocationBar(select_all);
3155 }
3156
RenderWidgetShowing()3157 void Browser::RenderWidgetShowing() {
3158 window_->DisableInactiveFrame();
3159 }
3160
GetExtraRenderViewHeight() const3161 int Browser::GetExtraRenderViewHeight() const {
3162 return window_->GetExtraRenderViewHeight();
3163 }
3164
OnStartDownload(DownloadItem * download,TabContents * tab)3165 void Browser::OnStartDownload(DownloadItem* download, TabContents* tab) {
3166 if (!window())
3167 return;
3168
3169 #if defined(OS_CHROMEOS)
3170 // Don't show content browser for extension/theme downloads from gallery.
3171 if (download->is_extension_install()) {
3172 ExtensionService* service = profile_->GetExtensionService();
3173 if (service && service->IsDownloadFromGallery(download->url(),
3174 download->referrer_url())) {
3175 return;
3176 }
3177 }
3178 // Open the Active Downloads ui for chromeos.
3179 ActiveDownloadsUI::OpenPopup(profile_);
3180 #else
3181 // GetDownloadShelf creates the download shelf if it was not yet created.
3182 window()->GetDownloadShelf()->AddDownload(new DownloadItemModel(download));
3183
3184 // Don't show the animation for "Save file" downloads.
3185 if (download->total_bytes() <= 0)
3186 return;
3187
3188 // For non-theme extensions, we don't show the download animation.
3189 if (download->is_extension_install() &&
3190 !ExtensionService::IsDownloadFromMiniGallery(download->url()))
3191 return;
3192
3193 TabContents* current_tab = GetSelectedTabContents();
3194 // We make this check for the case of minimized windows, unit tests, etc.
3195 if (platform_util::IsVisible(current_tab->GetNativeView()) &&
3196 ui::Animation::ShouldRenderRichAnimation()) {
3197 DownloadStartedAnimation::Show(current_tab);
3198 }
3199 #endif
3200
3201 // If the download occurs in a new tab, close it
3202 if (tab->controller().IsInitialNavigation() &&
3203 GetConstrainingContents(tab) == tab && tab_count() > 1) {
3204 CloseContents(tab);
3205 }
3206 }
3207
ShowPageInfo(Profile * profile,const GURL & url,const NavigationEntry::SSLStatus & ssl,bool show_history)3208 void Browser::ShowPageInfo(Profile* profile,
3209 const GURL& url,
3210 const NavigationEntry::SSLStatus& ssl,
3211 bool show_history) {
3212 window()->ShowPageInfo(profile, url, ssl, show_history);
3213 }
3214
ViewSourceForTab(TabContents * source,const GURL & page_url)3215 void Browser::ViewSourceForTab(TabContents* source, const GURL& page_url) {
3216 DCHECK(source);
3217 int index = tabstrip_model()->GetWrapperIndex(source);
3218 TabContentsWrapper* wrapper = tabstrip_model()->GetTabContentsAt(index);
3219 ViewSource(wrapper);
3220 }
3221
ViewSourceForFrame(TabContents * source,const GURL & frame_url,const std::string & frame_content_state)3222 void Browser::ViewSourceForFrame(TabContents* source,
3223 const GURL& frame_url,
3224 const std::string& frame_content_state) {
3225 DCHECK(source);
3226 int index = tabstrip_model()->GetWrapperIndex(source);
3227 TabContentsWrapper* wrapper = tabstrip_model()->GetTabContentsAt(index);
3228 ViewSource(wrapper, frame_url, frame_content_state);
3229 }
3230
PreHandleKeyboardEvent(const NativeWebKeyboardEvent & event,bool * is_keyboard_shortcut)3231 bool Browser::PreHandleKeyboardEvent(const NativeWebKeyboardEvent& event,
3232 bool* is_keyboard_shortcut) {
3233 return window()->PreHandleKeyboardEvent(event, is_keyboard_shortcut);
3234 }
3235
HandleKeyboardEvent(const NativeWebKeyboardEvent & event)3236 void Browser::HandleKeyboardEvent(const NativeWebKeyboardEvent& event) {
3237 window()->HandleKeyboardEvent(event);
3238 }
3239
ShowRepostFormWarningDialog(TabContents * tab_contents)3240 void Browser::ShowRepostFormWarningDialog(TabContents *tab_contents) {
3241 window()->ShowRepostFormWarningDialog(tab_contents);
3242 }
3243
ShowContentSettingsPage(ContentSettingsType content_type)3244 void Browser::ShowContentSettingsPage(ContentSettingsType content_type) {
3245 ShowOptionsTab(
3246 chrome::kContentSettingsExceptionsSubPage + std::string(kHashMark) +
3247 ContentSettingsHandler::ContentSettingsTypeToGroupName(content_type));
3248 }
3249
ShowCollectedCookiesDialog(TabContents * tab_contents)3250 void Browser::ShowCollectedCookiesDialog(TabContents *tab_contents) {
3251 window()->ShowCollectedCookiesDialog(tab_contents);
3252 }
3253
ShouldAddNavigationToHistory(const history::HistoryAddPageArgs & add_page_args,NavigationType::Type navigation_type)3254 bool Browser::ShouldAddNavigationToHistory(
3255 const history::HistoryAddPageArgs& add_page_args,
3256 NavigationType::Type navigation_type) {
3257 // Don't update history if running as app.
3258 return !IsApplication();
3259 }
3260
ContentRestrictionsChanged(TabContents * source)3261 void Browser::ContentRestrictionsChanged(TabContents* source) {
3262 UpdateCommandsForContentRestrictionState();
3263 }
3264
WorkerCrashed()3265 void Browser::WorkerCrashed() {
3266 TabContents* tab_contents = GetSelectedTabContents();
3267 if (!tab_contents)
3268 return;
3269 tab_contents->AddInfoBar(new SimpleAlertInfoBarDelegate(tab_contents, NULL,
3270 l10n_util::GetStringUTF16(IDS_WEBWORKER_CRASHED_PROMPT), true));
3271 }
3272
3273 ///////////////////////////////////////////////////////////////////////////////
3274 // Browser, TabContentsWrapperDelegate implementation:
3275
URLStarredChanged(TabContentsWrapper * source,bool starred)3276 void Browser::URLStarredChanged(TabContentsWrapper* source, bool starred) {
3277 if (source == GetSelectedTabContentsWrapper())
3278 window_->SetStarredState(starred);
3279 }
3280
OnDidGetApplicationInfo(TabContentsWrapper * source,int32 page_id)3281 void Browser::OnDidGetApplicationInfo(TabContentsWrapper* source,
3282 int32 page_id) {
3283 if (GetSelectedTabContentsWrapper() != source)
3284 return;
3285
3286 NavigationEntry* entry = source->controller().GetLastCommittedEntry();
3287 if (!entry || (entry->page_id() != page_id))
3288 return;
3289
3290 switch (pending_web_app_action_) {
3291 case CREATE_SHORTCUT: {
3292 window()->ShowCreateWebAppShortcutsDialog(source);
3293 break;
3294 }
3295 case UPDATE_SHORTCUT: {
3296 web_app::UpdateShortcutForTabContents(source);
3297 break;
3298 }
3299 default:
3300 NOTREACHED();
3301 break;
3302 }
3303
3304 pending_web_app_action_ = NONE;
3305 }
3306
OnInstallApplication(TabContentsWrapper * source,const WebApplicationInfo & web_app)3307 void Browser::OnInstallApplication(TabContentsWrapper* source,
3308 const WebApplicationInfo& web_app) {
3309 ExtensionService* extensions_service = profile()->GetExtensionService();
3310 if (!extensions_service)
3311 return;
3312
3313 scoped_refptr<CrxInstaller> installer(
3314 new CrxInstaller(extensions_service,
3315 extensions_service->show_extensions_prompts() ?
3316 new ExtensionInstallUI(profile()) : NULL));
3317 installer->InstallWebApp(web_app);
3318 }
3319
3320 ///////////////////////////////////////////////////////////////////////////////
3321 // Browser, SearchEngineTabHelperDelegate implementation:
3322
ConfirmSetDefaultSearchProvider(TabContents * tab_contents,TemplateURL * template_url,TemplateURLModel * template_url_model)3323 void Browser::ConfirmSetDefaultSearchProvider(
3324 TabContents* tab_contents,
3325 TemplateURL* template_url,
3326 TemplateURLModel* template_url_model) {
3327 window()->ConfirmSetDefaultSearchProvider(tab_contents, template_url,
3328 template_url_model);
3329 }
3330
ConfirmAddSearchProvider(const TemplateURL * template_url,Profile * profile)3331 void Browser::ConfirmAddSearchProvider(const TemplateURL* template_url,
3332 Profile* profile) {
3333 window()->ConfirmAddSearchProvider(template_url, profile);
3334 }
3335
3336 ///////////////////////////////////////////////////////////////////////////////
3337 // Browser, SelectFileDialog::Listener implementation:
3338
FileSelected(const FilePath & path,int index,void * params)3339 void Browser::FileSelected(const FilePath& path, int index, void* params) {
3340 profile_->set_last_selected_directory(path.DirName());
3341 GURL file_url = net::FilePathToFileURL(path);
3342 if (!file_url.is_empty())
3343 OpenURL(file_url, GURL(), CURRENT_TAB, PageTransition::TYPED);
3344 }
3345
3346 ///////////////////////////////////////////////////////////////////////////////
3347 // Browser, NotificationObserver implementation:
3348
Observe(NotificationType type,const NotificationSource & source,const NotificationDetails & details)3349 void Browser::Observe(NotificationType type,
3350 const NotificationSource& source,
3351 const NotificationDetails& details) {
3352 switch (type.value) {
3353 case NotificationType::TAB_CONTENTS_DISCONNECTED:
3354 if (is_attempting_to_close_browser_) {
3355 // Pass in false so that we delay processing. We need to delay the
3356 // processing as it may close the tab, which is currently on the call
3357 // stack above us.
3358 ClearUnloadState(Source<TabContents>(source).ptr(), false);
3359 }
3360 break;
3361
3362 case NotificationType::SSL_VISIBLE_STATE_CHANGED:
3363 // When the current tab's SSL state changes, we need to update the URL
3364 // bar to reflect the new state. Note that it's possible for the selected
3365 // tab contents to be NULL. This is because we listen for all sources
3366 // (NavigationControllers) for convenience, so the notification could
3367 // actually be for a different window while we're doing asynchronous
3368 // closing of this one.
3369 if (GetSelectedTabContents() &&
3370 &GetSelectedTabContents()->controller() ==
3371 Source<NavigationController>(source).ptr())
3372 UpdateToolbar(false);
3373 break;
3374
3375 case NotificationType::EXTENSION_UPDATE_DISABLED: {
3376 // Show the UI if the extension was disabled for escalated permissions.
3377 Profile* profile = Source<Profile>(source).ptr();
3378 if (profile_->IsSameProfile(profile)) {
3379 ExtensionService* service = profile->GetExtensionService();
3380 DCHECK(service);
3381 const Extension* extension = Details<const Extension>(details).ptr();
3382 if (service->extension_prefs()->DidExtensionEscalatePermissions(
3383 extension->id()))
3384 ShowExtensionDisabledUI(service, profile_, extension);
3385 }
3386 break;
3387 }
3388
3389 case NotificationType::EXTENSION_UNLOADED: {
3390 window()->GetLocationBar()->UpdatePageActions();
3391
3392 // Close any tabs from the unloaded extension.
3393 const Extension* extension =
3394 Details<UnloadedExtensionInfo>(details)->extension;
3395 TabStripModel* model = tab_handler_->GetTabStripModel();
3396 for (int i = model->count() - 1; i >= 0; --i) {
3397 TabContents* tc = model->GetTabContentsAt(i)->tab_contents();
3398 if (tc->GetURL().SchemeIs(chrome::kExtensionScheme) &&
3399 tc->GetURL().host() == extension->id()) {
3400 CloseTabContents(tc);
3401 }
3402 }
3403
3404 break;
3405 }
3406
3407 case NotificationType::EXTENSION_PROCESS_TERMINATED: {
3408 window()->GetLocationBar()->InvalidatePageActions();
3409 break;
3410 }
3411
3412 case NotificationType::EXTENSION_UNINSTALLED:
3413 case NotificationType::EXTENSION_LOADED:
3414 window()->GetLocationBar()->UpdatePageActions();
3415 break;
3416
3417 case NotificationType::BROWSER_THEME_CHANGED:
3418 window()->UserChangedTheme();
3419 break;
3420
3421 case NotificationType::EXTENSION_READY_FOR_INSTALL: {
3422 // Handle EXTENSION_READY_FOR_INSTALL for last active normal browser.
3423 if (BrowserList::FindBrowserWithType(profile(),
3424 Browser::TYPE_NORMAL,
3425 true) != this)
3426 break;
3427
3428 // We only want to show the loading dialog for themes, but we don't want
3429 // to wait until unpack to find out an extension is a theme, so we test
3430 // the download_url GURL instead. This means that themes in the extensions
3431 // gallery won't get the loading dialog.
3432 GURL download_url = *(Details<GURL>(details).ptr());
3433 if (ExtensionService::IsDownloadFromMiniGallery(download_url))
3434 window()->ShowThemeInstallBubble();
3435 break;
3436 }
3437
3438 case NotificationType::PREF_CHANGED: {
3439 const std::string& pref_name = *Details<std::string>(details).ptr();
3440 if (pref_name == prefs::kUseVerticalTabs) {
3441 UseVerticalTabsChanged();
3442 } else if (pref_name == prefs::kPrintingEnabled) {
3443 UpdatePrintingState(0);
3444 } else if (pref_name == prefs::kInstantEnabled) {
3445 if (!InstantController::IsEnabled(profile())) {
3446 if (instant()) {
3447 instant()->DestroyPreviewContents();
3448 instant_.reset();
3449 instant_unload_handler_.reset();
3450 }
3451 } else {
3452 CreateInstantIfNecessary();
3453 }
3454 } else if (pref_name == prefs::kDevToolsDisabled) {
3455 UpdateCommandsForDevTools();
3456 if (dev_tools_disabled_.GetValue())
3457 g_browser_process->devtools_manager()->CloseAllClientHosts();
3458 } else if (pref_name == prefs::kIncognitoEnabled) {
3459 break; // No further action is required.
3460 } else if (pref_name == prefs::kEditBookmarksEnabled) {
3461 UpdateCommandsForBookmarkEditing();
3462 } else {
3463 NOTREACHED();
3464 }
3465 break;
3466 }
3467
3468 default:
3469 NOTREACHED() << "Got a notification we didn't register for.";
3470 }
3471 }
3472
3473 ///////////////////////////////////////////////////////////////////////////////
3474 // Browser, ProfileSyncServiceObserver implementation:
3475
OnStateChanged()3476 void Browser::OnStateChanged() {
3477 DCHECK(profile_->GetProfileSyncService());
3478
3479 #if !defined(OS_MACOSX)
3480 const bool show_main_ui = (type() == TYPE_NORMAL) && !window_->IsFullscreen();
3481 #else
3482 const bool show_main_ui = (type() == TYPE_NORMAL);
3483 #endif
3484
3485 command_updater_.UpdateCommandEnabled(IDC_SYNC_BOOKMARKS,
3486 show_main_ui && profile_->IsSyncAccessible());
3487 }
3488
3489 ///////////////////////////////////////////////////////////////////////////////
3490 // Browser, InstantDelegate implementation:
3491
PrepareForInstant()3492 void Browser::PrepareForInstant() {
3493 window_->PrepareForInstant();
3494 }
3495
ShowInstant(TabContentsWrapper * preview_contents)3496 void Browser::ShowInstant(TabContentsWrapper* preview_contents) {
3497 DCHECK(instant_->tab_contents() == GetSelectedTabContentsWrapper());
3498 window_->ShowInstant(preview_contents);
3499 }
3500
HideInstant()3501 void Browser::HideInstant() {
3502 window_->HideInstant(instant_->is_active());
3503 }
3504
CommitInstant(TabContentsWrapper * preview_contents)3505 void Browser::CommitInstant(TabContentsWrapper* preview_contents) {
3506 TabContentsWrapper* tab_contents = instant_->tab_contents();
3507 int index =
3508 tab_handler_->GetTabStripModel()->GetIndexOfTabContents(tab_contents);
3509 DCHECK_NE(TabStripModel::kNoTab, index);
3510 // TabStripModel takes ownership of preview_contents.
3511 tab_handler_->GetTabStripModel()->ReplaceTabContentsAt(
3512 index, preview_contents);
3513 // InstantUnloadHandler takes ownership of tab_contents.
3514 instant_unload_handler_->RunUnloadListenersOrDestroy(tab_contents, index);
3515
3516 GURL url = preview_contents->tab_contents()->GetURL();
3517 DCHECK(profile_->GetExtensionService());
3518 if (profile_->GetExtensionService()->IsInstalledApp(url)) {
3519 UMA_HISTOGRAM_ENUMERATION(extension_misc::kAppLaunchHistogram,
3520 extension_misc::APP_LAUNCH_OMNIBOX_INSTANT,
3521 extension_misc::APP_LAUNCH_BUCKET_BOUNDARY);
3522 }
3523 }
3524
SetSuggestedText(const string16 & text,InstantCompleteBehavior behavior)3525 void Browser::SetSuggestedText(const string16& text,
3526 InstantCompleteBehavior behavior) {
3527 window()->GetLocationBar()->SetSuggestedText(text, behavior);
3528 }
3529
GetInstantBounds()3530 gfx::Rect Browser::GetInstantBounds() {
3531 return window()->GetInstantBounds();
3532 }
3533
3534 ///////////////////////////////////////////////////////////////////////////////
3535 // Browser, protected:
3536
CreateBrowserWindow()3537 BrowserWindow* Browser::CreateBrowserWindow() {
3538 if (type() == Browser::TYPE_APP_PANEL &&
3539 CommandLine::ForCurrentProcess()->HasSwitch(switches::kEnablePanels))
3540 return PanelManager::GetInstance()->CreatePanel(this);
3541
3542 return BrowserWindow::CreateBrowserWindow(this);
3543 }
3544
3545
3546 ///////////////////////////////////////////////////////////////////////////////
3547 // Browser, Command and state updating (private):
3548
InitCommandState()3549 void Browser::InitCommandState() {
3550 // All browser commands whose state isn't set automagically some other way
3551 // (like Back & Forward with initial page load) must have their state
3552 // initialized here, otherwise they will be forever disabled.
3553
3554 // Navigation commands
3555 command_updater_.UpdateCommandEnabled(IDC_RELOAD, true);
3556 command_updater_.UpdateCommandEnabled(IDC_RELOAD_IGNORING_CACHE, true);
3557
3558 // Window management commands
3559 command_updater_.UpdateCommandEnabled(IDC_NEW_WINDOW, true);
3560 command_updater_.UpdateCommandEnabled(IDC_NEW_INCOGNITO_WINDOW,
3561 incognito_mode_allowed_.GetValue());
3562 command_updater_.UpdateCommandEnabled(IDC_CLOSE_WINDOW, true);
3563 command_updater_.UpdateCommandEnabled(IDC_NEW_TAB, true);
3564 command_updater_.UpdateCommandEnabled(IDC_CLOSE_TAB, true);
3565 command_updater_.UpdateCommandEnabled(IDC_DUPLICATE_TAB, true);
3566 command_updater_.UpdateCommandEnabled(IDC_RESTORE_TAB, false);
3567 command_updater_.UpdateCommandEnabled(IDC_EXIT, true);
3568 command_updater_.UpdateCommandEnabled(IDC_TOGGLE_VERTICAL_TABS, true);
3569
3570 // Page-related commands
3571 command_updater_.UpdateCommandEnabled(IDC_EMAIL_PAGE_LOCATION, true);
3572 command_updater_.UpdateCommandEnabled(IDC_ENCODING_AUTO_DETECT, true);
3573 command_updater_.UpdateCommandEnabled(IDC_ENCODING_UTF8, true);
3574 command_updater_.UpdateCommandEnabled(IDC_ENCODING_UTF16LE, true);
3575 command_updater_.UpdateCommandEnabled(IDC_ENCODING_ISO88591, true);
3576 command_updater_.UpdateCommandEnabled(IDC_ENCODING_WINDOWS1252, true);
3577 command_updater_.UpdateCommandEnabled(IDC_ENCODING_GBK, true);
3578 command_updater_.UpdateCommandEnabled(IDC_ENCODING_GB18030, true);
3579 command_updater_.UpdateCommandEnabled(IDC_ENCODING_BIG5HKSCS, true);
3580 command_updater_.UpdateCommandEnabled(IDC_ENCODING_BIG5, true);
3581 command_updater_.UpdateCommandEnabled(IDC_ENCODING_THAI, true);
3582 command_updater_.UpdateCommandEnabled(IDC_ENCODING_KOREAN, true);
3583 command_updater_.UpdateCommandEnabled(IDC_ENCODING_SHIFTJIS, true);
3584 command_updater_.UpdateCommandEnabled(IDC_ENCODING_ISO2022JP, true);
3585 command_updater_.UpdateCommandEnabled(IDC_ENCODING_EUCJP, true);
3586 command_updater_.UpdateCommandEnabled(IDC_ENCODING_ISO885915, true);
3587 command_updater_.UpdateCommandEnabled(IDC_ENCODING_MACINTOSH, true);
3588 command_updater_.UpdateCommandEnabled(IDC_ENCODING_ISO88592, true);
3589 command_updater_.UpdateCommandEnabled(IDC_ENCODING_WINDOWS1250, true);
3590 command_updater_.UpdateCommandEnabled(IDC_ENCODING_ISO88595, true);
3591 command_updater_.UpdateCommandEnabled(IDC_ENCODING_WINDOWS1251, true);
3592 command_updater_.UpdateCommandEnabled(IDC_ENCODING_KOI8R, true);
3593 command_updater_.UpdateCommandEnabled(IDC_ENCODING_KOI8U, true);
3594 command_updater_.UpdateCommandEnabled(IDC_ENCODING_ISO88597, true);
3595 command_updater_.UpdateCommandEnabled(IDC_ENCODING_WINDOWS1253, true);
3596 command_updater_.UpdateCommandEnabled(IDC_ENCODING_ISO88594, true);
3597 command_updater_.UpdateCommandEnabled(IDC_ENCODING_ISO885913, true);
3598 command_updater_.UpdateCommandEnabled(IDC_ENCODING_WINDOWS1257, true);
3599 command_updater_.UpdateCommandEnabled(IDC_ENCODING_ISO88593, true);
3600 command_updater_.UpdateCommandEnabled(IDC_ENCODING_ISO885910, true);
3601 command_updater_.UpdateCommandEnabled(IDC_ENCODING_ISO885914, true);
3602 command_updater_.UpdateCommandEnabled(IDC_ENCODING_ISO885916, true);
3603 command_updater_.UpdateCommandEnabled(IDC_ENCODING_WINDOWS1254, true);
3604 command_updater_.UpdateCommandEnabled(IDC_ENCODING_ISO88596, true);
3605 command_updater_.UpdateCommandEnabled(IDC_ENCODING_WINDOWS1256, true);
3606 command_updater_.UpdateCommandEnabled(IDC_ENCODING_ISO88598, true);
3607 command_updater_.UpdateCommandEnabled(IDC_ENCODING_ISO88598I, true);
3608 command_updater_.UpdateCommandEnabled(IDC_ENCODING_WINDOWS1255, true);
3609 command_updater_.UpdateCommandEnabled(IDC_ENCODING_WINDOWS1258, true);
3610
3611 // Zoom
3612 command_updater_.UpdateCommandEnabled(IDC_ZOOM_MENU, true);
3613 command_updater_.UpdateCommandEnabled(IDC_ZOOM_PLUS, true);
3614 command_updater_.UpdateCommandEnabled(IDC_ZOOM_NORMAL, true);
3615 command_updater_.UpdateCommandEnabled(IDC_ZOOM_MINUS, true);
3616
3617 // Show various bits of UI
3618 command_updater_.UpdateCommandEnabled(IDC_OPEN_FILE, true);
3619 command_updater_.UpdateCommandEnabled(IDC_CREATE_SHORTCUTS, false);
3620 UpdateCommandsForDevTools();
3621 command_updater_.UpdateCommandEnabled(IDC_TASK_MANAGER, true);
3622 command_updater_.UpdateCommandEnabled(IDC_SHOW_HISTORY, true);
3623 command_updater_.UpdateCommandEnabled(IDC_SHOW_BOOKMARK_MANAGER,
3624 browser_defaults::bookmarks_enabled);
3625 command_updater_.UpdateCommandEnabled(IDC_SHOW_DOWNLOADS, true);
3626 command_updater_.UpdateCommandEnabled(IDC_HELP_PAGE, true);
3627 command_updater_.UpdateCommandEnabled(IDC_IMPORT_SETTINGS, true);
3628
3629 #if defined(OS_CHROMEOS)
3630 command_updater_.UpdateCommandEnabled(IDC_FILE_MANAGER, true);
3631 command_updater_.UpdateCommandEnabled(IDC_SEARCH, true);
3632 command_updater_.UpdateCommandEnabled(IDC_SHOW_KEYBOARD_OVERLAY, true);
3633 command_updater_.UpdateCommandEnabled(IDC_SYSTEM_OPTIONS, true);
3634 command_updater_.UpdateCommandEnabled(IDC_INTERNET_OPTIONS, true);
3635 #endif
3636
3637 ExtensionService* extensions_service = profile()->GetExtensionService();
3638 bool enable_extensions =
3639 extensions_service && extensions_service->extensions_enabled();
3640 command_updater_.UpdateCommandEnabled(IDC_MANAGE_EXTENSIONS,
3641 enable_extensions);
3642
3643 // Initialize other commands based on the window type.
3644 bool normal_window = type() == TYPE_NORMAL;
3645 bool non_devtools_window = type() != TYPE_DEVTOOLS;
3646
3647 // Navigation commands
3648 command_updater_.UpdateCommandEnabled(IDC_HOME, normal_window);
3649
3650 // Window management commands
3651 command_updater_.UpdateCommandEnabled(IDC_FULLSCREEN,
3652 type() != TYPE_APP_PANEL);
3653 command_updater_.UpdateCommandEnabled(IDC_SELECT_NEXT_TAB, normal_window);
3654 command_updater_.UpdateCommandEnabled(IDC_SELECT_PREVIOUS_TAB,
3655 normal_window);
3656 command_updater_.UpdateCommandEnabled(IDC_MOVE_TAB_NEXT, normal_window);
3657 command_updater_.UpdateCommandEnabled(IDC_MOVE_TAB_PREVIOUS, normal_window);
3658 command_updater_.UpdateCommandEnabled(IDC_SELECT_TAB_0, normal_window);
3659 command_updater_.UpdateCommandEnabled(IDC_SELECT_TAB_1, normal_window);
3660 command_updater_.UpdateCommandEnabled(IDC_SELECT_TAB_2, normal_window);
3661 command_updater_.UpdateCommandEnabled(IDC_SELECT_TAB_3, normal_window);
3662 command_updater_.UpdateCommandEnabled(IDC_SELECT_TAB_4, normal_window);
3663 command_updater_.UpdateCommandEnabled(IDC_SELECT_TAB_5, normal_window);
3664 command_updater_.UpdateCommandEnabled(IDC_SELECT_TAB_6, normal_window);
3665 command_updater_.UpdateCommandEnabled(IDC_SELECT_TAB_7, normal_window);
3666 command_updater_.UpdateCommandEnabled(IDC_SELECT_LAST_TAB, normal_window);
3667 #if defined(OS_MACOSX)
3668 command_updater_.UpdateCommandEnabled(IDC_TABPOSE, normal_window);
3669 #endif
3670
3671 // Clipboard commands
3672 command_updater_.UpdateCommandEnabled(IDC_COPY_URL, non_devtools_window);
3673
3674 // Find-in-page
3675 command_updater_.UpdateCommandEnabled(IDC_FIND, non_devtools_window);
3676 command_updater_.UpdateCommandEnabled(IDC_FIND_NEXT, non_devtools_window);
3677 command_updater_.UpdateCommandEnabled(IDC_FIND_PREVIOUS, non_devtools_window);
3678
3679 // Autofill
3680 command_updater_.UpdateCommandEnabled(IDC_AUTOFILL_DEFAULT,
3681 non_devtools_window);
3682
3683 // Show various bits of UI
3684 command_updater_.UpdateCommandEnabled(IDC_CLEAR_BROWSING_DATA, normal_window);
3685
3686 // The upgrade entry and the view incompatibility entry should always be
3687 // enabled. Whether they are visible is a separate matter determined on menu
3688 // show.
3689 command_updater_.UpdateCommandEnabled(IDC_UPGRADE_DIALOG, true);
3690 command_updater_.UpdateCommandEnabled(IDC_VIEW_INCOMPATIBILITIES, true);
3691
3692 // View Background Pages entry is always enabled, but is hidden if there are
3693 // no background pages.
3694 command_updater_.UpdateCommandEnabled(IDC_VIEW_BACKGROUND_PAGES, true);
3695
3696 // Initialize other commands whose state changes based on fullscreen mode.
3697 UpdateCommandsForFullscreenMode(false);
3698
3699 UpdateCommandsForContentRestrictionState();
3700
3701 UpdateCommandsForBookmarkEditing();
3702 }
3703
UpdateCommandsForTabState()3704 void Browser::UpdateCommandsForTabState() {
3705 TabContents* current_tab = GetSelectedTabContents();
3706 TabContentsWrapper* current_tab_wrapper = GetSelectedTabContentsWrapper();
3707 if (!current_tab || !current_tab_wrapper) // May be NULL during tab restore.
3708 return;
3709
3710 // Navigation commands
3711 NavigationController& nc = current_tab->controller();
3712 command_updater_.UpdateCommandEnabled(IDC_BACK, nc.CanGoBack());
3713 command_updater_.UpdateCommandEnabled(IDC_FORWARD, nc.CanGoForward());
3714 command_updater_.UpdateCommandEnabled(IDC_RELOAD,
3715 CanReloadContents(current_tab));
3716 command_updater_.UpdateCommandEnabled(IDC_RELOAD_IGNORING_CACHE,
3717 CanReloadContents(current_tab));
3718
3719 // Window management commands
3720 bool non_app_window = !(type() & TYPE_APP);
3721 command_updater_.UpdateCommandEnabled(IDC_DUPLICATE_TAB,
3722 non_app_window && CanDuplicateContentsAt(active_index()));
3723
3724 // Page-related commands
3725 window_->SetStarredState(current_tab_wrapper->is_starred());
3726 command_updater_.UpdateCommandEnabled(IDC_VIEW_SOURCE,
3727 current_tab->controller().CanViewSource());
3728 command_updater_.UpdateCommandEnabled(IDC_EMAIL_PAGE_LOCATION,
3729 current_tab->ShouldDisplayURL() && current_tab->GetURL().is_valid());
3730
3731 // Changing the encoding is not possible on Chrome-internal webpages.
3732 // Instead of using GetURL here, we use url() (which is the "real" url of the
3733 // page) from the NavigationEntry because its reflects their origin rather
3734 // than the display one (returned by GetURL) which may be different (like
3735 // having "view-source:" on the front).
3736 NavigationEntry* active_entry = nc.GetActiveEntry();
3737 bool is_chrome_internal = (active_entry ?
3738 active_entry->url().SchemeIs(chrome::kChromeUIScheme) : false);
3739 command_updater_.UpdateCommandEnabled(IDC_ENCODING_MENU,
3740 !is_chrome_internal && SavePackage::IsSavableContents(
3741 current_tab->contents_mime_type()));
3742
3743 // Show various bits of UI
3744 // TODO(pinkerton): Disable app-mode in the model until we implement it
3745 // on the Mac. Be sure to remove both ifdefs. http://crbug.com/13148
3746 #if !defined(OS_MACOSX)
3747 command_updater_.UpdateCommandEnabled(IDC_CREATE_SHORTCUTS,
3748 web_app::IsValidUrl(current_tab->GetURL()));
3749 #endif
3750
3751 UpdateCommandsForContentRestrictionState();
3752 UpdateCommandsForBookmarkEditing();
3753 }
3754
UpdateCommandsForContentRestrictionState()3755 void Browser::UpdateCommandsForContentRestrictionState() {
3756 int restrictions = 0;
3757 TabContents* current_tab = GetSelectedTabContents();
3758 if (current_tab) {
3759 restrictions = current_tab->content_restrictions();
3760 NavigationEntry* active_entry = current_tab->controller().GetActiveEntry();
3761 // See comment in UpdateCommandsForTabState about why we call url().
3762 if (!SavePackage::IsSavableURL(active_entry ? active_entry->url() : GURL()))
3763 restrictions |= CONTENT_RESTRICTION_SAVE;
3764 }
3765
3766 command_updater_.UpdateCommandEnabled(
3767 IDC_COPY, !(restrictions & CONTENT_RESTRICTION_COPY));
3768 command_updater_.UpdateCommandEnabled(
3769 IDC_CUT, !(restrictions & CONTENT_RESTRICTION_CUT));
3770 command_updater_.UpdateCommandEnabled(
3771 IDC_PASTE, !(restrictions & CONTENT_RESTRICTION_PASTE));
3772 command_updater_.UpdateCommandEnabled(
3773 IDC_SAVE_PAGE, !(restrictions & CONTENT_RESTRICTION_SAVE));
3774 UpdatePrintingState(restrictions);
3775 }
3776
UpdatePrintingState(int content_restrictions)3777 void Browser::UpdatePrintingState(int content_restrictions) {
3778 bool enabled = true;
3779 if (content_restrictions & CONTENT_RESTRICTION_PRINT) {
3780 enabled = false;
3781 } else if (g_browser_process->local_state()) {
3782 enabled = printing_enabled_.GetValue();
3783 }
3784 command_updater_.UpdateCommandEnabled(IDC_PRINT, enabled);
3785 }
3786
UpdateReloadStopState(bool is_loading,bool force)3787 void Browser::UpdateReloadStopState(bool is_loading, bool force) {
3788 window_->UpdateReloadStopState(is_loading, force);
3789 command_updater_.UpdateCommandEnabled(IDC_STOP, is_loading);
3790 }
3791
UpdateCommandsForDevTools()3792 void Browser::UpdateCommandsForDevTools() {
3793 bool dev_tools_enabled = !dev_tools_disabled_.GetValue();
3794 command_updater_.UpdateCommandEnabled(IDC_DEV_TOOLS,
3795 dev_tools_enabled);
3796 command_updater_.UpdateCommandEnabled(IDC_DEV_TOOLS_CONSOLE,
3797 dev_tools_enabled);
3798 command_updater_.UpdateCommandEnabled(IDC_DEV_TOOLS_INSPECT,
3799 dev_tools_enabled);
3800 }
3801
UpdateCommandsForBookmarkEditing()3802 void Browser::UpdateCommandsForBookmarkEditing() {
3803 bool enabled = edit_bookmarks_enabled_.GetValue() &&
3804 browser_defaults::bookmarks_enabled;
3805
3806 command_updater_.UpdateCommandEnabled(IDC_BOOKMARK_PAGE,
3807 enabled && type() == TYPE_NORMAL);
3808 command_updater_.UpdateCommandEnabled(IDC_BOOKMARK_ALL_TABS,
3809 enabled && CanBookmarkAllTabs());
3810 }
3811
3812 ///////////////////////////////////////////////////////////////////////////////
3813 // Browser, UI update coalescing and handling (private):
3814
UpdateToolbar(bool should_restore_state)3815 void Browser::UpdateToolbar(bool should_restore_state) {
3816 window_->UpdateToolbar(GetSelectedTabContentsWrapper(), should_restore_state);
3817 }
3818
ScheduleUIUpdate(const TabContents * source,unsigned changed_flags)3819 void Browser::ScheduleUIUpdate(const TabContents* source,
3820 unsigned changed_flags) {
3821 if (!source)
3822 return;
3823
3824 // Do some synchronous updates.
3825 if (changed_flags & TabContents::INVALIDATE_URL &&
3826 source == GetSelectedTabContents()) {
3827 // Only update the URL for the current tab. Note that we do not update
3828 // the navigation commands since those would have already been updated
3829 // synchronously by NavigationStateChanged.
3830 UpdateToolbar(false);
3831 changed_flags &= ~TabContents::INVALIDATE_URL;
3832 }
3833 if (changed_flags & TabContents::INVALIDATE_LOAD) {
3834 // Update the loading state synchronously. This is so the throbber will
3835 // immediately start/stop, which gives a more snappy feel. We want to do
3836 // this for any tab so they start & stop quickly.
3837 tab_handler_->GetTabStripModel()->UpdateTabContentsStateAt(
3838 tab_handler_->GetTabStripModel()->GetIndexOfController(
3839 &source->controller()),
3840 TabStripModelObserver::LOADING_ONLY);
3841 // The status bubble needs to be updated during INVALIDATE_LOAD too, but
3842 // we do that asynchronously by not stripping INVALIDATE_LOAD from
3843 // changed_flags.
3844 }
3845
3846 if (changed_flags & TabContents::INVALIDATE_TITLE && !source->is_loading()) {
3847 // To correctly calculate whether the title changed while not loading
3848 // we need to process the update synchronously. This state only matters for
3849 // the TabStripModel, so we notify the TabStripModel now and notify others
3850 // asynchronously.
3851 tab_handler_->GetTabStripModel()->UpdateTabContentsStateAt(
3852 tab_handler_->GetTabStripModel()->GetIndexOfController(
3853 &source->controller()),
3854 TabStripModelObserver::TITLE_NOT_LOADING);
3855 }
3856
3857 if (changed_flags & TabContents::INVALIDATE_BOOKMARK_BAR) {
3858 window()->ShelfVisibilityChanged();
3859 changed_flags &= ~TabContents::INVALIDATE_BOOKMARK_BAR;
3860 }
3861
3862 // If the only updates were synchronously handled above, we're done.
3863 if (changed_flags == 0)
3864 return;
3865
3866 // Save the dirty bits.
3867 scheduled_updates_[source] |= changed_flags;
3868
3869 if (chrome_updater_factory_.empty()) {
3870 // No task currently scheduled, start another.
3871 MessageLoop::current()->PostDelayedTask(
3872 FROM_HERE,
3873 chrome_updater_factory_.NewRunnableMethod(
3874 &Browser::ProcessPendingUIUpdates),
3875 kUIUpdateCoalescingTimeMS);
3876 }
3877 }
3878
ProcessPendingUIUpdates()3879 void Browser::ProcessPendingUIUpdates() {
3880 #ifndef NDEBUG
3881 // Validate that all tabs we have pending updates for exist. This is scary
3882 // because the pending list must be kept in sync with any detached or
3883 // deleted tabs.
3884 for (UpdateMap::const_iterator i = scheduled_updates_.begin();
3885 i != scheduled_updates_.end(); ++i) {
3886 bool found = false;
3887 for (int tab = 0; tab < tab_count(); tab++) {
3888 if (GetTabContentsAt(tab) == i->first) {
3889 found = true;
3890 break;
3891 }
3892 }
3893 DCHECK(found);
3894 }
3895 #endif
3896
3897 chrome_updater_factory_.RevokeAll();
3898
3899 for (UpdateMap::const_iterator i = scheduled_updates_.begin();
3900 i != scheduled_updates_.end(); ++i) {
3901 // Do not dereference |contents|, it may be out-of-date!
3902 const TabContents* contents = i->first;
3903 unsigned flags = i->second;
3904
3905 if (contents == GetSelectedTabContents()) {
3906 // Updates that only matter when the tab is selected go here.
3907
3908 if (flags & TabContents::INVALIDATE_PAGE_ACTIONS) {
3909 LocationBar* location_bar = window()->GetLocationBar();
3910 if (location_bar)
3911 location_bar->UpdatePageActions();
3912 }
3913 // Updating the URL happens synchronously in ScheduleUIUpdate.
3914 if (flags & TabContents::INVALIDATE_LOAD && GetStatusBubble()) {
3915 GetStatusBubble()->SetStatus(
3916 GetSelectedTabContentsWrapper()->GetStatusText());
3917 }
3918
3919 if (flags & (TabContents::INVALIDATE_TAB |
3920 TabContents::INVALIDATE_TITLE)) {
3921 // TODO(pinkerton): Disable app-mode in the model until we implement it
3922 // on the Mac. Be sure to remove both ifdefs. http://crbug.com/13148
3923 #if !defined(OS_MACOSX)
3924 command_updater_.UpdateCommandEnabled(IDC_CREATE_SHORTCUTS,
3925 web_app::IsValidUrl(contents->GetURL()));
3926 #endif
3927 window_->UpdateTitleBar();
3928 }
3929 }
3930
3931 // Updates that don't depend upon the selected state go here.
3932 if (flags & (TabContents::INVALIDATE_TAB | TabContents::INVALIDATE_TITLE)) {
3933 tab_handler_->GetTabStripModel()->UpdateTabContentsStateAt(
3934 tab_handler_->GetTabStripModel()->GetWrapperIndex(contents),
3935 TabStripModelObserver::ALL);
3936 }
3937
3938 // We don't need to process INVALIDATE_STATE, since that's not visible.
3939 }
3940
3941 scheduled_updates_.clear();
3942 }
3943
RemoveScheduledUpdatesFor(TabContents * contents)3944 void Browser::RemoveScheduledUpdatesFor(TabContents* contents) {
3945 if (!contents)
3946 return;
3947
3948 UpdateMap::iterator i = scheduled_updates_.find(contents);
3949 if (i != scheduled_updates_.end())
3950 scheduled_updates_.erase(i);
3951 }
3952
3953
3954 ///////////////////////////////////////////////////////////////////////////////
3955 // Browser, Getters for UI (private):
3956
GetStatusBubble()3957 StatusBubble* Browser::GetStatusBubble() {
3958 #if !defined(OS_MACOSX)
3959 // In kiosk mode, we want to always hide the status bubble.
3960 if (CommandLine::ForCurrentProcess()->HasSwitch(switches::kKioskMode))
3961 return NULL;
3962 #endif
3963 return window_ ? window_->GetStatusBubble() : NULL;
3964 }
3965
3966 ///////////////////////////////////////////////////////////////////////////////
3967 // Browser, Session restore functions (private):
3968
SyncHistoryWithTabs(int index)3969 void Browser::SyncHistoryWithTabs(int index) {
3970 if (!profile()->HasSessionService())
3971 return;
3972 SessionService* session_service = profile()->GetSessionService();
3973 if (session_service) {
3974 for (int i = index; i < tab_count(); ++i) {
3975 TabContents* contents = GetTabContentsAt(i);
3976 if (contents) {
3977 session_service->SetTabIndexInWindow(
3978 session_id(), contents->controller().session_id(), i);
3979 session_service->SetPinnedState(
3980 session_id(),
3981 contents->controller().session_id(),
3982 tab_handler_->GetTabStripModel()->IsTabPinned(i));
3983 }
3984 }
3985 }
3986 }
3987
3988 ///////////////////////////////////////////////////////////////////////////////
3989 // Browser, OnBeforeUnload handling (private):
3990
ProcessPendingTabs()3991 void Browser::ProcessPendingTabs() {
3992 if (!is_attempting_to_close_browser_) {
3993 // Because we might invoke this after a delay it's possible for the value of
3994 // is_attempting_to_close_browser_ to have changed since we scheduled the
3995 // task.
3996 return;
3997 }
3998
3999 if (HasCompletedUnloadProcessing()) {
4000 // We've finished all the unload events and can proceed to close the
4001 // browser.
4002 OnWindowClosing();
4003 return;
4004 }
4005
4006 // Process beforeunload tabs first. When that queue is empty, process
4007 // unload tabs.
4008 if (!tabs_needing_before_unload_fired_.empty()) {
4009 TabContents* tab = *(tabs_needing_before_unload_fired_.begin());
4010 // Null check render_view_host here as this gets called on a PostTask and
4011 // the tab's render_view_host may have been nulled out.
4012 if (tab->render_view_host()) {
4013 tab->render_view_host()->FirePageBeforeUnload(false);
4014 } else {
4015 ClearUnloadState(tab, true);
4016 }
4017 } else if (!tabs_needing_unload_fired_.empty()) {
4018 // We've finished firing all beforeunload events and can proceed with unload
4019 // events.
4020 // TODO(ojan): We should add a call to browser_shutdown::OnShutdownStarting
4021 // somewhere around here so that we have accurate measurements of shutdown
4022 // time.
4023 // TODO(ojan): We can probably fire all the unload events in parallel and
4024 // get a perf benefit from that in the cases where the tab hangs in it's
4025 // unload handler or takes a long time to page in.
4026 TabContents* tab = *(tabs_needing_unload_fired_.begin());
4027 // Null check render_view_host here as this gets called on a PostTask and
4028 // the tab's render_view_host may have been nulled out.
4029 if (tab->render_view_host()) {
4030 tab->render_view_host()->ClosePage(false, -1, -1);
4031 } else {
4032 ClearUnloadState(tab, true);
4033 }
4034 } else {
4035 NOTREACHED();
4036 }
4037 }
4038
HasCompletedUnloadProcessing() const4039 bool Browser::HasCompletedUnloadProcessing() const {
4040 return is_attempting_to_close_browser_ &&
4041 tabs_needing_before_unload_fired_.empty() &&
4042 tabs_needing_unload_fired_.empty();
4043 }
4044
CancelWindowClose()4045 void Browser::CancelWindowClose() {
4046 // Closing of window can be canceled from:
4047 // - canceling beforeunload
4048 // - disallowing closing from IsClosingPermitted.
4049 DCHECK(is_attempting_to_close_browser_);
4050 tabs_needing_before_unload_fired_.clear();
4051 tabs_needing_unload_fired_.clear();
4052 is_attempting_to_close_browser_ = false;
4053
4054 // Inform TabCloseableStateWatcher that closing of window has been canceled.
4055 TabCloseableStateWatcher* watcher =
4056 g_browser_process->tab_closeable_state_watcher();
4057 if (watcher)
4058 watcher->OnWindowCloseCanceled(this);
4059 }
4060
RemoveFromSet(UnloadListenerSet * set,TabContents * tab)4061 bool Browser::RemoveFromSet(UnloadListenerSet* set, TabContents* tab) {
4062 DCHECK(is_attempting_to_close_browser_);
4063
4064 UnloadListenerSet::iterator iter = std::find(set->begin(), set->end(), tab);
4065 if (iter != set->end()) {
4066 set->erase(iter);
4067 return true;
4068 }
4069 return false;
4070 }
4071
ClearUnloadState(TabContents * tab,bool process_now)4072 void Browser::ClearUnloadState(TabContents* tab, bool process_now) {
4073 // Closing of browser could be canceled (via IsClosingPermitted) between the
4074 // time when request was initiated and when this method is called, so check
4075 // for is_attempting_to_close_browser_ flag before proceeding.
4076 if (is_attempting_to_close_browser_) {
4077 RemoveFromSet(&tabs_needing_before_unload_fired_, tab);
4078 RemoveFromSet(&tabs_needing_unload_fired_, tab);
4079 if (process_now) {
4080 ProcessPendingTabs();
4081 } else {
4082 MessageLoop::current()->PostTask(
4083 FROM_HERE,
4084 method_factory_.NewRunnableMethod(&Browser::ProcessPendingTabs));
4085 }
4086 }
4087 }
4088
4089 ///////////////////////////////////////////////////////////////////////////////
4090 // Browser, In-progress download termination handling (private):
4091
CheckDownloadsInProgress(bool * normal_downloads_are_present,bool * incognito_downloads_are_present)4092 void Browser::CheckDownloadsInProgress(bool* normal_downloads_are_present,
4093 bool* incognito_downloads_are_present) {
4094 *normal_downloads_are_present = false;
4095 *incognito_downloads_are_present = false;
4096
4097 // If there are no download in-progress, our job is done.
4098 DownloadManager* download_manager = NULL;
4099 // But first we need to check for the existance of the download manager, as
4100 // GetDownloadManager() will unnecessarily try to create one if it does not
4101 // exist.
4102 if (profile()->HasCreatedDownloadManager())
4103 download_manager = profile()->GetDownloadManager();
4104 if (profile()->IsOffTheRecord()) {
4105 // Browser is incognito and so download_manager if present is for incognito
4106 // downloads.
4107 *incognito_downloads_are_present =
4108 (download_manager && download_manager->in_progress_count() != 0);
4109 // Check original profile.
4110 if (profile()->GetOriginalProfile()->HasCreatedDownloadManager())
4111 download_manager = profile()->GetOriginalProfile()->GetDownloadManager();
4112 }
4113
4114 *normal_downloads_are_present =
4115 (download_manager && download_manager->in_progress_count() != 0);
4116 }
4117
CanCloseWithInProgressDownloads()4118 bool Browser::CanCloseWithInProgressDownloads() {
4119 if (cancel_download_confirmation_state_ != NOT_PROMPTED) {
4120 if (cancel_download_confirmation_state_ == WAITING_FOR_RESPONSE) {
4121 // We need to hear from the user before we can close.
4122 return false;
4123 }
4124 // RESPONSE_RECEIVED case, the user decided to go along with the closing.
4125 return true;
4126 }
4127 // Indicated that normal (non-incognito) downloads are pending.
4128 bool normal_downloads_are_present = false;
4129 bool incognito_downloads_are_present = false;
4130 CheckDownloadsInProgress(&normal_downloads_are_present,
4131 &incognito_downloads_are_present);
4132 if (!normal_downloads_are_present && !incognito_downloads_are_present)
4133 return true;
4134
4135 if (is_attempting_to_close_browser_)
4136 return true;
4137
4138 if ((!normal_downloads_are_present && !profile()->IsOffTheRecord()) ||
4139 (!incognito_downloads_are_present && profile()->IsOffTheRecord()))
4140 return true;
4141
4142 // Let's figure out if we are the last window for our profile.
4143 // Note that we cannot just use BrowserList::GetBrowserCount as browser
4144 // windows closing is delayed and the returned count might include windows
4145 // that are being closed.
4146 // The browser allowed to be closed only if:
4147 // 1. It is a regular browser and there are no regular downloads present or
4148 // this is not the last regular browser window.
4149 // 2. It is an incognito browser and there are no incognito downloads present
4150 // or this is not the last incognito browser window.
4151 int count = 0;
4152 for (BrowserList::const_iterator iter = BrowserList::begin();
4153 iter != BrowserList::end(); ++iter) {
4154 // Don't count this browser window or any other in the process of closing.
4155 // Only consider normal browser windows, not popups.
4156 Browser* const browser = *iter;
4157 if (browser == this
4158 || browser->is_attempting_to_close_browser_
4159 || browser->type() != Browser::TYPE_NORMAL)
4160 continue;
4161
4162 // Verify that this is not the last non-incognito or incognito browser,
4163 // depending on the pending downloads.
4164 if (normal_downloads_are_present && !profile()->IsOffTheRecord() &&
4165 browser->profile()->IsOffTheRecord())
4166 continue;
4167 if (incognito_downloads_are_present && profile()->IsOffTheRecord() &&
4168 !browser->profile()->IsOffTheRecord())
4169 continue;
4170
4171 // We test the original profile, because an incognito browser window keeps
4172 // the original profile alive (and its DownloadManager).
4173 // We also need to test explicitly the profile directly so that 2 incognito
4174 // profiles count as a match.
4175 if ((*iter)->profile() == profile() ||
4176 (*iter)->profile()->GetOriginalProfile() == profile())
4177 count++;
4178 }
4179 if (count > 0)
4180 return true;
4181
4182 cancel_download_confirmation_state_ = WAITING_FOR_RESPONSE;
4183 window_->ConfirmBrowserCloseWithPendingDownloads();
4184
4185 // Return false so the browser does not close. We'll close if the user
4186 // confirms in the dialog.
4187 return false;
4188 }
4189
4190 ///////////////////////////////////////////////////////////////////////////////
4191 // Browser, Assorted utility functions (private):
4192
4193 // static
GetTabbedBrowser(Profile * profile,bool match_incognito)4194 Browser* Browser::GetTabbedBrowser(Profile* profile, bool match_incognito) {
4195 return BrowserList::FindBrowserWithType(profile, TYPE_NORMAL,
4196 match_incognito);
4197 }
4198
4199 // static
GetOrCreateTabbedBrowser(Profile * profile)4200 Browser* Browser::GetOrCreateTabbedBrowser(Profile* profile) {
4201 Browser* browser = GetTabbedBrowser(profile, false);
4202 if (!browser)
4203 browser = Browser::Create(profile);
4204 return browser;
4205 }
4206
SetAsDelegate(TabContentsWrapper * tab,Browser * delegate)4207 void Browser::SetAsDelegate(TabContentsWrapper* tab, Browser* delegate) {
4208 tab->tab_contents()->set_delegate(delegate);
4209 tab->set_delegate(delegate);
4210 tab->search_engine_tab_helper()->set_delegate(delegate);
4211 }
4212
FindInPage(bool find_next,bool forward_direction)4213 void Browser::FindInPage(bool find_next, bool forward_direction) {
4214 ShowFindBar();
4215 if (find_next) {
4216 string16 find_text;
4217 #if defined(OS_MACOSX)
4218 // We always want to search for the contents of the find pasteboard on OS X.
4219 find_text = GetFindPboardText();
4220 #endif
4221 GetSelectedTabContentsWrapper()->
4222 find_tab_helper()->StartFinding(find_text,
4223 forward_direction,
4224 false); // Not case sensitive.
4225 }
4226 }
4227
CloseFrame()4228 void Browser::CloseFrame() {
4229 window_->Close();
4230 }
4231
TabDetachedAtImpl(TabContentsWrapper * contents,int index,DetachType type)4232 void Browser::TabDetachedAtImpl(TabContentsWrapper* contents, int index,
4233 DetachType type) {
4234 if (type == DETACH_TYPE_DETACH) {
4235 // Save the current location bar state, but only if the tab being detached
4236 // is the selected tab. Because saving state can conditionally revert the
4237 // location bar, saving the current tab's location bar state to a
4238 // non-selected tab can corrupt both tabs.
4239 if (contents == GetSelectedTabContentsWrapper()) {
4240 LocationBar* location_bar = window()->GetLocationBar();
4241 if (location_bar)
4242 location_bar->SaveStateToContents(contents->tab_contents());
4243 }
4244
4245 if (!tab_handler_->GetTabStripModel()->closing_all())
4246 SyncHistoryWithTabs(0);
4247 }
4248
4249 SetAsDelegate(contents, NULL);
4250 RemoveScheduledUpdatesFor(contents->tab_contents());
4251
4252 if (find_bar_controller_.get() &&
4253 index == tab_handler_->GetTabStripModel()->active_index()) {
4254 find_bar_controller_->ChangeTabContents(NULL);
4255 }
4256
4257 if (is_attempting_to_close_browser_) {
4258 // If this is the last tab with unload handlers, then ProcessPendingTabs
4259 // would call back into the TabStripModel (which is invoking this method on
4260 // us). Avoid that by passing in false so that the call to
4261 // ProcessPendingTabs is delayed.
4262 ClearUnloadState(contents->tab_contents(), false);
4263 }
4264
4265 registrar_.Remove(this, NotificationType::TAB_CONTENTS_DISCONNECTED,
4266 Source<TabContentsWrapper>(contents));
4267 }
4268
4269 // static
RegisterAppPrefs(const std::string & app_name,Profile * profile)4270 void Browser::RegisterAppPrefs(const std::string& app_name, Profile* profile) {
4271 // A set of apps that we've already started.
4272 static std::set<std::string>* g_app_names = NULL;
4273
4274 if (!g_app_names)
4275 g_app_names = new std::set<std::string>;
4276
4277 // Only register once for each app name.
4278 if (g_app_names->find(app_name) != g_app_names->end())
4279 return;
4280 g_app_names->insert(app_name);
4281
4282 // We need to register the window position pref.
4283 std::string window_pref(prefs::kBrowserWindowPlacement);
4284 window_pref.append("_");
4285 window_pref.append(app_name);
4286 profile->GetPrefs()->RegisterDictionaryPref(window_pref.c_str());
4287 }
4288
TabRestoreServiceChanged(TabRestoreService * service)4289 void Browser::TabRestoreServiceChanged(TabRestoreService* service) {
4290 command_updater_.UpdateCommandEnabled(IDC_RESTORE_TAB,
4291 !service->entries().empty());
4292 }
4293
TabRestoreServiceDestroyed(TabRestoreService * service)4294 void Browser::TabRestoreServiceDestroyed(TabRestoreService* service) {
4295 if (!tab_restore_service_)
4296 return;
4297
4298 DCHECK_EQ(tab_restore_service_, service);
4299 tab_restore_service_->RemoveObserver(this);
4300 tab_restore_service_ = NULL;
4301 }
4302
4303 // Centralized method for creating a TabContents, configuring and installing
4304 // all its supporting objects and observers.
TabContentsFactory(Profile * profile,SiteInstance * site_instance,int routing_id,const TabContents * base_tab_contents,SessionStorageNamespace * session_storage_namespace)4305 TabContentsWrapper* Browser::TabContentsFactory(
4306 Profile* profile,
4307 SiteInstance* site_instance,
4308 int routing_id,
4309 const TabContents* base_tab_contents,
4310 SessionStorageNamespace* session_storage_namespace) {
4311 TabContents* new_contents = new TabContents(profile, site_instance,
4312 routing_id, base_tab_contents,
4313 session_storage_namespace);
4314 TabContentsWrapper* wrapper = new TabContentsWrapper(new_contents);
4315 return wrapper;
4316 }
4317
OpenInstant(WindowOpenDisposition disposition)4318 bool Browser::OpenInstant(WindowOpenDisposition disposition) {
4319 if (!instant() || !instant()->is_active() || !instant()->IsCurrent() ||
4320 disposition == NEW_BACKGROUND_TAB) {
4321 // NEW_BACKGROUND_TAB results in leaving the omnibox open, so we don't
4322 // attempt to use the instant preview.
4323 return false;
4324 }
4325
4326 if (disposition == CURRENT_TAB) {
4327 instant()->CommitCurrentPreview(INSTANT_COMMIT_PRESSED_ENTER);
4328 return true;
4329 }
4330 if (disposition == NEW_FOREGROUND_TAB) {
4331 TabContentsWrapper* preview_contents = instant()->ReleasePreviewContents(
4332 INSTANT_COMMIT_PRESSED_ENTER);
4333 // HideInstant is invoked after release so that InstantController is not
4334 // active when HideInstant asks it for its state.
4335 HideInstant();
4336 preview_contents->controller().PruneAllButActive();
4337 tab_handler_->GetTabStripModel()->AddTabContents(
4338 preview_contents,
4339 -1,
4340 instant()->last_transition_type(),
4341 TabStripModel::ADD_ACTIVE);
4342 instant()->CompleteRelease(preview_contents->tab_contents());
4343 return true;
4344 }
4345 // The omnibox currently doesn't use other dispositions, so we don't attempt
4346 // to handle them. If you hit this NOTREACHED file a bug and I'll (sky) add
4347 // support for the new disposition.
4348 NOTREACHED();
4349 return false;
4350 }
4351
CreateInstantIfNecessary()4352 void Browser::CreateInstantIfNecessary() {
4353 if (type() == TYPE_NORMAL && InstantController::IsEnabled(profile()) &&
4354 !profile()->IsOffTheRecord()) {
4355 instant_.reset(new InstantController(profile_, this));
4356 instant_unload_handler_.reset(new InstantUnloadHandler(this));
4357 }
4358 }
4359
ViewSource(TabContentsWrapper * contents)4360 void Browser::ViewSource(TabContentsWrapper* contents) {
4361 DCHECK(contents);
4362
4363 NavigationEntry* active_entry = contents->controller().GetActiveEntry();
4364 if (!active_entry)
4365 return;
4366
4367 ViewSource(contents, active_entry->url(), active_entry->content_state());
4368 }
4369
ViewSource(TabContentsWrapper * contents,const GURL & url,const std::string & content_state)4370 void Browser::ViewSource(TabContentsWrapper* contents,
4371 const GURL& url,
4372 const std::string& content_state) {
4373 UserMetrics::RecordAction(UserMetricsAction("ViewSource"), profile_);
4374 DCHECK(contents);
4375
4376 TabContentsWrapper* view_source_contents = contents->Clone();
4377 view_source_contents->controller().PruneAllButActive();
4378 NavigationEntry* active_entry =
4379 view_source_contents->controller().GetActiveEntry();
4380 if (!active_entry)
4381 return;
4382
4383 GURL view_source_url = GURL(chrome::kViewSourceScheme + std::string(":") +
4384 url.spec());
4385 active_entry->set_virtual_url(view_source_url);
4386
4387 // Do not restore scroller position.
4388 active_entry->set_content_state(
4389 webkit_glue::RemoveScrollOffsetFromHistoryState(content_state));
4390
4391 // Do not restore title, derive it from the url.
4392 active_entry->set_title(string16());
4393
4394 // Now show view-source entry.
4395 if (CanSupportWindowFeature(FEATURE_TABSTRIP)) {
4396 // If this is a tabbed browser, just create a duplicate tab inside the same
4397 // window next to the tab being duplicated.
4398 int index = tab_handler_->GetTabStripModel()->
4399 GetIndexOfTabContents(contents);
4400 int add_types = TabStripModel::ADD_ACTIVE |
4401 TabStripModel::ADD_INHERIT_GROUP;
4402 tab_handler_->GetTabStripModel()->InsertTabContentsAt(index + 1,
4403 view_source_contents,
4404 add_types);
4405 } else {
4406 Browser* browser = Browser::CreateForType(TYPE_NORMAL, profile_);
4407
4408 // Preserve the size of the original window. The new window has already
4409 // been given an offset by the OS, so we shouldn't copy the old bounds.
4410 BrowserWindow* new_window = browser->window();
4411 new_window->SetBounds(gfx::Rect(new_window->GetRestoredBounds().origin(),
4412 window()->GetRestoredBounds().size()));
4413
4414 // We need to show the browser now. Otherwise ContainerWin assumes the
4415 // TabContents is invisible and won't size it.
4416 browser->window()->Show();
4417
4418 // The page transition below is only for the purpose of inserting the tab.
4419 browser->AddTab(view_source_contents, PageTransition::LINK);
4420 }
4421
4422 if (profile_->HasSessionService()) {
4423 SessionService* session_service = profile_->GetSessionService();
4424 if (session_service)
4425 session_service->TabRestored(&view_source_contents->controller(), false);
4426 }
4427 }
4428