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