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
150using base::TimeDelta;
151
152///////////////////////////////////////////////////////////////////////////////
153
154namespace {
155
156// The URL to be loaded to display Help.
157const 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.
169const 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.
177const 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.
182const char kPrivacyDashboardUrl[] = "https://www.google.com/dashboard";
183
184// How long we wait before updating the browser chrome while loading a page.
185const int kUIUpdateCoalescingTimeMS = 200;
186
187const 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
192const float kPopupMaxWidthFactor = 0.5;
193const float kPopupMaxHeightFactor = 0.6;
194#endif
195
196}  // namespace
197
198extern bool g_log_bug53991;
199
200///////////////////////////////////////////////////////////////////////////////
201// Browser, Constructors, Creation, Showing:
202
203Browser::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
284Browser::~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
341Browser* Browser::Create(Profile* profile) {
342  Browser* browser = new Browser(TYPE_NORMAL, profile);
343  browser->InitBrowserWindow();
344  return browser;
345}
346
347// static
348Browser* 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
362Browser* Browser::CreateForType(Type type, Profile* profile) {
363  Browser* browser = new Browser(type, profile);
364  browser->InitBrowserWindow();
365  return browser;
366}
367
368// static
369Browser* 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
399Browser* 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
406void 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
467const std::vector<std::wstring>& Browser::user_data_dir_profiles() const {
468  return g_browser_process->user_data_dir_profiles();
469}
470
471void Browser::set_user_data_dir_profiles(
472    const std::vector<std::wstring>& profiles) {
473  g_browser_process->user_data_dir_profiles() = profiles;
474}
475
476FindBarController* 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
487bool Browser::HasFindBarController() const {
488  return find_bar_controller_.get() != NULL;
489}
490
491///////////////////////////////////////////////////////////////////////////////
492// Browser, Creation Helpers:
493
494// static
495void Browser::OpenEmptyWindow(Profile* profile) {
496  Browser* browser = Browser::Create(profile);
497  browser->AddBlankTab(true);
498  browser->window()->Show();
499}
500
501// static
502void Browser::OpenWindowWithRestoredTabs(Profile* profile) {
503  TabRestoreService* service = profile->GetTabRestoreService();
504  if (service)
505    service->RestoreMostRecentEntry(NULL);
506}
507
508// static
509void 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
517TabContents* 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
546TabContents* 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
597TabContents* 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
624TabContents* 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(&params);
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
692void 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
700void Browser::OpenHistoryWindow(Profile* profile) {
701  Browser* browser = Browser::Create(profile);
702  browser->ShowHistoryTab();
703  browser->window()->Show();
704}
705
706// static
707void Browser::OpenDownloadsWindow(Profile* profile) {
708  Browser* browser = Browser::Create(profile);
709  browser->ShowDownloadsTab();
710  browser->window()->Show();
711}
712
713// static
714void Browser::OpenHelpWindow(Profile* profile) {
715  Browser* browser = Browser::Create(profile);
716  browser->OpenHelpTab();
717  browser->window()->Show();
718}
719
720// static
721void Browser::OpenOptionsWindow(Profile* profile) {
722  Browser* browser = Browser::Create(profile);
723  browser->OpenOptionsDialog();
724  browser->window()->Show();
725}
726
727// static
728void Browser::OpenClearBrowingDataDialogWindow(Profile* profile) {
729  Browser* browser = Browser::Create(profile);
730  browser->OpenClearBrowsingDataDialog();
731  browser->window()->Show();
732}
733
734// static
735void Browser::OpenImportSettingsDialogWindow(Profile* profile) {
736  Browser* browser = Browser::Create(profile);
737  browser->OpenImportSettingsDialog();
738  browser->window()->Show();
739}
740
741// static
742void Browser::OpenInstantConfirmDialogWindow(Profile* profile) {
743  Browser* browser = Browser::Create(profile);
744  browser->OpenInstantConfirmDialog();
745  browser->window()->Show();
746}
747#endif
748
749// static
750void 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
760std::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
769bool 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
774void 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
786gfx::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.
808bool 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
825SkBitmap 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
832string16 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
859void 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
871bool 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
882bool 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
898void 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
938void 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
957int Browser::tab_count() const {
958  return tab_handler_->GetTabStripModel()->count();
959}
960
961int Browser::active_index() const {
962  return tab_handler_->GetTabStripModel()->active_index();
963}
964
965int Browser::GetIndexOfController(
966    const NavigationController* controller) const {
967  return tab_handler_->GetTabStripModel()->GetIndexOfController(controller);
968}
969
970TabContentsWrapper* Browser::GetSelectedTabContentsWrapper() const {
971  return tabstrip_model()->GetSelectedTabContents();
972}
973TabContentsWrapper* Browser::GetTabContentsWrapperAt(int index) const {
974  return tabstrip_model()->GetTabContentsAt(index);
975}
976
977TabContents* Browser::GetSelectedTabContents() const {
978  TabContentsWrapper* wrapper = GetSelectedTabContentsWrapper();
979  if (wrapper)
980    return wrapper->tab_contents();
981  return NULL;
982}
983
984TabContents* 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
991void Browser::ActivateTabAt(int index, bool user_gesture) {
992  tab_handler_->GetTabStripModel()->ActivateTabAt(index, user_gesture);
993}
994
995bool Browser::IsTabPinned(int index) const {
996  return tabstrip_model()->IsTabPinned(index);
997}
998
999void Browser::CloseAllTabs() {
1000  tab_handler_->GetTabStripModel()->CloseAllTabs();
1001}
1002
1003////////////////////////////////////////////////////////////////////////////////
1004// Browser, Tab adding/showing functions:
1005
1006bool Browser::IsTabStripEditable() const {
1007  return window()->IsTabStripEditable();
1008}
1009
1010int Browser::GetIndexForInsertionDuringRestore(int relative_index) {
1011  return (tab_handler_->GetTabStripModel()->insertion_policy() ==
1012      TabStripModel::INSERT_AFTER) ? tab_count() : relative_index;
1013}
1014
1015TabContentsWrapper* 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(&params);
1020  return params.target_contents;
1021}
1022
1023TabContents* 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
1030void 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
1037void Browser::CloseTabContents(TabContents* contents) {
1038  CloseContents(contents);
1039}
1040
1041void Browser::BrowserShowHtmlDialog(HtmlDialogUIDelegate* delegate,
1042                                    gfx::NativeWindow parent_window) {
1043  ShowHtmlDialog(delegate, parent_window);
1044}
1045
1046void Browser::BrowserRenderWidgetShowing() {
1047  RenderWidgetShowing();
1048}
1049
1050void Browser::BookmarkBarSizeChanged(bool is_animating) {
1051  window_->ToolbarSizeChanged(is_animating);
1052}
1053
1054TabContents* 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
1100void 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
1120bool Browser::CanRestoreTab() {
1121  return command_updater_.IsCommandEnabled(IDC_RESTORE_TAB);
1122}
1123
1124bool 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
1134browser::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
1142void Browser::ShowSingletonTab(const GURL& url) {
1143  browser::NavigateParams params(GetSingletonTabNavigateParams(url));
1144  browser::Navigate(&params);
1145}
1146
1147void 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
1202bool Browser::ShouldOpenNewTabForWindowDisposition(
1203    WindowOpenDisposition disposition) {
1204  return (disposition == NEW_FOREGROUND_TAB ||
1205          disposition == NEW_BACKGROUND_TAB);
1206}
1207
1208TabContents* 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
1221void Browser::UpdateTabStripModelInsertionPolicy() {
1222  tab_handler_->GetTabStripModel()->SetInsertionPolicy(UseVerticalTabs() ?
1223      TabStripModel::INSERT_BEFORE : TabStripModel::INSERT_AFTER);
1224}
1225
1226void Browser::UseVerticalTabsChanged() {
1227  UpdateTabStripModelInsertionPolicy();
1228  window()->ToggleTabStripMode();
1229}
1230
1231bool 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
1269bool 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
1278void 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
1293void Browser::GoForward(WindowOpenDisposition disposition) {
1294  UserMetrics::RecordAction(UserMetricsAction("Forward"), profile_);
1295  if (GetSelectedTabContentsWrapper()->controller().CanGoForward())
1296    GetOrCloneTabForDisposition(disposition)->controller().GoForward();
1297}
1298
1299void Browser::Reload(WindowOpenDisposition disposition) {
1300  UserMetrics::RecordAction(UserMetricsAction("Reload"), profile_);
1301  ReloadInternal(disposition, false);
1302}
1303
1304void Browser::ReloadIgnoringCache(WindowOpenDisposition disposition) {
1305  UserMetrics::RecordAction(UserMetricsAction("ReloadIgnoringCache"), profile_);
1306  ReloadInternal(disposition, true);
1307}
1308
1309void 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
1330void Browser::Home(WindowOpenDisposition disposition) {
1331  UserMetrics::RecordAction(UserMetricsAction("Home"), profile_);
1332  OpenURL(GetHomePage(), GURL(), disposition, PageTransition::AUTO_BOOKMARK);
1333}
1334
1335void 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(&params);
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
1376void Browser::Stop() {
1377  UserMetrics::RecordAction(UserMetricsAction("Stop"), profile_);
1378  GetSelectedTabContentsWrapper()->tab_contents()->Stop();
1379}
1380
1381void 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
1397void 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
1407void Browser::CloseWindow() {
1408  UserMetrics::RecordAction(UserMetricsAction("CloseWindow"), profile_);
1409  window_->Close();
1410}
1411
1412void 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
1429void Browser::CloseTab() {
1430  UserMetrics::RecordAction(UserMetricsAction("CloseTab_Accelerator"),
1431                            profile_);
1432  if (CanCloseTab())
1433    tab_handler_->GetTabStripModel()->CloseSelectedTabs();
1434}
1435
1436void Browser::SelectNextTab() {
1437  UserMetrics::RecordAction(UserMetricsAction("SelectNextTab"), profile_);
1438  tab_handler_->GetTabStripModel()->SelectNextTab();
1439}
1440
1441void Browser::SelectPreviousTab() {
1442  UserMetrics::RecordAction(UserMetricsAction("SelectPrevTab"), profile_);
1443  tab_handler_->GetTabStripModel()->SelectPreviousTab();
1444}
1445
1446void 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
1460void Browser::MoveTabNext() {
1461  UserMetrics::RecordAction(UserMetricsAction("MoveTabNext"), profile_);
1462  tab_handler_->GetTabStripModel()->MoveTabNext();
1463}
1464
1465void Browser::MoveTabPrevious() {
1466  UserMetrics::RecordAction(UserMetricsAction("MoveTabPrevious"), profile_);
1467  tab_handler_->GetTabStripModel()->MoveTabPrevious();
1468}
1469
1470void 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
1478void Browser::SelectLastTab() {
1479  UserMetrics::RecordAction(UserMetricsAction("SelectLastTab"), profile_);
1480  tab_handler_->GetTabStripModel()->SelectLastTab();
1481}
1482
1483void Browser::DuplicateTab() {
1484  UserMetrics::RecordAction(UserMetricsAction("Duplicate"), profile_);
1485  DuplicateContentsAt(active_index());
1486}
1487
1488void 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
1497void 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
1512void 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
1522void 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)
1541void 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
1564void Browser::ShowKeyboardOverlay() {
1565  window_->ShowKeyboardOverlay(window_->GetNativeHandle());
1566}
1567#endif
1568
1569void 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
1592void 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
1619void 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
1627void Browser::ViewSelectedSource() {
1628  ViewSource(GetSelectedTabContentsWrapper());
1629}
1630
1631void Browser::ShowFindBar() {
1632  GetFindBarController()->Show();
1633}
1634
1635bool Browser::SupportsWindowFeature(WindowFeature feature) const {
1636  return SupportsWindowFeatureImpl(feature, true);
1637}
1638
1639bool Browser::CanSupportWindowFeature(WindowFeature feature) const {
1640  return SupportsWindowFeatureImpl(feature, false);
1641}
1642
1643void Browser::EmailPageLocation() {
1644  UserMetrics::RecordAction(UserMetricsAction("EmailPageLocation"), profile_);
1645  GetSelectedTabContents()->EmailPageLocation();
1646}
1647
1648void 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
1659void 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
1673void 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
1691void Browser::Cut() {
1692  UserMetrics::RecordAction(UserMetricsAction("Cut"), profile_);
1693  window()->Cut();
1694}
1695
1696void Browser::Copy() {
1697  UserMetrics::RecordAction(UserMetricsAction("Copy"), profile_);
1698  window()->Copy();
1699}
1700
1701void Browser::Paste() {
1702  UserMetrics::RecordAction(UserMetricsAction("Paste"), profile_);
1703  window()->Paste();
1704}
1705
1706void Browser::Find() {
1707  UserMetrics::RecordAction(UserMetricsAction("Find"), profile_);
1708  FindInPage(false, false);
1709}
1710
1711void Browser::FindNext() {
1712  UserMetrics::RecordAction(UserMetricsAction("FindNext"), profile_);
1713  FindInPage(true, true);
1714}
1715
1716void Browser::FindPrevious() {
1717  UserMetrics::RecordAction(UserMetricsAction("FindPrevious"), profile_);
1718  FindInPage(true, false);
1719}
1720
1721void 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
1734void Browser::FocusToolbar() {
1735  UserMetrics::RecordAction(UserMetricsAction("FocusToolbar"), profile_);
1736  window_->FocusToolbar();
1737}
1738
1739void Browser::FocusAppMenu() {
1740  UserMetrics::RecordAction(UserMetricsAction("FocusAppMenu"), profile_);
1741  window_->FocusAppMenu();
1742}
1743
1744void Browser::FocusLocationBar() {
1745  UserMetrics::RecordAction(UserMetricsAction("FocusLocation"), profile_);
1746  window_->SetFocusToLocationBar(true);
1747}
1748
1749void Browser::FocusBookmarksToolbar() {
1750  UserMetrics::RecordAction(UserMetricsAction("FocusBookmarksToolbar"),
1751                            profile_);
1752  window_->FocusBookmarksToolbar();
1753}
1754
1755void Browser::FocusChromeOSStatus() {
1756  UserMetrics::RecordAction(UserMetricsAction("FocusChromeOSStatus"), profile_);
1757  window_->FocusChromeOSStatus();
1758}
1759
1760void Browser::FocusNextPane() {
1761  UserMetrics::RecordAction(UserMetricsAction("FocusNextPane"), profile_);
1762  window_->RotatePaneFocus(true);
1763}
1764
1765void Browser::FocusPreviousPane() {
1766  UserMetrics::RecordAction(UserMetricsAction("FocusPreviousPane"), profile_);
1767  window_->RotatePaneFocus(false);
1768}
1769
1770void Browser::FocusSearch() {
1771  // TODO(beng): replace this with FocusLocationBar
1772  UserMetrics::RecordAction(UserMetricsAction("FocusSearch"), profile_);
1773  window_->GetLocationBar()->FocusSearch();
1774}
1775
1776void 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
1799void 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
1823void 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
1840void 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
1848void Browser::OpenBugReportDialog() {
1849  UserMetrics::RecordAction(UserMetricsAction("ReportBug"), profile_);
1850  browser::ShowHtmlBugReportView(this);
1851}
1852
1853void Browser::ToggleBookmarkBar() {
1854  UserMetrics::RecordAction(UserMetricsAction("ShowBookmarksBar"), profile_);
1855  window_->ToggleBookmarkBar();
1856}
1857
1858void Browser::OpenBookmarkManager() {
1859  UserMetrics::RecordAction(UserMetricsAction("ShowBookmarkManager"), profile_);
1860  ShowBookmarkManagerTab();
1861}
1862
1863void Browser::ShowAppMenu() {
1864  // We record the user metric for this event in WrenchMenu::RunMenu.
1865  window_->ShowAppMenu();
1866}
1867
1868void Browser::ShowBookmarkManagerTab() {
1869  UserMetrics::RecordAction(UserMetricsAction("ShowBookmarks"), profile_);
1870  ShowSingletonTab(GURL(chrome::kChromeUIBookmarksURL));
1871}
1872
1873void Browser::ShowHistoryTab() {
1874  UserMetrics::RecordAction(UserMetricsAction("ShowHistory"), profile_);
1875  ShowSingletonTab(GURL(chrome::kChromeUIHistoryURL));
1876}
1877
1878void 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
1888void Browser::ShowExtensionsTab() {
1889  UserMetrics::RecordAction(UserMetricsAction("ShowExtensions"), profile_);
1890  ShowSingletonTab(GURL(chrome::kChromeUIExtensionsURL));
1891}
1892
1893void Browser::ShowAboutConflictsTab() {
1894  UserMetrics::RecordAction(UserMetricsAction("AboutConflicts"), profile_);
1895  ShowSingletonTab(GURL(chrome::kChromeUIConflictsURL));
1896}
1897
1898void 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
1913void 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(&params);
1918}
1919
1920void Browser::OpenClearBrowsingDataDialog() {
1921  UserMetrics::RecordAction(UserMetricsAction("ClearBrowsingData_ShowDlg"),
1922                            profile_);
1923  ShowOptionsTab(chrome::kClearBrowserDataSubPage);
1924}
1925
1926void 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(&params);
1932}
1933
1934void Browser::OpenPasswordManager() {
1935  UserMetrics::RecordAction(UserMetricsAction("Options_ShowPasswordManager"),
1936                            profile_);
1937  ShowOptionsTab(chrome::kPasswordManagerSubPage);
1938}
1939
1940void Browser::OpenImportSettingsDialog() {
1941  UserMetrics::RecordAction(UserMetricsAction("Import_ShowDlg"), profile_);
1942  ShowOptionsTab(chrome::kImportDataSubPage);
1943}
1944
1945void Browser::OpenInstantConfirmDialog() {
1946  ShowOptionsTab(chrome::kInstantConfirmPage);
1947}
1948
1949void Browser::OpenSyncMyBookmarksDialog() {
1950  sync_ui_util::OpenSyncMyBookmarksDialog(
1951      profile_, this, ProfileSyncService::START_FROM_WRENCH);
1952}
1953
1954void 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
1963void Browser::OpenUpdateChromeDialog() {
1964  UserMetrics::RecordAction(UserMetricsAction("UpdateChrome"), profile_);
1965  window_->ShowUpdateChromeDialog();
1966}
1967
1968void 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
1974void Browser::OpenThemeGalleryTabAndActivate() {
1975  AddSelectedTabWithURL(GURL(l10n_util::GetStringUTF8(IDS_THEMES_GALLERY_URL)),
1976                        PageTransition::LINK);
1977}
1978
1979void Browser::OpenPrivacyDashboardTabAndActivate() {
1980  OpenURL(GURL(kPrivacyDashboardUrl), GURL(),
1981          NEW_FOREGROUND_TAB, PageTransition::LINK);
1982  window_->Activate();
1983}
1984
1985void Browser::OpenAutofillHelpTabAndActivate() {
1986  GURL help_url = google_util::AppendGoogleLocaleParam(GURL(kAutofillHelpUrl));
1987  AddSelectedTabWithURL(help_url, PageTransition::LINK);
1988}
1989
1990void Browser::OpenSearchEngineOptionsDialog() {
1991  UserMetrics::RecordAction(UserMetricsAction("EditSearchEngines"), profile_);
1992  ShowOptionsTab(chrome::kSearchEnginesSubPage);
1993}
1994
1995#if defined(OS_CHROMEOS)
1996void Browser::OpenFileManager() {
1997  UserMetrics::RecordAction(UserMetricsAction("OpenFileManager"));
1998  ShowSingletonTab(FileManagerUtil::GetFileBrowserUrl());
1999}
2000
2001void Browser::OpenSystemOptionsDialog() {
2002  UserMetrics::RecordAction(UserMetricsAction("OpenSystemOptionsDialog"),
2003                            profile_);
2004  ShowOptionsTab(chrome::kSystemOptionsSubPage);
2005}
2006
2007void Browser::OpenInternetOptionsDialog() {
2008  UserMetrics::RecordAction(UserMetricsAction("OpenInternetOptionsDialog"),
2009                            profile_);
2010  ShowOptionsTab(chrome::kInternetOptionsSubPage);
2011}
2012
2013void Browser::OpenLanguageOptionsDialog() {
2014  UserMetrics::RecordAction(UserMetricsAction("OpenLanguageOptionsDialog"),
2015                            profile_);
2016  ShowOptionsTab(chrome::kLanguageOptionsSubPage);
2017}
2018
2019void Browser::OpenSystemTabAndActivate() {
2020  OpenURL(GURL(chrome::kChromeUISystemInfoURL), GURL(),
2021          NEW_FOREGROUND_TAB, PageTransition::LINK);
2022  window_->Activate();
2023}
2024
2025void Browser::OpenMobilePlanTabAndActivate() {
2026  OpenURL(GURL(chrome::kChromeUIMobileSetupURL), GURL(),
2027          NEW_FOREGROUND_TAB, PageTransition::LINK);
2028  window_->Activate();
2029}
2030#endif
2031
2032void Browser::OpenPluginsTabAndActivate() {
2033  OpenURL(GURL(chrome::kAboutPluginsURL), GURL(),
2034          NEW_FOREGROUND_TAB, PageTransition::LINK);
2035  window_->Activate();
2036}
2037
2038///////////////////////////////////////////////////////////////////////////////
2039
2040// static
2041void 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
2059void 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
2074void 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
2124bool 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
2141Browser* 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
2157void 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
2345bool 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
2354bool 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
2391void 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
2399int Browser::GetLastBlockedCommand(WindowOpenDisposition* disposition) {
2400  if (disposition)
2401    *disposition = last_blocked_command_disposition_;
2402  return last_blocked_command_id_;
2403}
2404
2405void 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
2433GURL 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
2463void 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
2472void Browser::ExecuteCommand(int id) {
2473  ExecuteCommandWithDisposition(id, CURRENT_TAB);
2474}
2475
2476///////////////////////////////////////////////////////////////////////////////
2477// Browser, TabHandlerDelegate implementation:
2478
2479Profile* Browser::GetProfile() const {
2480  return profile();
2481}
2482
2483Browser* Browser::AsBrowser() {
2484  return this;
2485}
2486
2487///////////////////////////////////////////////////////////////////////////////
2488// Browser, TabStripModelDelegate implementation:
2489
2490TabContentsWrapper* Browser::AddBlankTab(bool foreground) {
2491  return AddBlankTabAt(-1, foreground);
2492}
2493
2494TabContentsWrapper* 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(&params);
2504  params.target_contents->tab_contents()->set_new_tab_start_time(
2505      new_tab_start_time);
2506  return params.target_contents;
2507}
2508
2509Browser* 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
2533int Browser::GetDragActions() const {
2534  return TabStripModelDelegate::TAB_TEAROFF_ACTION | (tab_count() > 1 ?
2535      TabStripModelDelegate::TAB_MOVE_ACTION : 0);
2536}
2537
2538TabContentsWrapper* 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
2554bool Browser::CanDuplicateContentsAt(int index) {
2555  NavigationController& nc = GetTabContentsAt(index)->controller();
2556  return nc.tab_contents() && nc.GetLastCommittedEntry();
2557}
2558
2559void 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
2610void 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
2621void 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
2637bool Browser::RunUnloadListenerBeforeClosing(TabContentsWrapper* contents) {
2638  return Browser::RunUnloadEventsHelper(contents->tab_contents());
2639}
2640
2641bool Browser::CanReloadContents(TabContents* source) const {
2642  return type() != TYPE_DEVTOOLS;
2643}
2644
2645bool 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
2657bool Browser::CanBookmarkAllTabs() const {
2658  BookmarkModel* model = profile()->GetBookmarkModel();
2659  return (model && model->IsLoaded()) &&
2660         tab_count() > 1 &&
2661         edit_bookmarks_enabled_.GetValue();
2662}
2663
2664void 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
2678bool Browser::CanCloseTab() const {
2679  TabCloseableStateWatcher* watcher =
2680      g_browser_process->tab_closeable_state_watcher();
2681  return !watcher || watcher->CanCloseTab(this);
2682}
2683
2684void Browser::ToggleUseVerticalTabs() {
2685  use_vertical_tabs_.SetValue(!UseVerticalTabs());
2686  UseVerticalTabsChanged();
2687}
2688
2689bool 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
2699void 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
2722void 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
2734void Browser::TabDetachedAt(TabContentsWrapper* contents, int index) {
2735  TabDetachedAtImpl(contents, index, DETACH_TYPE_DETACH);
2736}
2737
2738void 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
2747void 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
2803void 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
2811void 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
2841void 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
2853void 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
2869void 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(&params);
2883}
2884
2885void 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
2897void 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(&params);
2939}
2940
2941void Browser::ActivateContents(TabContents* contents) {
2942  tab_handler_->GetTabStripModel()->ActivateTabAt(
2943      tab_handler_->GetTabStripModel()->GetWrapperIndex(contents), false);
2944  window_->Activate();
2945}
2946
2947void Browser::DeactivateContents(TabContents* contents) {
2948  window_->Deactivate();
2949}
2950
2951void 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
2981void 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
3001void 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
3009void Browser::DetachContents(TabContents* source) {
3010  int index = tab_handler_->GetTabStripModel()->GetWrapperIndex(source);
3011  if (index >= 0)
3012    tab_handler_->GetTabStripModel()->DetachTabContentsAt(index);
3013}
3014
3015bool Browser::IsPopup(const TabContents* source) const {
3016  // A non-tabbed BROWSER is an unconstrained popup.
3017  return !!(type() & TYPE_POPUP);
3018}
3019
3020void 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
3032void 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
3043void Browser::UpdateDownloadShelfVisibility(bool visible) {
3044  if (GetStatusBubble())
3045    GetStatusBubble()->UpdateDownloadShelfVisibility(visible);
3046}
3047
3048bool Browser::UseVerticalTabs() const {
3049  return use_vertical_tabs_.GetValue();
3050}
3051
3052void Browser::ContentsZoomChange(bool zoom_in) {
3053  ExecuteCommand(zoom_in ? IDC_ZOOM_PLUS : IDC_ZOOM_MINUS);
3054}
3055
3056void 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
3064void 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
3073void Browser::TabContentsFocused(TabContents* tab_content) {
3074  window_->TabContentsFocused(tab_content);
3075}
3076
3077bool 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
3085bool Browser::IsApplication() const {
3086  return (type_ & TYPE_APP) != 0;
3087}
3088
3089void 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
3105bool Browser::ShouldDisplayURLField() {
3106  return !IsApplication();
3107}
3108
3109void 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
3141void Browser::ShowHtmlDialog(HtmlDialogUIDelegate* delegate,
3142                             gfx::NativeWindow parent_window) {
3143  window_->ShowHTMLDialog(delegate, parent_window);
3144}
3145
3146void 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
3157void Browser::RenderWidgetShowing() {
3158  window_->DisableInactiveFrame();
3159}
3160
3161int Browser::GetExtraRenderViewHeight() const {
3162  return window_->GetExtraRenderViewHeight();
3163}
3164
3165void 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
3208void 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
3215void 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
3222void 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
3231bool Browser::PreHandleKeyboardEvent(const NativeWebKeyboardEvent& event,
3232                                     bool* is_keyboard_shortcut) {
3233  return window()->PreHandleKeyboardEvent(event, is_keyboard_shortcut);
3234}
3235
3236void Browser::HandleKeyboardEvent(const NativeWebKeyboardEvent& event) {
3237  window()->HandleKeyboardEvent(event);
3238}
3239
3240void Browser::ShowRepostFormWarningDialog(TabContents *tab_contents) {
3241  window()->ShowRepostFormWarningDialog(tab_contents);
3242}
3243
3244void Browser::ShowContentSettingsPage(ContentSettingsType content_type) {
3245  ShowOptionsTab(
3246      chrome::kContentSettingsExceptionsSubPage + std::string(kHashMark) +
3247      ContentSettingsHandler::ContentSettingsTypeToGroupName(content_type));
3248}
3249
3250void Browser::ShowCollectedCookiesDialog(TabContents *tab_contents) {
3251  window()->ShowCollectedCookiesDialog(tab_contents);
3252}
3253
3254bool 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
3261void Browser::ContentRestrictionsChanged(TabContents* source) {
3262  UpdateCommandsForContentRestrictionState();
3263}
3264
3265void 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
3276void Browser::URLStarredChanged(TabContentsWrapper* source, bool starred) {
3277  if (source == GetSelectedTabContentsWrapper())
3278    window_->SetStarredState(starred);
3279}
3280
3281void 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
3307void 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
3323void 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
3331void Browser::ConfirmAddSearchProvider(const TemplateURL* template_url,
3332                                       Profile* profile) {
3333  window()->ConfirmAddSearchProvider(template_url, profile);
3334}
3335
3336///////////////////////////////////////////////////////////////////////////////
3337// Browser, SelectFileDialog::Listener implementation:
3338
3339void 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
3349void 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
3476void 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
3492void Browser::PrepareForInstant() {
3493  window_->PrepareForInstant();
3494}
3495
3496void Browser::ShowInstant(TabContentsWrapper* preview_contents) {
3497  DCHECK(instant_->tab_contents() == GetSelectedTabContentsWrapper());
3498  window_->ShowInstant(preview_contents);
3499}
3500
3501void Browser::HideInstant() {
3502  window_->HideInstant(instant_->is_active());
3503}
3504
3505void 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
3525void Browser::SetSuggestedText(const string16& text,
3526                               InstantCompleteBehavior behavior) {
3527  window()->GetLocationBar()->SetSuggestedText(text, behavior);
3528}
3529
3530gfx::Rect Browser::GetInstantBounds() {
3531  return window()->GetInstantBounds();
3532}
3533
3534///////////////////////////////////////////////////////////////////////////////
3535// Browser, protected:
3536
3537BrowserWindow* 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
3549void 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
3704void 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
3755void 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
3777void 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
3787void Browser::UpdateReloadStopState(bool is_loading, bool force) {
3788  window_->UpdateReloadStopState(is_loading, force);
3789  command_updater_.UpdateCommandEnabled(IDC_STOP, is_loading);
3790}
3791
3792void 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
3802void 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
3815void Browser::UpdateToolbar(bool should_restore_state) {
3816  window_->UpdateToolbar(GetSelectedTabContentsWrapper(), should_restore_state);
3817}
3818
3819void 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
3879void 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
3944void 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
3957StatusBubble* 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
3969void 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
3991void 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
4039bool 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
4045void 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
4061bool 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
4072void 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
4092void 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
4118bool 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
4194Browser* Browser::GetTabbedBrowser(Profile* profile, bool match_incognito) {
4195  return BrowserList::FindBrowserWithType(profile, TYPE_NORMAL,
4196                                          match_incognito);
4197}
4198
4199// static
4200Browser* Browser::GetOrCreateTabbedBrowser(Profile* profile) {
4201  Browser* browser = GetTabbedBrowser(profile, false);
4202  if (!browser)
4203    browser = Browser::Create(profile);
4204  return browser;
4205}
4206
4207void 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
4213void 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
4228void Browser::CloseFrame() {
4229  window_->Close();
4230}
4231
4232void 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
4270void 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
4289void Browser::TabRestoreServiceChanged(TabRestoreService* service) {
4290  command_updater_.UpdateCommandEnabled(IDC_RESTORE_TAB,
4291                                        !service->entries().empty());
4292}
4293
4294void 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.
4305TabContentsWrapper* 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
4318bool 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
4352void 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
4360void 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
4370void 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