The find bar should be owned and managed from the BrowserView, not the WebContentsVie...
[chromium-blink-merge.git] / chrome / browser / browser.cc
blob9c479a6f9aef4912b8b0281fe56456c915320c9f
1 // Copyright (c) 2006-2008 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.
5 #include "chrome/browser/browser.h"
7 #include "base/command_line.h"
8 #include "base/idle_timer.h"
9 #include "base/logging.h"
10 #include "base/string_util.h"
11 #include "chrome/app/chrome_dll_resource.h"
12 #include "chrome/browser/bookmarks/bookmark_model.h"
13 #include "chrome/browser/browser_list.h"
14 #include "chrome/browser/browser_shutdown.h"
15 #include "chrome/browser/location_bar.h"
16 #include "chrome/browser/metrics/user_metrics.h"
17 #include "chrome/browser/net/url_fixer_upper.h"
18 #include "chrome/browser/profile.h"
19 #include "chrome/browser/sessions/session_service.h"
20 #include "chrome/browser/sessions/session_types.h"
21 #include "chrome/browser/sessions/tab_restore_service.h"
22 #include "chrome/browser/tab_contents/interstitial_page.h"
23 #include "chrome/browser/tab_contents/navigation_controller.h"
24 #include "chrome/browser/tab_contents/navigation_entry.h"
25 #include "chrome/browser/tab_contents/site_instance.h"
26 #include "chrome/browser/tab_contents/tab_contents_type.h"
27 #include "chrome/browser/tab_contents/web_contents.h"
28 #include "chrome/common/chrome_constants.h"
29 #include "chrome/common/chrome_switches.h"
30 #include "chrome/common/l10n_util.h"
31 #include "chrome/common/notification_service.h"
32 #include "chrome/common/page_transition_types.h"
33 #include "chrome/common/pref_names.h"
34 #include "chrome/common/pref_service.h"
35 #ifdef CHROME_PERSONALIZATION
36 #include "chrome/personalization/personalization.h"
37 #endif
38 #include "net/base/cookie_monster.h"
39 #include "net/base/cookie_policy.h"
40 #include "net/base/net_util.h"
41 #include "net/base/registry_controlled_domain.h"
42 #include "net/url_request/url_request_context.h"
43 #include "webkit/glue/window_open_disposition.h"
45 #if defined(OS_WIN) || defined(OS_LINUX)
46 #include "chrome/browser/status_bubble.h"
47 #endif
49 #if defined(OS_WIN)
51 #include <windows.h>
52 #include <shellapi.h>
54 #include "chrome/browser/automation/ui_controls.h"
55 #include "chrome/browser/browser_process.h"
56 #include "chrome/browser/browser_url_handler.h"
57 #include "chrome/browser/browser_window.h"
58 #include "chrome/browser/cert_store.h"
59 #include "chrome/browser/character_encoding.h"
60 #include "chrome/browser/debugger/debugger_window.h"
61 #include "chrome/browser/dock_info.h"
62 #include "chrome/browser/dom_ui/new_tab_ui.h"
63 #include "chrome/browser/download/save_package.h"
64 #include "chrome/browser/history_tab_ui.h"
65 #include "chrome/browser/options_window.h"
66 #include "chrome/browser/ssl/ssl_error_info.h"
67 #include "chrome/browser/tab_contents/web_contents_view.h"
68 #include "chrome/browser/task_manager.h"
69 #include "chrome/browser/user_data_manager.h"
70 #include "chrome/browser/view_ids.h"
71 #include "chrome/browser/views/download_tab_view.h"
72 #include "chrome/browser/views/location_bar_view.h"
73 #include "chrome/browser/window_sizer.h"
74 #include "chrome/common/child_process_host.h"
75 #include "chrome/common/win_util.h"
76 #include "grit/chromium_strings.h"
77 #include "grit/generated_resources.h"
78 #include "grit/locale_settings.h"
80 #endif // OS_WIN
82 using base::TimeDelta;
84 // How long we wait before updating the browser chrome while loading a page.
85 static const int kUIUpdateCoalescingTimeMS = 200;
87 // Idle time before helping prune memory consumption.
88 static const int kBrowserReleaseMemoryInterval = 30; // In seconds.
90 // How much horizontal and vertical offset there is between newly opened
91 // windows.
92 static const int kWindowTilePixels = 20;
94 ///////////////////////////////////////////////////////////////////////////////
96 // A task to reduce the working set of the child processes that live on the IO
97 // thread (i.e. plugins, workers).
98 class ReduceChildProcessesWorkingSetTask : public Task {
99 public:
100 virtual void Run() {
101 #if defined(OS_WIN)
102 for (ChildProcessHost::Iterator iter; !iter.Done(); ++iter)
103 iter->ReduceWorkingSet();
104 #endif
108 // A browser task to run when the user is not using the browser.
109 // In our case, we're trying to be nice to the operating system and release
110 // memory not in use.
111 class BrowserIdleTimer : public base::IdleTimer {
112 public:
113 BrowserIdleTimer()
114 : base::IdleTimer(TimeDelta::FromSeconds(kBrowserReleaseMemoryInterval),
115 false) {
118 virtual void OnIdle() {
119 #if defined(OS_WIN)
120 // We're idle. Release browser and renderer unused pages.
122 // Handle the Browser.
123 base::Process process(GetCurrentProcess());
124 process.ReduceWorkingSet();
126 // Handle the Renderer(s).
127 RenderProcessHost::iterator renderer_iter;
128 for (renderer_iter = RenderProcessHost::begin(); renderer_iter !=
129 RenderProcessHost::end(); renderer_iter++) {
130 base::Process process = renderer_iter->second->process();
131 process.ReduceWorkingSet();
134 // Handle the child processe. We need to iterate through them on the IO
135 // thread because that thread manages the child process collection.
136 g_browser_process->io_thread()->message_loop()->PostTask(FROM_HERE,
137 new ReduceChildProcessesWorkingSetTask());
138 #endif
142 ///////////////////////////////////////////////////////////////////////////////
144 struct Browser::UIUpdate {
145 UIUpdate(const TabContents* src, unsigned flags)
146 : source(src),
147 changed_flags(flags) {
150 // The source of the update.
151 const TabContents* source;
153 // What changed in the UI.
154 unsigned changed_flags;
157 namespace {
159 // Returns true if the specified TabContents has unload listeners registered.
160 bool TabHasUnloadListener(TabContents* contents) {
161 WebContents* web_contents = contents->AsWebContents();
162 return web_contents && web_contents->notify_disconnection() &&
163 !web_contents->showing_interstitial_page() &&
164 web_contents->render_view_host()->HasUnloadListener();
167 } // namespace
169 ///////////////////////////////////////////////////////////////////////////////
170 // Browser, Constructors, Creation, Showing:
172 Browser::Browser(Type type, Profile* profile)
173 : type_(type),
174 profile_(profile),
175 window_(NULL),
176 tabstrip_model_(this, profile),
177 command_updater_(this),
178 toolbar_model_(this),
179 chrome_updater_factory_(this),
180 is_attempting_to_close_browser_(false),
181 override_maximized_(false),
182 method_factory_(this),
183 idle_task_(new BrowserIdleTimer) {
184 tabstrip_model_.AddObserver(this);
186 NotificationService::current()->AddObserver(
187 this,
188 NotificationType::SSL_STATE_CHANGED,
189 NotificationService::AllSources());
191 InitCommandState();
192 BrowserList::AddBrowser(this);
194 encoding_auto_detect_.Init(prefs::kWebKitUsesUniversalDetector,
195 profile_->GetPrefs(), NULL);
197 // Trim browser memory on idle for low & medium memory models.
198 if (g_browser_process->memory_model() < BrowserProcess::HIGH_MEMORY_MODEL)
199 idle_task_->Start();
202 Browser::~Browser() {
203 // The tab strip should be empty at this point.
204 #if !defined(OS_LINUX)
205 // TODO(erg): Temporarily disabling this DCHECK while we build the linux
206 // views system. We don't have a tabstrip model up yet.
207 DCHECK(tabstrip_model_.empty());
208 #endif
209 tabstrip_model_.RemoveObserver(this);
211 BrowserList::RemoveBrowser(this);
213 if (!BrowserList::HasBrowserWithProfile(profile_)) {
214 // We're the last browser window with this profile. We need to nuke the
215 // TabRestoreService, which will start the shutdown of the
216 // NavigationControllers and allow for proper shutdown. If we don't do this
217 // chrome won't shutdown cleanly, and may end up crashing when some
218 // thread tries to use the IO thread (or another thread) that is no longer
219 // valid.
220 profile_->ResetTabRestoreService();
223 SessionService* session_service = profile_->GetSessionService();
224 if (session_service)
225 session_service->WindowClosed(session_id_);
227 TabRestoreService* tab_restore_service = profile()->GetTabRestoreService();
228 if (tab_restore_service)
229 tab_restore_service->BrowserClosed(this);
231 NotificationService::current()->RemoveObserver(
232 this,
233 NotificationType::SSL_STATE_CHANGED,
234 NotificationService::AllSources());
236 if (profile_->IsOffTheRecord() &&
237 !BrowserList::IsOffTheRecordSessionActive()) {
238 // We reuse the OTR cookie store across OTR windows. If the last OTR
239 // window is closed, then we want to wipe the cookie store clean, so when
240 // an OTR window is open again, it starts with an empty cookie store. This
241 // also frees up the memory that the OTR cookies were using. OTR never
242 // loads or writes persistent cookies (there is no backing store), so we
243 // can just delete all of the cookies in the store.
244 profile_->GetRequestContext()->cookie_store()->DeleteAll(false);
247 // There may be pending file dialogs, we need to tell them that we've gone
248 // away so they don't try and call back to us.
249 if (select_file_dialog_.get())
250 select_file_dialog_->ListenerDestroyed();
253 // static
254 Browser* Browser::Create(Profile* profile) {
255 Browser* browser = new Browser(TYPE_NORMAL, profile);
256 browser->CreateBrowserWindow();
257 return browser;
260 // static
261 Browser* Browser::CreateForPopup(Profile* profile) {
262 Browser* browser = new Browser(TYPE_POPUP, profile);
263 browser->CreateBrowserWindow();
264 return browser;
267 // static
268 Browser* Browser::CreateForApp(const std::wstring& app_name,
269 Profile* profile) {
270 Browser* browser = new Browser(TYPE_APP, profile);
271 browser->app_name_ = app_name;
272 browser->CreateBrowserWindow();
273 return browser;
276 void Browser::CreateBrowserWindow() {
277 DCHECK(!window_);
278 window_ = BrowserWindow::CreateBrowserWindow(this);
280 // Show the First Run information bubble if we've been told to.
281 PrefService* local_state = g_browser_process->local_state();
282 if (!local_state)
283 return;
284 if (local_state->IsPrefRegistered(prefs::kShouldShowFirstRunBubble) &&
285 local_state->GetBoolean(prefs::kShouldShowFirstRunBubble)) {
286 // Reset the preference so we don't show the bubble for subsequent windows.
287 local_state->ClearPref(prefs::kShouldShowFirstRunBubble);
288 window_->GetLocationBar()->ShowFirstRunBubble();
292 ///////////////////////////////////////////////////////////////////////////////
293 // Browser, Creation Helpers:
295 // static
296 void Browser::OpenEmptyWindow(Profile* profile) {
297 Browser* browser = Browser::Create(profile);
298 browser->AddBlankTab(true);
299 browser->window()->Show();
302 // static
303 void Browser::OpenURLOffTheRecord(Profile* profile, const GURL& url) {
304 Profile* off_the_record_profile = profile->GetOffTheRecordProfile();
305 Browser* browser = BrowserList::FindBrowserWithType(
306 off_the_record_profile,
307 TYPE_NORMAL);
308 if (!browser)
309 browser = Browser::Create(off_the_record_profile);
310 // TODO(eroman): should we have referrer here?
311 browser->AddTabWithURL(url, GURL(), PageTransition::LINK, true, NULL);
312 browser->window()->Show();
315 // static
316 void Browser::OpenApplicationWindow(Profile* profile, const GURL& url) {
317 std::wstring app_name = ComputeApplicationNameFromURL(url);
318 RegisterAppPrefs(app_name);
320 Browser* browser = Browser::CreateForApp(app_name, profile);
321 browser->AddTabWithURL(url, GURL(), PageTransition::START_PAGE, true, NULL);
322 browser->window()->Show();
325 ///////////////////////////////////////////////////////////////////////////////
326 // Browser, State Storage and Retrieval for UI:
328 std::wstring Browser::GetWindowPlacementKey() const {
329 std::wstring name(prefs::kBrowserWindowPlacement);
330 if (!app_name_.empty()) {
331 name.append(L"_");
332 name.append(app_name_);
334 return name;
337 bool Browser::ShouldSaveWindowPlacement() const {
338 // We don't save window position for popups.
339 return type() != TYPE_POPUP;
342 void Browser::SaveWindowPlacement(const gfx::Rect& bounds, bool maximized) {
343 // Save to the session storage service, used when reloading a past session.
344 // Note that we don't want to be the ones who cause lazy initialization of
345 // the session service. This function gets called during initial window
346 // showing, and we don't want to bring in the session service this early.
347 if (profile()->HasSessionService()) {
348 SessionService* session_service = profile()->GetSessionService();
349 if (session_service)
350 session_service->SetWindowBounds(session_id_, bounds, maximized);
354 gfx::Rect Browser::GetSavedWindowBounds() const {
355 const CommandLine& parsed_command_line = *CommandLine::ForCurrentProcess();
356 bool record_mode = parsed_command_line.HasSwitch(switches::kRecordMode);
357 bool playback_mode = parsed_command_line.HasSwitch(switches::kPlaybackMode);
358 if (record_mode || playback_mode) {
359 // In playback/record mode we always fix the size of the browser and
360 // move it to (0,0). The reason for this is two reasons: First we want
361 // resize/moves in the playback to still work, and Second we want
362 // playbacks to work (as much as possible) on machines w/ different
363 // screen sizes.
364 return gfx::Rect(0, 0, 800, 600);
367 gfx::Rect restored_bounds = override_bounds_;
368 bool maximized;
369 WindowSizer::GetBrowserWindowBounds(app_name_, restored_bounds,
370 &restored_bounds, &maximized);
371 return restored_bounds;
374 // TODO(beng): obtain maximized state some other way so we don't need to go
375 // through all this hassle.
376 bool Browser::GetSavedMaximizedState() const {
377 if (CommandLine::ForCurrentProcess()->HasSwitch(switches::kStartMaximized))
378 return true;
380 gfx::Rect restored_bounds;
381 bool maximized = override_maximized_;
382 WindowSizer::GetBrowserWindowBounds(app_name_, restored_bounds,
383 &restored_bounds, &maximized);
384 return maximized;
387 SkBitmap Browser::GetCurrentPageIcon() const {
388 TabContents* contents = GetSelectedTabContents();
389 // |contents| can be NULL since GetCurrentPageIcon() is called by the window
390 // during the window's creation (before tabs have been added).
391 return contents ? contents->GetFavIcon() : SkBitmap();
394 std::wstring Browser::GetCurrentPageTitle() const {
395 #if defined(OS_WIN)
396 TabContents* contents = tabstrip_model_.GetSelectedTabContents();
397 std::wstring title;
399 // |contents| can be NULL because GetCurrentPageTitle is called by the window
400 // during the window's creation (before tabs have been added).
401 if (contents) {
402 title = contents->GetTitle();
403 FormatTitleForDisplay(&title);
405 if (title.empty())
406 title = l10n_util::GetString(IDS_TAB_UNTITLED_TITLE);
408 return l10n_util::GetStringF(IDS_BROWSER_WINDOW_TITLE_FORMAT, title);
409 #elif defined(OS_POSIX)
410 // TODO(port): turn on when generating chrome_strings.h from grit
411 return L"untitled";
412 #endif
415 // static
416 void Browser::FormatTitleForDisplay(std::wstring* title) {
417 size_t current_index = 0;
418 size_t match_index;
419 while ((match_index = title->find(L'\n', current_index)) !=
420 std::wstring::npos) {
421 title->replace(match_index, 1, L"");
422 current_index = match_index;
427 ///////////////////////////////////////////////////////////////////////////////
428 // Browser, OnBeforeUnload handling:
430 bool Browser::ShouldCloseWindow() {
431 if (HasCompletedUnloadProcessing()) {
432 return true;
434 is_attempting_to_close_browser_ = true;
436 for (int i = 0; i < tab_count(); ++i) {
437 TabContents* contents = GetTabContentsAt(i);
438 if (TabHasUnloadListener(contents))
439 tabs_needing_before_unload_fired_.insert(contents);
442 if (tabs_needing_before_unload_fired_.empty())
443 return true;
445 ProcessPendingTabs();
446 return false;
449 void Browser::OnWindowClosing() {
450 if (!ShouldCloseWindow())
451 return;
453 #if defined(OS_WIN) || defined(OS_LINUX)
454 // We don't want to do this on Mac since closing all windows isn't a sign
455 // that the app is shutting down.
456 if (BrowserList::size() == 1)
457 browser_shutdown::OnShutdownStarting(browser_shutdown::WINDOW_CLOSE);
458 #endif
460 // Don't use HasSessionService here, we want to force creation of the
461 // session service so that user can restore what was open.
462 SessionService* session_service = profile()->GetSessionService();
463 if (session_service)
464 session_service->WindowClosing(session_id());
466 TabRestoreService* tab_restore_service = profile()->GetTabRestoreService();
467 if (tab_restore_service)
468 tab_restore_service->BrowserClosing(this);
470 CloseAllTabs();
473 ///////////////////////////////////////////////////////////////////////////////
474 // Browser, Tab adding/showing functions:
476 TabContents* Browser::AddTabWithURL(
477 const GURL& url, const GURL& referrer, PageTransition::Type transition,
478 bool foreground, SiteInstance* instance) {
479 if (type_ == TYPE_APP && tabstrip_model_.count() == 1) {
480 NOTREACHED() << "Cannot add a tab in a mono tab application.";
481 return NULL;
484 GURL url_to_load = url;
485 if (url_to_load.is_empty())
486 url_to_load = GetHomePage();
487 TabContents* contents =
488 CreateTabContentsForURL(url_to_load, referrer, profile_, transition,
489 false, instance);
490 tabstrip_model_.AddTabContents(contents, -1, transition, foreground);
491 // By default, content believes it is not hidden. When adding contents
492 // in the background, tell it that it's hidden.
493 if (!foreground)
494 contents->WasHidden();
495 return contents;
498 TabContents* Browser::AddTabWithNavigationController(
499 NavigationController* ctrl, PageTransition::Type type) {
500 TabContents* tc = ctrl->active_contents();
501 tabstrip_model_.AddTabContents(tc, -1, type, true);
502 return tc;
505 NavigationController* Browser::AddRestoredTab(
506 const std::vector<TabNavigation>& navigations,
507 int tab_index,
508 int selected_navigation,
509 bool select) {
510 NavigationController* restored_controller =
511 BuildRestoredNavigationController(navigations, selected_navigation);
513 tabstrip_model_.InsertTabContentsAt(
514 tab_index,
515 restored_controller->active_contents(),
516 select, false);
517 if (profile_->HasSessionService()) {
518 SessionService* session_service = profile_->GetSessionService();
519 if (session_service)
520 session_service->TabRestored(restored_controller);
522 return restored_controller;
525 void Browser::ReplaceRestoredTab(
526 const std::vector<TabNavigation>& navigations,
527 int selected_navigation) {
528 NavigationController* restored_controller =
529 BuildRestoredNavigationController(navigations, selected_navigation);
531 tabstrip_model_.ReplaceNavigationControllerAt(
532 tabstrip_model_.selected_index(),
533 restored_controller);
536 void Browser::ShowNativeUITab(const GURL& url) {
537 int i, c;
538 TabContents* tc;
539 for (i = 0, c = tabstrip_model_.count(); i < c; ++i) {
540 tc = tabstrip_model_.GetTabContentsAt(i);
541 if (tc->type() == TAB_CONTENTS_NATIVE_UI &&
542 tc->GetURL() == url) {
543 tabstrip_model_.SelectTabContentsAt(i, false);
544 return;
548 TabContents* contents = CreateTabContentsForURL(url, GURL(), profile_,
549 PageTransition::LINK, false,
550 NULL);
551 AddNewContents(NULL, contents, NEW_FOREGROUND_TAB, gfx::Rect(), true);
554 ///////////////////////////////////////////////////////////////////////////////
555 // Browser, Assorted browser commands:
557 void Browser::GoBack() {
558 UserMetrics::RecordAction(L"Back", profile_);
560 // If we are showing an interstitial, just hide it.
561 TabContents* current_tab = GetSelectedTabContents();
562 WebContents* web_contents = current_tab->AsWebContents();
563 if (web_contents && web_contents->interstitial_page()) {
564 // The GoBack() case is a special case when an interstitial is shown because
565 // the "previous" page is still available, just hidden by the interstitial.
566 // We treat the back as a "Don't proceed", this hides the interstitial and
567 // reveals the previous page.
568 web_contents->interstitial_page()->DontProceed();
569 return;
571 if (current_tab->controller()->CanGoBack())
572 current_tab->controller()->GoBack();
575 void Browser::GoForward() {
576 UserMetrics::RecordAction(L"Forward", profile_);
577 if (GetSelectedTabContents()->controller()->CanGoForward())
578 GetSelectedTabContents()->controller()->GoForward();
581 void Browser::Reload() {
582 UserMetrics::RecordAction(L"Reload", profile_);
584 // If we are showing an interstitial, treat this as an OpenURL.
585 TabContents* current_tab = GetSelectedTabContents();
586 if (current_tab) {
587 WebContents* web_contents = current_tab->AsWebContents();
588 if (web_contents && web_contents->showing_interstitial_page()) {
589 NavigationEntry* entry = current_tab->controller()->GetActiveEntry();
590 DCHECK(entry); // Should exist if interstitial is showing.
591 OpenURL(entry->url(), GURL(), CURRENT_TAB, PageTransition::RELOAD);
592 return;
596 if (current_tab) {
597 // As this is caused by a user action, give the focus to the page.
598 current_tab->Focus();
599 current_tab->controller()->Reload(true);
603 void Browser::Home() {
604 UserMetrics::RecordAction(L"Home", profile_);
605 GURL homepage_url = GetHomePage();
606 GetSelectedTabContents()->controller()->LoadURL(
607 homepage_url, GURL(), PageTransition::AUTO_BOOKMARK);
610 void Browser::OpenCurrentURL() {
611 UserMetrics::RecordAction(L"LoadURL", profile_);
612 LocationBar* location_bar = window_->GetLocationBar();
613 OpenURL(GURL(WideToUTF8(location_bar->GetInputString())), GURL(),
614 location_bar->GetWindowOpenDisposition(),
615 location_bar->GetPageTransition());
618 void Browser::Go() {
619 UserMetrics::RecordAction(L"Go", profile_);
620 window_->GetLocationBar()->AcceptInput();
623 void Browser::Stop() {
624 UserMetrics::RecordAction(L"Stop", profile_);
625 GetSelectedTabContents()->Stop();
628 void Browser::NewWindow() {
629 UserMetrics::RecordAction(L"NewWindow", profile_);
630 Browser::OpenEmptyWindow(profile_->GetOriginalProfile());
633 void Browser::NewIncognitoWindow() {
634 UserMetrics::RecordAction(L"NewIncognitoWindow", profile_);
635 Browser::OpenEmptyWindow(profile_->GetOffTheRecordProfile());
638 void Browser::NewProfileWindowByIndex(int index) {
639 #if defined(OS_WIN)
640 UserMetrics::RecordAction(L"NewProfileWindowByIndex", profile_);
641 UserDataManager::Get()->LaunchChromeForProfile(index);
642 #endif
645 void Browser::CloseWindow() {
646 UserMetrics::RecordAction(L"CloseWindow", profile_);
647 window_->Close();
650 void Browser::NewTab() {
651 UserMetrics::RecordAction(L"NewTab", profile_);
652 if (type() == TYPE_NORMAL) {
653 AddBlankTab(true);
654 } else {
655 Browser* b = GetOrCreateTabbedBrowser();
656 b->AddBlankTab(true);
657 b->window()->Show();
658 // The call to AddBlankTab above did not set the focus to the tab as its
659 // window was not active, so we have to do it explicitly.
660 // See http://crbug.com/6380.
661 TabContents* tab = b->GetSelectedTabContents();
662 tab->RestoreFocus();
666 void Browser::CloseTab() {
667 UserMetrics::RecordAction(L"CloseTab_Accelerator", profile_);
668 tabstrip_model_.CloseTabContentsAt(tabstrip_model_.selected_index());
671 void Browser::SelectNextTab() {
672 UserMetrics::RecordAction(L"SelectNextTab", profile_);
673 tabstrip_model_.SelectNextTab();
676 void Browser::SelectPreviousTab() {
677 UserMetrics::RecordAction(L"SelectPrevTab", profile_);
678 tabstrip_model_.SelectPreviousTab();
681 void Browser::SelectNumberedTab(int index) {
682 if (index < tab_count()) {
683 UserMetrics::RecordAction(L"SelectNumberedTab", profile_);
684 tabstrip_model_.SelectTabContentsAt(index, true);
688 void Browser::SelectLastTab() {
689 UserMetrics::RecordAction(L"SelectLastTab", profile_);
690 tabstrip_model_.SelectLastTab();
693 void Browser::DuplicateTab() {
694 UserMetrics::RecordAction(L"Duplicate", profile_);
695 DuplicateContentsAt(selected_index());
698 void Browser::RestoreTab() {
699 UserMetrics::RecordAction(L"RestoreTab", profile_);
700 TabRestoreService* service = profile_->GetTabRestoreService();
701 if (!service)
702 return;
704 service->RestoreMostRecentEntry(this);
707 void Browser::ConvertPopupToTabbedBrowser() {
708 UserMetrics::RecordAction(L"ShowAsTab", profile_);
709 int tab_strip_index = tabstrip_model_.selected_index();
710 TabContents* contents = tabstrip_model_.DetachTabContentsAt(tab_strip_index);
711 Browser* browser = Browser::Create(profile_);
712 browser->tabstrip_model()->AppendTabContents(contents, true);
713 browser->window()->Show();
716 void Browser::ToggleFullscreenMode() {
717 UserMetrics::RecordAction(L"ToggleFullscreen", profile_);
718 window_->SetFullscreen(!window_->IsFullscreen());
719 UpdateCommandsForFullscreenMode(window_->IsFullscreen());
722 void Browser::Exit() {
723 UserMetrics::RecordAction(L"Exit", profile_);
724 BrowserList::CloseAllBrowsers(true);
727 void Browser::BookmarkCurrentPage() {
728 UserMetrics::RecordAction(L"Star", profile_);
730 TabContents* contents = GetSelectedTabContents();
731 BookmarkModel* model = contents->profile()->GetBookmarkModel();
732 if (!model || !model->IsLoaded())
733 return; // Ignore requests until bookmarks are loaded.
735 NavigationEntry* entry = contents->controller()->GetActiveEntry();
736 if (!entry)
737 return; // Can't star if there is no URL.
738 const GURL& url = entry->display_url();
739 if (url.is_empty() || !url.is_valid())
740 return;
742 model->SetURLStarred(url, entry->title(), true);
743 window_->ShowBookmarkBubble(url, model->IsBookmarked(url));
746 void Browser::ViewSource() {
747 UserMetrics::RecordAction(L"ViewSource", profile_);
749 TabContents* current_tab = GetSelectedTabContents();
750 NavigationEntry* entry = current_tab->controller()->GetLastCommittedEntry();
751 if (entry) {
752 GURL url("view-source:" + entry->url().spec());
753 OpenURL(url, GURL(), NEW_FOREGROUND_TAB, PageTransition::LINK);
757 #if defined(OS_WIN)
759 void Browser::ClosePopups() {
760 UserMetrics::RecordAction(L"CloseAllSuppressedPopups", profile_);
761 GetSelectedTabContents()->CloseAllSuppressedPopups();
764 void Browser::Print() {
765 UserMetrics::RecordAction(L"PrintPreview", profile_);
766 GetSelectedTabContents()->AsWebContents()->PrintPreview();
769 void Browser::SavePage() {
770 UserMetrics::RecordAction(L"SavePage", profile_);
771 GetSelectedTabContents()->AsWebContents()->OnSavePage();
774 void Browser::ToggleEncodingAutoDetect() {
775 UserMetrics::RecordAction(L"AutoDetectChange", profile_);
776 encoding_auto_detect_.SetValue(!encoding_auto_detect_.GetValue());
777 // Reload the page so we can try to auto-detect the charset.
778 Reload();
781 void Browser::OverrideEncoding(int encoding_id) {
782 UserMetrics::RecordAction(L"OverrideEncoding", profile_);
783 const std::wstring selected_encoding =
784 CharacterEncoding::GetCanonicalEncodingNameByCommandId(encoding_id);
785 WebContents* current_web_contents = GetSelectedTabContents()->AsWebContents();
786 if (!selected_encoding.empty() && current_web_contents)
787 current_web_contents->override_encoding(selected_encoding);
788 // Update the list of recently selected encodings.
789 std::wstring new_selected_encoding_list;
790 if (CharacterEncoding::UpdateRecentlySelectdEncoding(
791 profile_->GetPrefs()->GetString(prefs::kRecentlySelectedEncoding),
792 encoding_id,
793 &new_selected_encoding_list)) {
794 profile_->GetPrefs()->SetString(prefs::kRecentlySelectedEncoding,
795 new_selected_encoding_list);
799 // TODO(devint): http://b/issue?id=1117225 Cut, Copy, and Paste are always
800 // enabled in the page menu regardless of whether the command will do
801 // anything. When someone selects the menu item, we just act as if they hit
802 // the keyboard shortcut for the command by sending the associated key press
803 // to windows. The real fix to this bug is to disable the commands when they
804 // won't do anything. We'll need something like an overall clipboard command
805 // manager to do that.
807 void Browser::Cut() {
808 UserMetrics::RecordAction(L"Cut", profile_);
809 ui_controls::SendKeyPress(L'X', true, false, false);
812 void Browser::Copy() {
813 UserMetrics::RecordAction(L"Copy", profile_);
814 ui_controls::SendKeyPress(L'C', true, false, false);
817 void Browser::CopyCurrentPageURL() {
818 UserMetrics::RecordAction(L"CopyURLToClipBoard", profile_);
819 std::string url = GetSelectedTabContents()->GetURL().spec();
821 if (!::OpenClipboard(NULL)) {
822 NOTREACHED();
823 return;
826 if (::EmptyClipboard()) {
827 HGLOBAL text = ::GlobalAlloc(GMEM_MOVEABLE, url.size() + 1);
828 LPSTR ptr = static_cast<LPSTR>(::GlobalLock(text));
829 memcpy(ptr, url.c_str(), url.size());
830 ptr[url.size()] = '\0';
831 ::GlobalUnlock(text);
833 ::SetClipboardData(CF_TEXT, text);
836 if (!::CloseClipboard()) {
837 NOTREACHED();
841 void Browser::Paste() {
842 UserMetrics::RecordAction(L"Paste", profile_);
843 ui_controls::SendKeyPress(L'V', true, false, false);
846 void Browser::Find() {
847 UserMetrics::RecordAction(L"Find", profile_);
848 FindInPage(false, false);
851 void Browser::FindNext() {
852 UserMetrics::RecordAction(L"FindNext", profile_);
853 FindInPage(true, true);
856 void Browser::FindPrevious() {
857 UserMetrics::RecordAction(L"FindPrevious", profile_);
858 FindInPage(true, false);
861 void Browser::ZoomIn() {
862 UserMetrics::RecordAction(L"ZoomPlus", profile_);
863 GetSelectedTabContents()->AsWebContents()->render_view_host()->Zoom(
864 PageZoom::LARGER);
867 void Browser::ZoomReset() {
868 UserMetrics::RecordAction(L"ZoomNormal", profile_);
869 GetSelectedTabContents()->AsWebContents()->render_view_host()->Zoom(
870 PageZoom::STANDARD);
873 void Browser::ZoomOut() {
874 UserMetrics::RecordAction(L"ZoomMinus", profile_);
875 GetSelectedTabContents()->AsWebContents()->render_view_host()->Zoom(
876 PageZoom::SMALLER);
879 void Browser::FocusToolbar() {
880 UserMetrics::RecordAction(L"FocusToolbar", profile_);
881 window_->FocusToolbar();
884 void Browser::FocusLocationBar() {
885 UserMetrics::RecordAction(L"FocusLocation", profile_);
886 window_->GetLocationBar()->FocusLocation();
889 void Browser::FocusSearch() {
890 // TODO(beng): replace this with FocusLocationBar
891 UserMetrics::RecordAction(L"FocusSearch", profile_);
892 window_->GetLocationBar()->FocusSearch();
895 void Browser::OpenFile() {
896 UserMetrics::RecordAction(L"OpenFile", profile_);
897 if (!select_file_dialog_.get())
898 select_file_dialog_ = SelectFileDialog::Create(this);
900 // TODO(beng): figure out how to juggle this.
901 HWND parent_hwnd = reinterpret_cast<HWND>(window_->GetNativeHandle());
902 select_file_dialog_->SelectFile(SelectFileDialog::SELECT_OPEN_FILE,
903 std::wstring(), std::wstring(),
904 std::wstring(), std::wstring(),
905 parent_hwnd, NULL);
908 void Browser::OpenCreateShortcutsDialog() {
909 UserMetrics::RecordAction(L"CreateShortcut", profile_);
910 GetSelectedTabContents()->AsWebContents()->CreateShortcut();
913 void Browser::OpenDebuggerWindow() {
914 #ifndef CHROME_DEBUGGER_DISABLED
915 UserMetrics::RecordAction(L"Debugger", profile_);
916 TabContents* current_tab = GetSelectedTabContents();
917 if (current_tab->AsWebContents()) {
918 // Only one debugger instance can exist at a time right now.
919 // TODO(erikkay): need an alert, dialog, something
920 // or better yet, fix the one instance limitation
921 if (!DebuggerWindow::DoesDebuggerExist())
922 debugger_window_ = new DebuggerWindow();
923 debugger_window_->Show(current_tab);
925 #endif
928 void Browser::OpenJavaScriptConsole() {
929 UserMetrics::RecordAction(L"ShowJSConsole", profile_);
930 GetSelectedTabContents()->AsWebContents()->render_view_host()->
931 ShowJavaScriptConsole();
934 void Browser::OpenTaskManager() {
935 UserMetrics::RecordAction(L"TaskManager", profile_);
936 TaskManager::Open();
939 void Browser::OpenSelectProfileDialog() {
940 UserMetrics::RecordAction(L"SelectProfile", profile_);
941 window_->ShowSelectProfileDialog();
944 void Browser::OpenNewProfileDialog() {
945 UserMetrics::RecordAction(L"CreateProfile", profile_);
946 window_->ShowNewProfileDialog();
949 void Browser::OpenBugReportDialog() {
950 UserMetrics::RecordAction(L"ReportBug", profile_);
951 window_->ShowReportBugDialog();
954 void Browser::ToggleBookmarkBar() {
955 UserMetrics::RecordAction(L"ShowBookmarksBar", profile_);
956 window_->ToggleBookmarkBar();
959 void Browser::ShowHistoryTab() {
960 UserMetrics::RecordAction(L"ShowHistory", profile_);
961 ShowNativeUITab(HistoryTabUI::GetURL());
964 void Browser::OpenBookmarkManager() {
965 UserMetrics::RecordAction(L"ShowBookmarkManager", profile_);
966 window_->ShowBookmarkManager();
969 void Browser::ShowDownloadsTab() {
970 UserMetrics::RecordAction(L"ShowDownloads", profile_);
971 ShowNativeUITab(DownloadTabUI::GetURL());
974 void Browser::OpenClearBrowsingDataDialog() {
975 UserMetrics::RecordAction(L"ClearBrowsingData_ShowDlg", profile_);
976 window_->ShowClearBrowsingDataDialog();
979 void Browser::OpenImportSettingsDialog() {
980 UserMetrics::RecordAction(L"Import_ShowDlg", profile_);
981 window_->ShowImportDialog();
984 void Browser::OpenOptionsDialog() {
985 UserMetrics::RecordAction(L"ShowOptions", profile_);
986 ShowOptionsWindow(OPTIONS_PAGE_DEFAULT, OPTIONS_GROUP_NONE, profile_);
989 void Browser::OpenKeywordEditor() {
990 UserMetrics::RecordAction(L"EditSearchEngines", profile_);
991 window_->ShowSearchEnginesDialog();
994 void Browser::OpenPasswordManager() {
995 window_->ShowPasswordManager();
998 void Browser::OpenAboutChromeDialog() {
999 UserMetrics::RecordAction(L"AboutChrome", profile_);
1000 window_->ShowAboutChromeDialog();
1003 void Browser::OpenHelpTab() {
1004 GURL help_url(l10n_util::GetString(IDS_HELP_CONTENT_URL));
1005 AddTabWithURL(help_url, GURL(), PageTransition::AUTO_BOOKMARK, true,
1006 NULL);
1009 #endif
1010 ///////////////////////////////////////////////////////////////////////////////
1012 // static
1013 void Browser::RegisterPrefs(PrefService* prefs) {
1014 prefs->RegisterDictionaryPref(prefs::kBrowserWindowPlacement);
1015 prefs->RegisterIntegerPref(prefs::kOptionsWindowLastTabIndex, 0);
1018 // static
1019 void Browser::RegisterUserPrefs(PrefService* prefs) {
1020 prefs->RegisterStringPref(prefs::kHomePage, L"chrome-internal:");
1021 prefs->RegisterBooleanPref(prefs::kHomePageIsNewTabPage, true);
1022 prefs->RegisterIntegerPref(prefs::kCookieBehavior,
1023 net::CookiePolicy::ALLOW_ALL_COOKIES);
1024 prefs->RegisterBooleanPref(prefs::kShowHomeButton, false);
1025 prefs->RegisterStringPref(prefs::kRecentlySelectedEncoding, L"");
1026 prefs->RegisterBooleanPref(prefs::kDeleteBrowsingHistory, true);
1027 prefs->RegisterBooleanPref(prefs::kDeleteDownloadHistory, true);
1028 prefs->RegisterBooleanPref(prefs::kDeleteCache, true);
1029 prefs->RegisterBooleanPref(prefs::kDeleteCookies, true);
1030 prefs->RegisterBooleanPref(prefs::kDeletePasswords, false);
1031 prefs->RegisterBooleanPref(prefs::kDeleteFormData, true);
1032 prefs->RegisterIntegerPref(prefs::kDeleteTimePeriod, 0);
1035 // static
1036 Browser* Browser::GetBrowserForController(
1037 const NavigationController* controller, int* index_result) {
1038 BrowserList::const_iterator it;
1039 for (it = BrowserList::begin(); it != BrowserList::end(); ++it) {
1040 int index = (*it)->tabstrip_model_.GetIndexOfController(controller);
1041 if (index != TabStripModel::kNoTab) {
1042 if (index_result)
1043 *index_result = index;
1044 return *it;
1048 return NULL;
1051 ///////////////////////////////////////////////////////////////////////////////
1052 // Browser, CommandUpdater::CommandUpdaterDelegate implementation:
1054 void Browser::ExecuteCommand(int id) {
1055 // No commands are enabled if there is not yet any selected tab.
1056 // TODO(pkasting): It seems like we should not need this, because either
1057 // most/all commands should not have been enabled yet anyway or the ones that
1058 // are enabled should be global, or safe themselves against having no selected
1059 // tab. However, Ben says he tried removing this before and got lots of
1060 // crashes, e.g. from Windows sending WM_COMMANDs at random times during
1061 // window construction. This probably could use closer examination someday.
1062 if (!GetSelectedTabContents())
1063 return;
1065 DCHECK(command_updater_.IsCommandEnabled(id)) << "Invalid/disabled command";
1067 // The order of commands in this switch statement must match the function
1068 // declaration order in browser.h!
1069 switch (id) {
1070 // Navigation commands
1071 case IDC_BACK: GoBack(); break;
1072 case IDC_FORWARD: GoForward(); break;
1073 case IDC_RELOAD: Reload(); break;
1074 case IDC_HOME: Home(); break;
1075 case IDC_OPEN_CURRENT_URL: OpenCurrentURL(); break;
1076 case IDC_GO: Go(); break;
1077 case IDC_STOP: Stop(); break;
1079 // Window management commands
1080 case IDC_NEW_WINDOW: NewWindow(); break;
1081 case IDC_NEW_INCOGNITO_WINDOW: NewIncognitoWindow(); break;
1082 case IDC_NEW_WINDOW_PROFILE_0:
1083 case IDC_NEW_WINDOW_PROFILE_1:
1084 case IDC_NEW_WINDOW_PROFILE_2:
1085 case IDC_NEW_WINDOW_PROFILE_3:
1086 case IDC_NEW_WINDOW_PROFILE_4:
1087 case IDC_NEW_WINDOW_PROFILE_5:
1088 case IDC_NEW_WINDOW_PROFILE_6:
1089 case IDC_NEW_WINDOW_PROFILE_7:
1090 case IDC_NEW_WINDOW_PROFILE_8:
1091 NewProfileWindowByIndex(id - IDC_NEW_WINDOW_PROFILE_0); break;
1092 #if defined(OS_WIN)
1093 case IDC_CLOSE_WINDOW: CloseWindow(); break;
1094 #endif
1095 case IDC_NEW_TAB: NewTab(); break;
1096 case IDC_CLOSE_TAB: CloseTab(); break;
1097 case IDC_SELECT_NEXT_TAB: SelectNextTab(); break;
1098 case IDC_SELECT_PREVIOUS_TAB: SelectPreviousTab(); break;
1099 case IDC_SELECT_TAB_0:
1100 case IDC_SELECT_TAB_1:
1101 case IDC_SELECT_TAB_2:
1102 case IDC_SELECT_TAB_3:
1103 case IDC_SELECT_TAB_4:
1104 case IDC_SELECT_TAB_5:
1105 case IDC_SELECT_TAB_6:
1106 case IDC_SELECT_TAB_7: SelectNumberedTab(id - IDC_SELECT_TAB_0);
1107 break;
1108 case IDC_SELECT_LAST_TAB: SelectLastTab(); break;
1109 case IDC_DUPLICATE_TAB: DuplicateTab(); break;
1110 case IDC_RESTORE_TAB: RestoreTab(); break;
1111 case IDC_SHOW_AS_TAB: ConvertPopupToTabbedBrowser(); break;
1112 case IDC_FULLSCREEN: ToggleFullscreenMode(); break;
1113 case IDC_EXIT: Exit(); break;
1115 // Page-related commands
1116 case IDC_STAR: BookmarkCurrentPage(); break;
1117 case IDC_VIEW_SOURCE: ViewSource(); break;
1118 #if defined(OS_WIN)
1119 case IDC_CLOSE_POPUPS: ClosePopups(); break;
1120 case IDC_PRINT: Print(); break;
1121 case IDC_SAVE_PAGE: SavePage(); break;
1122 case IDC_ENCODING_AUTO_DETECT: ToggleEncodingAutoDetect(); break;
1123 case IDC_ENCODING_UTF8:
1124 case IDC_ENCODING_UTF16LE:
1125 case IDC_ENCODING_ISO88591:
1126 case IDC_ENCODING_WINDOWS1252:
1127 case IDC_ENCODING_GBK:
1128 case IDC_ENCODING_GB18030:
1129 case IDC_ENCODING_BIG5HKSCS:
1130 case IDC_ENCODING_BIG5:
1131 case IDC_ENCODING_KOREAN:
1132 case IDC_ENCODING_SHIFTJIS:
1133 case IDC_ENCODING_ISO2022JP:
1134 case IDC_ENCODING_EUCJP:
1135 case IDC_ENCODING_THAI:
1136 case IDC_ENCODING_ISO885915:
1137 case IDC_ENCODING_MACINTOSH:
1138 case IDC_ENCODING_ISO88592:
1139 case IDC_ENCODING_WINDOWS1250:
1140 case IDC_ENCODING_ISO88595:
1141 case IDC_ENCODING_WINDOWS1251:
1142 case IDC_ENCODING_KOI8R:
1143 case IDC_ENCODING_KOI8U:
1144 case IDC_ENCODING_ISO88597:
1145 case IDC_ENCODING_WINDOWS1253:
1146 case IDC_ENCODING_ISO88594:
1147 case IDC_ENCODING_ISO885913:
1148 case IDC_ENCODING_WINDOWS1257:
1149 case IDC_ENCODING_ISO88593:
1150 case IDC_ENCODING_ISO885910:
1151 case IDC_ENCODING_ISO885914:
1152 case IDC_ENCODING_ISO885916:
1153 case IDC_ENCODING_WINDOWS1254:
1154 case IDC_ENCODING_ISO88596:
1155 case IDC_ENCODING_WINDOWS1256:
1156 case IDC_ENCODING_ISO88598:
1157 case IDC_ENCODING_WINDOWS1255:
1158 case IDC_ENCODING_WINDOWS1258: OverrideEncoding(id); break;
1160 // Clipboard commands
1161 case IDC_CUT: Cut(); break;
1162 case IDC_COPY: Copy(); break;
1163 case IDC_COPY_URL: CopyCurrentPageURL(); break;
1164 case IDC_PASTE: Paste(); break;
1166 // Find-in-page
1167 case IDC_FIND: Find(); break;
1168 case IDC_FIND_NEXT: FindNext(); break;
1169 case IDC_FIND_PREVIOUS: FindPrevious(); break;
1171 // Zoom
1172 case IDC_ZOOM_PLUS: ZoomIn(); break;
1173 case IDC_ZOOM_NORMAL: ZoomReset(); break;
1174 case IDC_ZOOM_MINUS: ZoomOut(); break;
1176 // Focus various bits of UI
1177 case IDC_FOCUS_TOOLBAR: FocusToolbar(); break;
1178 case IDC_FOCUS_LOCATION: FocusLocationBar(); break;
1179 case IDC_FOCUS_SEARCH: FocusSearch(); break;
1181 // Show various bits of UI
1182 case IDC_OPEN_FILE: OpenFile(); break;
1183 case IDC_CREATE_SHORTCUTS: OpenCreateShortcutsDialog(); break;
1184 case IDC_DEBUGGER: OpenDebuggerWindow(); break;
1185 case IDC_JS_CONSOLE: OpenJavaScriptConsole(); break;
1186 case IDC_TASK_MANAGER: OpenTaskManager(); break;
1187 case IDC_SELECT_PROFILE: OpenSelectProfileDialog(); break;
1188 case IDC_NEW_PROFILE: OpenNewProfileDialog(); break;
1189 case IDC_REPORT_BUG: OpenBugReportDialog(); break;
1190 case IDC_SHOW_BOOKMARK_BAR: ToggleBookmarkBar(); break;
1191 case IDC_SHOW_HISTORY: ShowHistoryTab(); break;
1192 case IDC_SHOW_BOOKMARK_MANAGER: OpenBookmarkManager(); break;
1193 case IDC_SHOW_DOWNLOADS: ShowDownloadsTab(); break;
1194 #ifdef CHROME_PERSONALIZATION
1195 case IDC_P13N_INFO:
1196 Personalization::HandleMenuItemClick(profile()); break;
1197 #endif
1198 case IDC_CLEAR_BROWSING_DATA: OpenClearBrowsingDataDialog(); break;
1199 case IDC_IMPORT_SETTINGS: OpenImportSettingsDialog(); break;
1200 case IDC_OPTIONS: OpenOptionsDialog(); break;
1201 case IDC_EDIT_SEARCH_ENGINES: OpenKeywordEditor(); break;
1202 case IDC_VIEW_PASSWORDS: OpenPasswordManager(); break;
1203 case IDC_ABOUT: OpenAboutChromeDialog(); break;
1204 case IDC_HELP_PAGE: OpenHelpTab(); break;
1205 #endif
1207 default:
1208 LOG(WARNING) << "Received Unimplemented Command: " << id;
1209 break;
1213 ///////////////////////////////////////////////////////////////////////////////
1214 // Browser, TabStripModelDelegate implementation:
1216 GURL Browser::GetBlankTabURL() const {
1217 return NewTabUIURL();
1220 void Browser::CreateNewStripWithContents(TabContents* detached_contents,
1221 const gfx::Rect& window_bounds,
1222 const DockInfo& dock_info) {
1223 DCHECK(type_ == TYPE_NORMAL);
1225 gfx::Rect new_window_bounds = window_bounds;
1226 bool maximize = false;
1227 if (dock_info.GetNewWindowBounds(&new_window_bounds, &maximize))
1228 dock_info.AdjustOtherWindowBounds();
1230 // Create an empty new browser window the same size as the old one.
1231 Browser* browser = new Browser(TYPE_NORMAL, profile_);
1232 browser->set_override_bounds(new_window_bounds);
1233 browser->set_override_maximized(maximize);
1234 browser->CreateBrowserWindow();
1235 browser->tabstrip_model()->AppendTabContents(detached_contents, true);
1236 // Make sure the loading state is updated correctly, otherwise the throbber
1237 // won't start if the page is loading.
1238 browser->LoadingStateChanged(detached_contents);
1239 browser->window()->Show();
1242 int Browser::GetDragActions() const {
1243 int result = 0;
1244 if (BrowserList::GetBrowserCountForType(profile_, TYPE_NORMAL) > 1 ||
1245 tab_count() > 1)
1246 result |= TAB_TEAROFF_ACTION;
1247 if (tab_count() > 1)
1248 result |= TAB_MOVE_ACTION;
1249 return result;
1252 TabContents* Browser::CreateTabContentsForURL(
1253 const GURL& url, const GURL& referrer, Profile* profile,
1254 PageTransition::Type transition, bool defer_load,
1255 SiteInstance* instance) const {
1256 // Create an appropriate tab contents.
1257 GURL real_url = url;
1258 TabContentsType type = TabContents::TypeForURL(&real_url);
1259 DCHECK(type != TAB_CONTENTS_UNKNOWN_TYPE);
1261 TabContents* contents = TabContents::CreateWithType(type, profile, instance);
1262 contents->SetupController(profile);
1264 if (!defer_load) {
1265 // Load the initial URL before adding the new tab contents to the tab strip
1266 // so that the tab contents has navigation state.
1267 contents->controller()->LoadURL(url, referrer, transition);
1270 return contents;
1273 bool Browser::CanDuplicateContentsAt(int index) {
1274 TabContents* contents = GetTabContentsAt(index);
1275 DCHECK(contents);
1277 NavigationController* nc = contents->controller();
1278 return nc ? (nc->active_contents() && nc->GetLastCommittedEntry()) : false;
1281 void Browser::DuplicateContentsAt(int index) {
1282 TabContents* contents = GetTabContentsAt(index);
1283 TabContents* new_contents = NULL;
1284 DCHECK(contents);
1286 if (type_ == TYPE_NORMAL) {
1287 // If this is a tabbed browser, just create a duplicate tab inside the same
1288 // window next to the tab being duplicated.
1289 new_contents = contents->controller()->Clone()->active_contents();
1290 // If you duplicate a tab that is not selected, we need to make sure to
1291 // select the tab being duplicated so that DetermineInsertionIndex returns
1292 // the right index (if tab 5 is selected and we right-click tab 1 we want
1293 // the new tab to appear in index position 2, not 6).
1294 if (tabstrip_model_.selected_index() != index)
1295 tabstrip_model_.SelectTabContentsAt(index, true);
1296 tabstrip_model_.AddTabContents(new_contents, index + 1,
1297 PageTransition::LINK, true);
1298 } else {
1299 Browser* browser = NULL;
1300 if (type_ == TYPE_APP) {
1301 browser = Browser::CreateForApp(app_name_, profile_);
1302 } else if (type_ == TYPE_POPUP) {
1303 browser = Browser::CreateForPopup(profile_);
1306 // Preserve the size of the original window. The new window has already
1307 // been given an offset by the OS, so we shouldn't copy the old bounds.
1308 BrowserWindow* new_window = browser->window();
1309 new_window->SetBounds(gfx::Rect(new_window->GetNormalBounds().origin(),
1310 window()->GetNormalBounds().size()));
1312 // We need to show the browser now. Otherwise ContainerWin assumes the
1313 // TabContents is invisible and won't size it.
1314 browser->window()->Show();
1316 // The page transition below is only for the purpose of inserting the tab.
1317 new_contents = browser->AddTabWithNavigationController(
1318 contents->controller()->Clone(),
1319 PageTransition::LINK);
1322 if (profile_->HasSessionService()) {
1323 SessionService* session_service = profile_->GetSessionService();
1324 if (session_service)
1325 session_service->TabRestored(new_contents->controller());
1329 void Browser::CloseFrameAfterDragSession() {
1330 #if defined(OS_WIN)
1331 // This is scheduled to run after we return to the message loop because
1332 // otherwise the frame will think the drag session is still active and ignore
1333 // the request.
1334 // TODO(port): figure out what is required here in a cross-platform world
1335 MessageLoop::current()->PostTask(FROM_HERE,
1336 method_factory_.NewRunnableMethod(&Browser::CloseFrame));
1337 #endif
1340 void Browser::CreateHistoricalTab(TabContents* contents) {
1341 // We don't create historical tabs for incognito windows or windows without
1342 // profiles.
1343 if (!profile() || profile()->IsOffTheRecord() ||
1344 !profile()->GetTabRestoreService()) {
1345 return;
1348 // We only create historical tab entries for normal tabbed browser windows.
1349 if (type() == TYPE_NORMAL) {
1350 profile()->GetTabRestoreService()->CreateHistoricalTab(
1351 contents->controller());
1355 bool Browser::RunUnloadListenerBeforeClosing(TabContents* contents) {
1356 WebContents* web_contents = contents->AsWebContents();
1357 if (web_contents) {
1358 // If the WebContents is not connected yet, then there's no unload
1359 // handler we can fire even if the WebContents has an unload listener.
1360 // One case where we hit this is in a tab that has an infinite loop
1361 // before load.
1362 if (TabHasUnloadListener(contents)) {
1363 // If the page has unload listeners, then we tell the renderer to fire
1364 // them. Once they have fired, we'll get a message back saying whether
1365 // to proceed closing the page or not, which sends us back to this method
1366 // with the HasUnloadListener bit cleared.
1367 web_contents->render_view_host()->FirePageBeforeUnload();
1368 return true;
1371 return false;
1375 ///////////////////////////////////////////////////////////////////////////////
1376 // Browser, TabStripModelObserver implementation:
1378 void Browser::TabInsertedAt(TabContents* contents,
1379 int index,
1380 bool foreground) {
1381 contents->set_delegate(this);
1382 contents->controller()->SetWindowID(session_id());
1384 SyncHistoryWithTabs(tabstrip_model_.GetIndexOfTabContents(contents));
1386 // Make sure the loading state is updated correctly, otherwise the throbber
1387 // won't start if the page is loading.
1388 LoadingStateChanged(contents);
1390 // If the tab crashes in the beforeunload or unload handler, it won't be
1391 // able to ack. But we know we can close it.
1392 NotificationService::current()->AddObserver(
1393 this,
1394 NotificationType::WEB_CONTENTS_DISCONNECTED,
1395 Source<TabContents>(contents));
1398 void Browser::TabClosingAt(TabContents* contents, int index) {
1399 NavigationController* controller = contents->controller();
1400 DCHECK(controller);
1401 NotificationService::current()->Notify(
1402 NotificationType::TAB_CLOSING,
1403 Source<NavigationController>(controller),
1404 NotificationService::NoDetails());
1406 // Sever the TabContents' connection back to us.
1407 contents->set_delegate(NULL);
1410 void Browser::TabDetachedAt(TabContents* contents, int index) {
1411 contents->set_delegate(NULL);
1412 if (!tabstrip_model_.closing_all())
1413 SyncHistoryWithTabs(0);
1415 RemoveScheduledUpdatesFor(contents);
1417 NotificationService::current()->RemoveObserver(
1418 this,
1419 NotificationType::WEB_CONTENTS_DISCONNECTED,
1420 Source<TabContents>(contents));
1423 void Browser::TabSelectedAt(TabContents* old_contents,
1424 TabContents* new_contents,
1425 int index,
1426 bool user_gesture) {
1427 DCHECK(old_contents != new_contents);
1429 // If we have any update pending, do it now.
1430 if (!chrome_updater_factory_.empty() && old_contents)
1431 ProcessPendingUIUpdates();
1433 if (old_contents) {
1434 // Save what the user's currently typing, so it can be restored when we
1435 // switch back to this tab.
1436 window_->GetLocationBar()->SaveStateToContents(old_contents);
1439 // Propagate the profile to the location bar.
1440 UpdateToolbar(true);
1442 // Update stop/go state.
1443 UpdateStopGoState(new_contents->is_loading());
1445 // Update commands to reflect current state.
1446 UpdateCommandsForTabState();
1448 // Reset the status bubble.
1449 StatusBubble* status_bubble = GetStatusBubble();
1450 if (status_bubble) {
1451 status_bubble->Hide();
1453 // Show the loading state (if any).
1454 status_bubble->SetStatus(GetSelectedTabContents()->GetStatusText());
1457 // Update sessions. Don't force creation of sessions. If sessions doesn't
1458 // exist, the change will be picked up by sessions when created.
1459 if (profile_->HasSessionService()) {
1460 SessionService* session_service = profile_->GetSessionService();
1461 if (session_service && !tabstrip_model_.closing_all()) {
1462 session_service->SetSelectedTabInWindow(
1463 session_id(), tabstrip_model_.selected_index());
1468 void Browser::TabMoved(TabContents* contents,
1469 int from_index,
1470 int to_index) {
1471 DCHECK(from_index >= 0 && to_index >= 0);
1472 // Notify the history service.
1473 SyncHistoryWithTabs(std::min(from_index, to_index));
1476 void Browser::TabStripEmpty() {
1477 // Close the frame after we return to the message loop (not immediately,
1478 // otherwise it will destroy this object before the stack has a chance to
1479 // cleanly unwind.)
1480 // Note: This will be called several times if TabStripEmpty is called several
1481 // times. This is because it does not close the window if tabs are
1482 // still present.
1483 // NOTE: If you change to be immediate (no invokeLater) then you'll need to
1484 // update BrowserList::CloseAllBrowsers.
1485 MessageLoop::current()->PostTask(FROM_HERE,
1486 method_factory_.NewRunnableMethod(&Browser::CloseFrame));
1489 ///////////////////////////////////////////////////////////////////////////////
1490 // Browser, TabContentsDelegate implementation:
1492 void Browser::OpenURLFromTab(TabContents* source,
1493 const GURL& url, const GURL& referrer,
1494 WindowOpenDisposition disposition,
1495 PageTransition::Type transition) {
1496 // TODO(beng): Move all this code into a separate helper that has unit tests.
1498 // No code for these yet
1499 DCHECK((disposition != NEW_POPUP) && (disposition != SAVE_TO_DISK));
1501 TabContents* current_tab = source ? source : GetSelectedTabContents();
1502 bool source_tab_was_frontmost = (current_tab == GetSelectedTabContents());
1503 TabContents* new_contents = NULL;
1505 // If the URL is part of the same web site, then load it in the same
1506 // SiteInstance (and thus the same process). This is an optimization to
1507 // reduce process overhead; it is not necessary for compatibility. (That is,
1508 // the new tab will not have script connections to the previous tab, so it
1509 // does not need to be part of the same SiteInstance or BrowsingInstance.)
1510 // Default to loading in a new SiteInstance and BrowsingInstance.
1511 // TODO(creis): should this apply to applications?
1512 SiteInstance* instance = NULL;
1513 // Don't use this logic when "--process-per-tab" is specified.
1514 if (!CommandLine::ForCurrentProcess()->HasSwitch(switches::kProcessPerTab)) {
1515 if (current_tab) {
1516 const WebContents* const web_contents = current_tab->AsWebContents();
1517 if (web_contents) {
1518 const GURL& current_url = web_contents->GetURL();
1519 if (SiteInstance::IsSameWebSite(current_url, url))
1520 instance = web_contents->GetSiteInstance();
1525 // If this is an application we can only have one tab so a new tab always
1526 // goes into a tabbed browser window.
1527 if (disposition != NEW_WINDOW && type_ == TYPE_APP) {
1528 // If the disposition is OFF_THE_RECORD we don't want to create a new
1529 // browser that will itself create another OTR browser. This will result in
1530 // a browser leak (and crash below because no tab is created or selected).
1531 if (disposition == OFF_THE_RECORD) {
1532 OpenURLOffTheRecord(profile_, url);
1533 return;
1536 Browser* b = GetOrCreateTabbedBrowser();
1537 DCHECK(b);
1539 // If we have just created a new browser window, make sure we select the
1540 // tab.
1541 if (b->tab_count() == 0 && disposition == NEW_BACKGROUND_TAB)
1542 disposition = NEW_FOREGROUND_TAB;
1544 b->OpenURL(url, referrer, disposition, transition);
1545 b->window()->Show();
1546 return;
1549 if (profile_->IsOffTheRecord() && disposition == OFF_THE_RECORD)
1550 disposition = NEW_FOREGROUND_TAB;
1552 if (disposition == NEW_WINDOW) {
1553 Browser* browser = Browser::Create(profile_);
1554 new_contents = browser->AddTabWithURL(url, referrer, transition, true,
1555 instance);
1556 browser->window()->Show();
1557 } else if ((disposition == CURRENT_TAB) && current_tab) {
1558 tabstrip_model_.TabNavigating(current_tab, transition);
1560 // TODO(beng): remove all this once there are no TabContents types.
1561 // It seems like under some circumstances current_tab can be dust after the
1562 // call to LoadURL (perhaps related to TabContents type switching), so we
1563 // save the NavigationController here.
1564 NavigationController* controller = current_tab->controller();
1565 controller->LoadURL(url, referrer, transition);
1566 // If the TabContents type has been swapped, we need to point to the current
1567 // active type otherwise there will be weirdness.
1568 new_contents = controller->active_contents();
1569 if (GetStatusBubble())
1570 GetStatusBubble()->Hide();
1572 // Synchronously update the location bar. This allows us to immediately
1573 // have the URL bar update when the user types something, rather than
1574 // going through the normal system of ScheduleUIUpdate which has a delay.
1575 UpdateToolbar(false);
1576 } else if (disposition == OFF_THE_RECORD) {
1577 OpenURLOffTheRecord(profile_, url);
1578 return;
1579 } else if (disposition != SUPPRESS_OPEN) {
1580 new_contents = AddTabWithURL(url, referrer, transition,
1581 disposition != NEW_BACKGROUND_TAB, instance);
1584 if (disposition != NEW_BACKGROUND_TAB && source_tab_was_frontmost) {
1585 // Give the focus to the newly navigated tab, if the source tab was
1586 // front-most.
1587 new_contents->Focus();
1591 void Browser::NavigationStateChanged(const TabContents* source,
1592 unsigned changed_flags) {
1593 // Only update the UI when something visible has changed.
1594 if (changed_flags)
1595 ScheduleUIUpdate(source, changed_flags);
1597 // We don't schedule updates to commands since they will only change once per
1598 // navigation, so we don't have to worry about flickering.
1599 if (changed_flags & TabContents::INVALIDATE_URL)
1600 UpdateCommandsForTabState();
1603 void Browser::ReplaceContents(TabContents* source, TabContents* new_contents) {
1604 source->set_delegate(NULL);
1605 new_contents->set_delegate(this);
1607 RemoveScheduledUpdatesFor(source);
1609 int index = tabstrip_model_.GetIndexOfTabContents(source);
1610 tabstrip_model_.ReplaceTabContentsAt(index, new_contents);
1612 if (is_attempting_to_close_browser_) {
1613 // Need to do this asynchronously as it will close the tab, which is
1614 // currently on the call stack above us.
1615 MessageLoop::current()->PostTask(FROM_HERE,
1616 method_factory_.NewRunnableMethod(&Browser::ClearUnloadState,
1617 Source<TabContents>(source).ptr()));
1619 // Need to remove ourselves as an observer for disconnection on the replaced
1620 // TabContents, since we only care to fire onbeforeunload handlers on active
1621 // Tabs. Make sure an observer is added for the replacement TabContents.
1622 NotificationService::current()->RemoveObserver(
1623 this,
1624 NotificationType::WEB_CONTENTS_DISCONNECTED,
1625 Source<TabContents>(source));
1626 NotificationService::current()->AddObserver(
1627 this,
1628 NotificationType::WEB_CONTENTS_DISCONNECTED,
1629 Source<TabContents>(new_contents));
1632 void Browser::AddNewContents(TabContents* source,
1633 TabContents* new_contents,
1634 WindowOpenDisposition disposition,
1635 const gfx::Rect& initial_pos,
1636 bool user_gesture) {
1637 DCHECK(disposition != SAVE_TO_DISK); // No code for this yet
1639 // If this is an application we can only have one tab so we need to process
1640 // this in tabbed browser window.
1641 if (tabstrip_model_.count() > 0 &&
1642 disposition != NEW_WINDOW && disposition != NEW_POPUP &&
1643 type_ != TYPE_NORMAL) {
1644 Browser* b = GetOrCreateTabbedBrowser();
1645 DCHECK(b);
1646 PageTransition::Type transition = PageTransition::LINK;
1647 // If we were called from an "installed webapp" we want to emulate the code
1648 // that is run from browser_init.cc for links from external applications.
1649 // This means we need to open the tab with the START PAGE transition.
1650 // AddNewContents doesn't support this but the TabStripModel's
1651 // AddTabContents method does.
1652 if (type_ == TYPE_APP)
1653 transition = PageTransition::START_PAGE;
1654 b->tabstrip_model()->AddTabContents(new_contents, -1, transition, true);
1655 b->window()->Show();
1656 return;
1659 if (disposition == NEW_POPUP) {
1660 BuildPopupWindow(source, new_contents, initial_pos);
1661 } else if (disposition == NEW_WINDOW) {
1662 Browser* browser = Browser::Create(profile_);
1663 browser->AddNewContents(source, new_contents, NEW_FOREGROUND_TAB,
1664 initial_pos, user_gesture);
1665 browser->window()->Show();
1666 } else if (disposition == CURRENT_TAB) {
1667 ReplaceContents(source, new_contents);
1668 } else if (disposition != SUPPRESS_OPEN) {
1669 tabstrip_model_.AddTabContents(new_contents, -1, PageTransition::LINK,
1670 disposition == NEW_FOREGROUND_TAB);
1674 void Browser::ActivateContents(TabContents* contents) {
1675 tabstrip_model_.SelectTabContentsAt(
1676 tabstrip_model_.GetIndexOfTabContents(contents), false);
1677 window_->Activate();
1680 void Browser::LoadingStateChanged(TabContents* source) {
1681 window_->UpdateLoadingAnimations(tabstrip_model_.TabsAreLoading());
1682 window_->UpdateTitleBar();
1684 if (source == GetSelectedTabContents()) {
1685 UpdateStopGoState(source->is_loading());
1686 if (GetStatusBubble())
1687 GetStatusBubble()->SetStatus(GetSelectedTabContents()->GetStatusText());
1691 void Browser::CloseContents(TabContents* source) {
1692 if (is_attempting_to_close_browser_) {
1693 // If we're trying to close the browser, just clear the state related to
1694 // waiting for unload to fire. Don't actually try to close the tab as it
1695 // will go down the slow shutdown path instead of the fast path of killing
1696 // all the renderer processes.
1697 ClearUnloadState(source);
1698 return;
1701 int index = tabstrip_model_.GetIndexOfTabContents(source);
1702 if (index == TabStripModel::kNoTab) {
1703 NOTREACHED() << "CloseContents called for tab not in our strip";
1704 return;
1706 tabstrip_model_.CloseTabContentsAt(index);
1709 void Browser::MoveContents(TabContents* source, const gfx::Rect& pos) {
1710 if (type() != TYPE_POPUP) {
1711 NOTREACHED() << "moving invalid browser type";
1712 return;
1714 window_->SetBounds(pos);
1717 bool Browser::IsPopup(TabContents* source) {
1718 // A non-tabbed BROWSER is an unconstrained popup.
1719 return (type() == TYPE_POPUP);
1722 void Browser::ToolbarSizeChanged(TabContents* source, bool is_animating) {
1723 if (source == GetSelectedTabContents() || source == NULL) {
1724 // This will refresh the shelf if needed.
1725 window_->SelectedTabToolbarSizeChanged(is_animating);
1729 void Browser::URLStarredChanged(TabContents* source, bool starred) {
1730 if (source == GetSelectedTabContents())
1731 window_->SetStarredState(starred);
1734 #if defined(OS_WIN)
1735 // TODO(port): Refactor this to win-specific delegate?
1736 void Browser::ContentsMouseEvent(TabContents* source, UINT message) {
1737 if (!GetStatusBubble())
1738 return;
1740 if (source == GetSelectedTabContents()) {
1741 if (message == WM_MOUSEMOVE) {
1742 GetStatusBubble()->MouseMoved();
1743 } else if (message == WM_MOUSELEAVE) {
1744 GetStatusBubble()->SetURL(GURL(), std::wstring());
1748 #endif
1750 void Browser::UpdateTargetURL(TabContents* source, const GURL& url) {
1751 if (!GetStatusBubble())
1752 return;
1754 if (source == GetSelectedTabContents()) {
1755 PrefService* prefs = profile_->GetPrefs();
1756 GetStatusBubble()->SetURL(url, prefs->GetString(prefs::kAcceptLanguages));
1760 void Browser::ContentsZoomChange(bool zoom_in) {
1761 ExecuteCommand(zoom_in ? IDC_ZOOM_PLUS : IDC_ZOOM_MINUS);
1764 bool Browser::IsApplication() const {
1765 return type_ == TYPE_APP;
1768 void Browser::ConvertContentsToApplication(TabContents* contents) {
1769 int index = tabstrip_model_.GetIndexOfTabContents(contents);
1770 if (index < 0)
1771 return;
1773 const GURL& url = contents->controller()->GetActiveEntry()->url();
1774 std::wstring app_name = ComputeApplicationNameFromURL(url);
1775 RegisterAppPrefs(app_name);
1777 tabstrip_model_.DetachTabContentsAt(index);
1778 Browser* browser = Browser::CreateForApp(app_name, profile_);
1779 browser->tabstrip_model()->AppendTabContents(contents, true);
1780 browser->window()->Show();
1783 void Browser::ContentsStateChanged(TabContents* source) {
1784 int index = tabstrip_model_.GetIndexOfTabContents(source);
1785 if (index != TabStripModel::kNoTab)
1786 tabstrip_model_.UpdateTabContentsStateAt(index);
1789 bool Browser::ShouldDisplayURLField() {
1790 return !IsApplication();
1793 void Browser::BeforeUnloadFired(TabContents* tab,
1794 bool proceed,
1795 bool* proceed_to_fire_unload) {
1796 if (!is_attempting_to_close_browser_) {
1797 *proceed_to_fire_unload = proceed;
1798 return;
1801 if (!proceed) {
1802 CancelWindowClose();
1803 *proceed_to_fire_unload = false;
1804 return;
1807 if (RemoveFromSet(&tabs_needing_before_unload_fired_, tab)) {
1808 // Now that beforeunload has fired, put the tab on the queue to fire
1809 // unload.
1810 tabs_needing_unload_fired_.insert(tab);
1811 ProcessPendingTabs();
1812 // We want to handle firing the unload event ourselves since we want to
1813 // fire all the beforeunload events before attempting to fire the unload
1814 // events should the user cancel closing the browser.
1815 *proceed_to_fire_unload = false;
1816 return;
1819 *proceed_to_fire_unload = true;
1822 gfx::Rect Browser::GetRootWindowResizerRect() const {
1823 return window_->GetRootWindowResizerRect();
1826 void Browser::ShowHtmlDialog(HtmlDialogContentsDelegate* delegate,
1827 void* parent_window) {
1828 window_->ShowHTMLDialog(delegate, parent_window);
1831 void Browser::SetFocusToLocationBar() {
1832 // Two differences between this and FocusLocationBar():
1833 // (1) This doesn't get recorded in user metrics, since it's called
1834 // internally.
1835 // (2) This checks whether the location bar can be focused, and if not, clears
1836 // the focus. FocusLocationBar() is only reached when the location bar is
1837 // focusable, but this may be reached at other times, e.g. while in
1838 // fullscreen mode, where we need to leave focus in a consistent state.
1839 window_->SetFocusToLocationBar();
1843 ///////////////////////////////////////////////////////////////////////////////
1844 // Browser, SelectFileDialog::Listener implementation:
1846 void Browser::FileSelected(const std::wstring& path, void* params) {
1847 GURL file_url = net::FilePathToFileURL(path);
1848 if (!file_url.is_empty())
1849 OpenURL(file_url, GURL(), CURRENT_TAB, PageTransition::TYPED);
1853 ///////////////////////////////////////////////////////////////////////////////
1854 // Browser, NotificationObserver implementation:
1856 void Browser::Observe(NotificationType type,
1857 const NotificationSource& source,
1858 const NotificationDetails& details) {
1859 switch (type.value) {
1860 case NotificationType::WEB_CONTENTS_DISCONNECTED:
1861 if (is_attempting_to_close_browser_) {
1862 // Need to do this asynchronously as it will close the tab, which is
1863 // currently on the call stack above us.
1864 MessageLoop::current()->PostTask(FROM_HERE,
1865 method_factory_.NewRunnableMethod(&Browser::ClearUnloadState,
1866 Source<TabContents>(source).ptr()));
1868 break;
1870 case NotificationType::SSL_STATE_CHANGED:
1871 // When the current tab's SSL state changes, we need to update the URL
1872 // bar to reflect the new state. Note that it's possible for the selected
1873 // tab contents to be NULL. This is because we listen for all sources
1874 // (NavigationControllers) for convenience, so the notification could
1875 // actually be for a different window while we're doing asynchronous
1876 // closing of this one.
1877 if (GetSelectedTabContents() &&
1878 GetSelectedTabContents()->controller() ==
1879 Source<NavigationController>(source).ptr())
1880 UpdateToolbar(false);
1881 break;
1883 default:
1884 NOTREACHED() << "Got a notification we didn't register for.";
1889 ///////////////////////////////////////////////////////////////////////////////
1890 // Browser, Command and state updating (private):
1892 void Browser::InitCommandState() {
1893 // All browser commands whose state isn't set automagically some other way
1894 // (like Back & Forward with initial page load) must have their state
1895 // initialized here, otherwise they will be forever disabled.
1897 // Navigation commands
1898 command_updater_.UpdateCommandEnabled(IDC_RELOAD, true);
1900 // Window management commands
1901 command_updater_.UpdateCommandEnabled(IDC_NEW_WINDOW, true);
1902 command_updater_.UpdateCommandEnabled(IDC_NEW_INCOGNITO_WINDOW, true);
1903 // TODO(pkasting): Perhaps the code that populates this submenu should do
1904 // this?
1905 command_updater_.UpdateCommandEnabled(IDC_NEW_WINDOW_PROFILE_0, true);
1906 command_updater_.UpdateCommandEnabled(IDC_NEW_WINDOW_PROFILE_1, true);
1907 command_updater_.UpdateCommandEnabled(IDC_NEW_WINDOW_PROFILE_2, true);
1908 command_updater_.UpdateCommandEnabled(IDC_NEW_WINDOW_PROFILE_3, true);
1909 command_updater_.UpdateCommandEnabled(IDC_NEW_WINDOW_PROFILE_4, true);
1910 command_updater_.UpdateCommandEnabled(IDC_NEW_WINDOW_PROFILE_5, true);
1911 command_updater_.UpdateCommandEnabled(IDC_NEW_WINDOW_PROFILE_6, true);
1912 command_updater_.UpdateCommandEnabled(IDC_NEW_WINDOW_PROFILE_7, true);
1913 command_updater_.UpdateCommandEnabled(IDC_NEW_WINDOW_PROFILE_8, true);
1914 command_updater_.UpdateCommandEnabled(IDC_CLOSE_WINDOW, true);
1915 command_updater_.UpdateCommandEnabled(IDC_NEW_TAB, true);
1916 command_updater_.UpdateCommandEnabled(IDC_CLOSE_TAB, true);
1917 command_updater_.UpdateCommandEnabled(IDC_DUPLICATE_TAB, true);
1918 command_updater_.UpdateCommandEnabled(IDC_FULLSCREEN, true);
1919 command_updater_.UpdateCommandEnabled(IDC_EXIT, true);
1921 // Page-related commands
1922 command_updater_.UpdateCommandEnabled(IDC_CLOSE_POPUPS, true);
1923 command_updater_.UpdateCommandEnabled(IDC_ENCODING_AUTO_DETECT, true);
1924 command_updater_.UpdateCommandEnabled(IDC_ENCODING_UTF8, true);
1925 command_updater_.UpdateCommandEnabled(IDC_ENCODING_UTF16LE, true);
1926 command_updater_.UpdateCommandEnabled(IDC_ENCODING_ISO88591, true);
1927 command_updater_.UpdateCommandEnabled(IDC_ENCODING_WINDOWS1252, true);
1928 command_updater_.UpdateCommandEnabled(IDC_ENCODING_GBK, true);
1929 command_updater_.UpdateCommandEnabled(IDC_ENCODING_GB18030, true);
1930 command_updater_.UpdateCommandEnabled(IDC_ENCODING_BIG5HKSCS, true);
1931 command_updater_.UpdateCommandEnabled(IDC_ENCODING_BIG5, true);
1932 command_updater_.UpdateCommandEnabled(IDC_ENCODING_THAI, true);
1933 command_updater_.UpdateCommandEnabled(IDC_ENCODING_KOREAN, true);
1934 command_updater_.UpdateCommandEnabled(IDC_ENCODING_SHIFTJIS, true);
1935 command_updater_.UpdateCommandEnabled(IDC_ENCODING_ISO2022JP, true);
1936 command_updater_.UpdateCommandEnabled(IDC_ENCODING_EUCJP, true);
1937 command_updater_.UpdateCommandEnabled(IDC_ENCODING_ISO885915, true);
1938 command_updater_.UpdateCommandEnabled(IDC_ENCODING_MACINTOSH, true);
1939 command_updater_.UpdateCommandEnabled(IDC_ENCODING_ISO88592, true);
1940 command_updater_.UpdateCommandEnabled(IDC_ENCODING_WINDOWS1250, true);
1941 command_updater_.UpdateCommandEnabled(IDC_ENCODING_ISO88595, true);
1942 command_updater_.UpdateCommandEnabled(IDC_ENCODING_WINDOWS1251, true);
1943 command_updater_.UpdateCommandEnabled(IDC_ENCODING_KOI8R, true);
1944 command_updater_.UpdateCommandEnabled(IDC_ENCODING_KOI8U, true);
1945 command_updater_.UpdateCommandEnabled(IDC_ENCODING_ISO88597, true);
1946 command_updater_.UpdateCommandEnabled(IDC_ENCODING_WINDOWS1253, true);
1947 command_updater_.UpdateCommandEnabled(IDC_ENCODING_ISO88594, true);
1948 command_updater_.UpdateCommandEnabled(IDC_ENCODING_ISO885913, true);
1949 command_updater_.UpdateCommandEnabled(IDC_ENCODING_WINDOWS1257, true);
1950 command_updater_.UpdateCommandEnabled(IDC_ENCODING_ISO88593, true);
1951 command_updater_.UpdateCommandEnabled(IDC_ENCODING_ISO885910, true);
1952 command_updater_.UpdateCommandEnabled(IDC_ENCODING_ISO885914, true);
1953 command_updater_.UpdateCommandEnabled(IDC_ENCODING_ISO885916, true);
1954 command_updater_.UpdateCommandEnabled(IDC_ENCODING_WINDOWS1254, true);
1955 command_updater_.UpdateCommandEnabled(IDC_ENCODING_ISO88596, true);
1956 command_updater_.UpdateCommandEnabled(IDC_ENCODING_WINDOWS1256, true);
1957 command_updater_.UpdateCommandEnabled(IDC_ENCODING_ISO88598, true);
1958 command_updater_.UpdateCommandEnabled(IDC_ENCODING_WINDOWS1255, true);
1959 command_updater_.UpdateCommandEnabled(IDC_ENCODING_WINDOWS1258, true);
1961 // Clipboard commands
1962 command_updater_.UpdateCommandEnabled(IDC_CUT, true);
1963 command_updater_.UpdateCommandEnabled(IDC_COPY, true);
1964 command_updater_.UpdateCommandEnabled(IDC_COPY_URL, true);
1965 command_updater_.UpdateCommandEnabled(IDC_PASTE, true);
1967 // Show various bits of UI
1968 command_updater_.UpdateCommandEnabled(IDC_OPEN_FILE, true);
1969 command_updater_.UpdateCommandEnabled(IDC_CREATE_SHORTCUTS, false);
1970 command_updater_.UpdateCommandEnabled(IDC_TASK_MANAGER, true);
1971 command_updater_.UpdateCommandEnabled(IDC_SELECT_PROFILE, true);
1972 command_updater_.UpdateCommandEnabled(IDC_SHOW_HISTORY, true);
1973 command_updater_.UpdateCommandEnabled(IDC_SHOW_BOOKMARK_MANAGER, true);
1974 command_updater_.UpdateCommandEnabled(IDC_SHOW_DOWNLOADS, true);
1975 command_updater_.UpdateCommandEnabled(IDC_HELP_PAGE, true);
1977 // Initialize other commands based on the window type.
1979 bool normal_window = type() == TYPE_NORMAL;
1981 // Navigation commands
1982 command_updater_.UpdateCommandEnabled(IDC_HOME, normal_window);
1984 // Window management commands
1985 command_updater_.UpdateCommandEnabled(IDC_SELECT_NEXT_TAB, normal_window);
1986 command_updater_.UpdateCommandEnabled(IDC_SELECT_PREVIOUS_TAB,
1987 normal_window);
1988 command_updater_.UpdateCommandEnabled(IDC_SELECT_TAB_0, normal_window);
1989 command_updater_.UpdateCommandEnabled(IDC_SELECT_TAB_1, normal_window);
1990 command_updater_.UpdateCommandEnabled(IDC_SELECT_TAB_2, normal_window);
1991 command_updater_.UpdateCommandEnabled(IDC_SELECT_TAB_3, normal_window);
1992 command_updater_.UpdateCommandEnabled(IDC_SELECT_TAB_4, normal_window);
1993 command_updater_.UpdateCommandEnabled(IDC_SELECT_TAB_5, normal_window);
1994 command_updater_.UpdateCommandEnabled(IDC_SELECT_TAB_6, normal_window);
1995 command_updater_.UpdateCommandEnabled(IDC_SELECT_TAB_7, normal_window);
1996 command_updater_.UpdateCommandEnabled(IDC_SELECT_LAST_TAB, normal_window);
1997 command_updater_.UpdateCommandEnabled(IDC_RESTORE_TAB,
1998 normal_window && !profile_->IsOffTheRecord());
2001 // Initialize other commands whose state changes based on fullscreen mode.
2002 UpdateCommandsForFullscreenMode(false);
2005 void Browser::UpdateCommandsForTabState() {
2006 TabContents* current_tab = GetSelectedTabContents();
2007 if (!current_tab) // May be NULL during tab restore.
2008 return;
2010 // Navigation commands
2011 NavigationController* nc = current_tab->controller();
2012 command_updater_.UpdateCommandEnabled(IDC_BACK, nc->CanGoBack());
2013 command_updater_.UpdateCommandEnabled(IDC_FORWARD, nc->CanGoForward());
2015 // Window management commands
2016 command_updater_.UpdateCommandEnabled(IDC_DUPLICATE_TAB,
2017 CanDuplicateContentsAt(selected_index()));
2019 // Initialize commands available only for web content.
2021 WebContents* web_contents = current_tab->AsWebContents();
2022 bool is_web_contents = web_contents != NULL;
2024 // Page-related commands
2025 // Only allow bookmarking for web content in normal windows.
2026 command_updater_.UpdateCommandEnabled(IDC_STAR,
2027 is_web_contents && (type() == TYPE_NORMAL));
2028 window_->SetStarredState(is_web_contents && web_contents->is_starred());
2029 // View-source should not be enabled if already in view-source mode.
2030 command_updater_.UpdateCommandEnabled(IDC_VIEW_SOURCE,
2031 is_web_contents && (current_tab->type() != TAB_CONTENTS_VIEW_SOURCE) &&
2032 current_tab->controller()->GetActiveEntry());
2033 command_updater_.UpdateCommandEnabled(IDC_PRINT, is_web_contents);
2034 command_updater_.UpdateCommandEnabled(IDC_SAVE_PAGE,
2035 is_web_contents && SavePackage::IsSavableURL(current_tab->GetURL()));
2036 command_updater_.UpdateCommandEnabled(IDC_ENCODING_MENU,
2037 is_web_contents &&
2038 SavePackage::IsSavableContents(web_contents->contents_mime_type()) &&
2039 SavePackage::IsSavableURL(current_tab->GetURL()));
2041 // Find-in-page
2042 command_updater_.UpdateCommandEnabled(IDC_FIND, is_web_contents);
2043 command_updater_.UpdateCommandEnabled(IDC_FIND_NEXT, is_web_contents);
2044 command_updater_.UpdateCommandEnabled(IDC_FIND_PREVIOUS, is_web_contents);
2046 // Zoom
2047 command_updater_.UpdateCommandEnabled(IDC_ZOOM_MENU, is_web_contents);
2048 command_updater_.UpdateCommandEnabled(IDC_ZOOM_PLUS, is_web_contents);
2049 command_updater_.UpdateCommandEnabled(IDC_ZOOM_NORMAL, is_web_contents);
2050 command_updater_.UpdateCommandEnabled(IDC_ZOOM_MINUS, is_web_contents);
2052 // Show various bits of UI
2053 command_updater_.UpdateCommandEnabled(IDC_JS_CONSOLE, is_web_contents);
2054 command_updater_.UpdateCommandEnabled(IDC_CREATE_SHORTCUTS,
2055 is_web_contents && !current_tab->GetFavIcon().isNull());
2059 void Browser::UpdateCommandsForFullscreenMode(bool is_fullscreen) {
2060 const bool show_main_ui = (type() == TYPE_NORMAL) && !is_fullscreen;
2062 // Navigation commands
2063 command_updater_.UpdateCommandEnabled(IDC_OPEN_CURRENT_URL, show_main_ui);
2065 // Window management commands
2066 command_updater_.UpdateCommandEnabled(IDC_PROFILE_MENU, show_main_ui);
2067 command_updater_.UpdateCommandEnabled(IDC_SHOW_AS_TAB,
2068 (type() == TYPE_POPUP) && !is_fullscreen);
2070 // Focus various bits of UI
2071 command_updater_.UpdateCommandEnabled(IDC_FOCUS_TOOLBAR, show_main_ui);
2072 command_updater_.UpdateCommandEnabled(IDC_FOCUS_LOCATION, show_main_ui);
2073 command_updater_.UpdateCommandEnabled(IDC_FOCUS_SEARCH, show_main_ui);
2075 // Show various bits of UI
2076 command_updater_.UpdateCommandEnabled(IDC_DEVELOPER_MENU, show_main_ui);
2077 #if defined(OS_WIN)
2078 command_updater_.UpdateCommandEnabled(IDC_DEBUGGER,
2079 // The debugger doesn't work in single process mode.
2080 show_main_ui && !RenderProcessHost::run_renderer_in_process());
2081 #endif
2082 command_updater_.UpdateCommandEnabled(IDC_NEW_PROFILE, show_main_ui);
2083 command_updater_.UpdateCommandEnabled(IDC_REPORT_BUG, show_main_ui);
2084 command_updater_.UpdateCommandEnabled(IDC_SHOW_BOOKMARK_BAR, show_main_ui);
2085 command_updater_.UpdateCommandEnabled(IDC_CLEAR_BROWSING_DATA, show_main_ui);
2086 command_updater_.UpdateCommandEnabled(IDC_IMPORT_SETTINGS, show_main_ui);
2087 command_updater_.UpdateCommandEnabled(IDC_OPTIONS, show_main_ui);
2088 command_updater_.UpdateCommandEnabled(IDC_EDIT_SEARCH_ENGINES, show_main_ui);
2089 command_updater_.UpdateCommandEnabled(IDC_VIEW_PASSWORDS, show_main_ui);
2090 command_updater_.UpdateCommandEnabled(IDC_ABOUT, show_main_ui);
2093 void Browser::UpdateStopGoState(bool is_loading) {
2094 window_->UpdateStopGoState(is_loading);
2095 command_updater_.UpdateCommandEnabled(IDC_GO, !is_loading);
2096 command_updater_.UpdateCommandEnabled(IDC_STOP, is_loading);
2100 ///////////////////////////////////////////////////////////////////////////////
2101 // Browser, UI update coalescing and handling (private):
2103 void Browser::UpdateToolbar(bool should_restore_state) {
2104 window_->UpdateToolbar(GetSelectedTabContents(), should_restore_state);
2107 void Browser::ScheduleUIUpdate(const TabContents* source,
2108 unsigned changed_flags) {
2109 // Synchronously update the URL.
2110 if (changed_flags & TabContents::INVALIDATE_URL &&
2111 source == GetSelectedTabContents()) {
2112 // Only update the URL for the current tab. Note that we do not update
2113 // the navigation commands since those would have already been updated
2114 // synchronously by NavigationStateChanged.
2115 UpdateToolbar(false);
2117 if (changed_flags == TabContents::INVALIDATE_URL)
2118 return; // Just had an update URL and nothing else.
2121 // Save the dirty bits.
2122 scheduled_updates_.push_back(UIUpdate(source, changed_flags));
2124 if (chrome_updater_factory_.empty()) {
2125 // No task currently scheduled, start another.
2126 MessageLoop::current()->PostDelayedTask(FROM_HERE,
2127 chrome_updater_factory_.NewRunnableMethod(
2128 &Browser::ProcessPendingUIUpdates),
2129 kUIUpdateCoalescingTimeMS);
2133 void Browser::ProcessPendingUIUpdates() {
2134 #ifndef NDEBUG
2135 // Validate that all tabs we have pending updates for exist. This is scary
2136 // because the pending list must be kept in sync with any detached or
2137 // deleted tabs. This code does not dereference any TabContents pointers.
2138 for (size_t i = 0; i < scheduled_updates_.size(); i++) {
2139 bool found = false;
2140 for (int tab = 0; tab < tab_count(); tab++) {
2141 if (GetTabContentsAt(tab)->controller() ==
2142 scheduled_updates_[i].source->controller()) {
2143 found = true;
2144 break;
2147 DCHECK(found);
2149 #endif
2151 chrome_updater_factory_.RevokeAll();
2153 // We could have many updates for the same thing in the queue. This map
2154 // tracks the bits of the stuff we've already updated for each TabContents so
2155 // we don't update again.
2156 typedef std::map<const TabContents*, unsigned> UpdateTracker;
2157 UpdateTracker updated_stuff;
2159 for (size_t i = 0; i < scheduled_updates_.size(); i++) {
2160 // Do not dereference |contents|, it may be out-of-date!
2161 const TabContents* contents = scheduled_updates_[i].source;
2162 unsigned flags = scheduled_updates_[i].changed_flags;
2164 // Remove any bits we have already updated, and save the new bits.
2165 UpdateTracker::iterator updated = updated_stuff.find(contents);
2166 if (updated != updated_stuff.end()) {
2167 // Turn off bits already set.
2168 flags &= ~updated->second;
2169 if (!flags)
2170 continue;
2172 updated->second |= flags;
2173 } else {
2174 updated_stuff[contents] = flags;
2177 // Updates to the title or favicon require a tab repaint. However, the
2178 // inverse is not true since updates to the title also update the window
2179 // title.
2180 bool invalidate_tab = false;
2181 if (flags & TabContents::INVALIDATE_TITLE ||
2182 flags & TabContents::INVALIDATE_FAVICON) {
2183 invalidate_tab = true;
2185 // Anything that repaints the tab means the favicon is updated.
2186 updated_stuff[contents] |= TabContents::INVALIDATE_FAVICON;
2189 // Updating the URL happens synchronously in ScheduleUIUpdate.
2191 if (flags & TabContents::INVALIDATE_LOAD && GetStatusBubble())
2192 GetStatusBubble()->SetStatus(GetSelectedTabContents()->GetStatusText());
2194 if (invalidate_tab) { // INVALIDATE_TITLE or INVALIDATE_FAVICON.
2195 tabstrip_model_.UpdateTabContentsStateAt(
2196 tabstrip_model_.GetIndexOfController(contents->controller()));
2197 window_->UpdateTitleBar();
2199 if (contents == GetSelectedTabContents()) {
2200 TabContents* current_tab = GetSelectedTabContents();
2201 command_updater_.UpdateCommandEnabled(IDC_CREATE_SHORTCUTS,
2202 current_tab->type() == TAB_CONTENTS_WEB &&
2203 !current_tab->GetFavIcon().isNull());
2207 // We don't need to process INVALIDATE_STATE, since that's not visible.
2210 scheduled_updates_.clear();
2213 void Browser::RemoveScheduledUpdatesFor(TabContents* contents) {
2214 if (!contents)
2215 return;
2217 // Remove any pending UI updates for the detached tab.
2218 UpdateVector::iterator cur_update = scheduled_updates_.begin();
2219 while (cur_update != scheduled_updates_.end()) {
2220 if (cur_update->source == contents) {
2221 cur_update = scheduled_updates_.erase(cur_update);
2222 } else {
2223 ++cur_update;
2229 ///////////////////////////////////////////////////////////////////////////////
2230 // Browser, Getters for UI (private):
2232 StatusBubble* Browser::GetStatusBubble() {
2233 return window_->GetStatusBubble();
2236 ///////////////////////////////////////////////////////////////////////////////
2237 // Browser, Session restore functions (private):
2239 void Browser::SyncHistoryWithTabs(int index) {
2240 if (!profile()->HasSessionService())
2241 return;
2242 SessionService* session_service = profile()->GetSessionService();
2243 if (session_service) {
2244 for (int i = index; i < tab_count(); ++i) {
2245 TabContents* contents = GetTabContentsAt(i);
2246 if (contents) {
2247 session_service->SetTabIndexInWindow(
2248 session_id(), contents->controller()->session_id(), i);
2254 NavigationController* Browser::BuildRestoredNavigationController(
2255 const std::vector<TabNavigation>& navigations,
2256 int selected_navigation) {
2257 if (!navigations.empty()) {
2258 DCHECK(selected_navigation >= 0 &&
2259 selected_navigation < static_cast<int>(navigations.size()));
2260 // Create a NavigationController. This constructor creates the appropriate
2261 // set of TabContents.
2262 return new NavigationController(profile_, navigations, selected_navigation);
2263 } else {
2264 // No navigations. Create a tab with about:blank.
2265 TabContents* contents =
2266 CreateTabContentsForURL(GURL("about:blank"), GURL(), profile_,
2267 PageTransition::START_PAGE, false, NULL);
2268 return new NavigationController(contents, profile_);
2272 ///////////////////////////////////////////////////////////////////////////////
2273 // Browser, OnBeforeUnload handling (private):
2275 void Browser::ProcessPendingTabs() {
2276 DCHECK(is_attempting_to_close_browser_);
2278 if (HasCompletedUnloadProcessing()) {
2279 // We've finished all the unload events and can proceed to close the
2280 // browser.
2281 OnWindowClosing();
2282 return;
2285 // Process beforeunload tabs first. When that queue is empty, process
2286 // unload tabs.
2287 if (!tabs_needing_before_unload_fired_.empty()) {
2288 TabContents* tab = *(tabs_needing_before_unload_fired_.begin());
2289 tab->AsWebContents()->render_view_host()->FirePageBeforeUnload();
2290 } else if (!tabs_needing_unload_fired_.empty()) {
2291 // We've finished firing all beforeunload events and can proceed with unload
2292 // events.
2293 // TODO(ojan): We should add a call to browser_shutdown::OnShutdownStarting
2294 // somewhere around here so that we have accurate measurements of shutdown
2295 // time.
2296 // TODO(ojan): We can probably fire all the unload events in parallel and
2297 // get a perf benefit from that in the cases where the tab hangs in it's
2298 // unload handler or takes a long time to page in.
2299 TabContents* tab = *(tabs_needing_unload_fired_.begin());
2300 tab->AsWebContents()->render_view_host()->FirePageUnload();
2301 } else {
2302 NOTREACHED();
2306 bool Browser::HasCompletedUnloadProcessing() {
2307 return is_attempting_to_close_browser_ &&
2308 tabs_needing_before_unload_fired_.empty() &&
2309 tabs_needing_unload_fired_.empty();
2312 void Browser::CancelWindowClose() {
2313 DCHECK(is_attempting_to_close_browser_);
2314 // Only cancelling beforeunload should be able to cancel the window's close.
2315 // So there had better be a tab that we think needs beforeunload fired.
2316 DCHECK(!tabs_needing_before_unload_fired_.empty());
2318 tabs_needing_before_unload_fired_.clear();
2319 tabs_needing_unload_fired_.clear();
2321 is_attempting_to_close_browser_ = false;
2324 bool Browser::RemoveFromSet(UnloadListenerSet* set, TabContents* tab) {
2325 DCHECK(is_attempting_to_close_browser_);
2327 UnloadListenerSet::iterator iter = std::find(set->begin(), set->end(), tab);
2328 if (iter != set->end()) {
2329 set->erase(iter);
2330 return true;
2332 return false;
2335 void Browser::ClearUnloadState(TabContents* tab) {
2336 DCHECK(is_attempting_to_close_browser_);
2337 RemoveFromSet(&tabs_needing_before_unload_fired_, tab);
2338 RemoveFromSet(&tabs_needing_unload_fired_, tab);
2339 ProcessPendingTabs();
2343 ///////////////////////////////////////////////////////////////////////////////
2344 // Browser, Assorted utility functions (private):
2346 Browser* Browser::GetOrCreateTabbedBrowser() {
2347 Browser* browser = BrowserList::FindBrowserWithType(
2348 profile_, TYPE_NORMAL);
2349 if (!browser)
2350 browser = Browser::Create(profile_);
2351 return browser;
2354 void Browser::BuildPopupWindow(TabContents* source,
2355 TabContents* new_contents,
2356 const gfx::Rect& initial_pos) {
2357 Browser* browser =
2358 new Browser((type_ == TYPE_APP) ? TYPE_APP : TYPE_POPUP, profile_);
2359 browser->set_override_bounds(initial_pos);
2360 browser->CreateBrowserWindow();
2361 // We need to Show before AddNewContents, otherwise AddNewContents will focus
2362 // it (via BrowserView::TabSelectedAt calling RestoreFocus), triggering any
2363 // onblur="" handlers.
2364 browser->window()->Show();
2365 // TODO(beng): See if this can be made to use
2366 // TabStripModel::AppendTabContents.
2367 browser->AddNewContents(source, new_contents, NEW_FOREGROUND_TAB,
2368 gfx::Rect(), true);
2371 GURL Browser::GetHomePage() {
2372 if (profile_->GetPrefs()->GetBoolean(prefs::kHomePageIsNewTabPage))
2373 return NewTabUIURL();
2374 GURL home_page = GURL(URLFixerUpper::FixupURL(
2375 WideToUTF8(profile_->GetPrefs()->GetString(prefs::kHomePage)),
2376 std::string()));
2377 if (!home_page.is_valid())
2378 return NewTabUIURL();
2379 return home_page;
2382 #if defined(OS_WIN)
2383 void Browser::FindInPage(bool find_next, bool forward_direction) {
2384 window_->ShowFindBar();
2385 if (find_next) {
2386 GetSelectedTabContents()->AsWebContents()->StartFinding(
2387 std::wstring(),
2388 forward_direction);
2391 #endif // OS_WIN
2393 void Browser::CloseFrame() {
2394 window_->Close();
2397 // static
2398 std::wstring Browser::ComputeApplicationNameFromURL(const GURL& url) {
2399 std::string t;
2400 t.append(url.host());
2401 t.append("_");
2402 t.append(url.path());
2403 return UTF8ToWide(t);
2406 // static
2407 void Browser::RegisterAppPrefs(const std::wstring& app_name) {
2408 // A set of apps that we've already started.
2409 static std::set<std::wstring>* g_app_names = NULL;
2411 if (!g_app_names)
2412 g_app_names = new std::set<std::wstring>;
2414 // Only register once for each app name.
2415 if (g_app_names->find(app_name) != g_app_names->end())
2416 return;
2417 g_app_names->insert(app_name);
2419 // We need to register the window position pref.
2420 std::wstring window_pref(prefs::kBrowserWindowPlacement);
2421 window_pref.append(L"_");
2422 window_pref.append(app_name);
2423 PrefService* prefs = g_browser_process->local_state();
2424 DCHECK(prefs);
2426 prefs->RegisterDictionaryPref(window_pref.c_str());