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