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"
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"
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"
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
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
{
102 for (ChildProcessHost::Iterator iter
; !iter
.Done(); ++iter
)
103 iter
->ReduceWorkingSet();
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
{
114 : base::IdleTimer(TimeDelta::FromSeconds(kBrowserReleaseMemoryInterval
),
118 virtual void OnIdle() {
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());
142 ///////////////////////////////////////////////////////////////////////////////
144 struct Browser::UIUpdate
{
145 UIUpdate(const TabContents
* src
, unsigned flags
)
147 changed_flags(flags
) {
150 // The source of the update.
151 const TabContents
* source
;
153 // What changed in the UI.
154 unsigned changed_flags
;
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();
169 ///////////////////////////////////////////////////////////////////////////////
170 // Browser, Constructors, Creation, Showing:
172 Browser::Browser(Type type
, Profile
* profile
)
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(
188 NotificationType::SSL_STATE_CHANGED
,
189 NotificationService::AllSources());
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
)
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());
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
220 profile_
->ResetTabRestoreService();
223 SessionService
* session_service
= profile_
->GetSessionService();
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(
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();
254 Browser
* Browser::Create(Profile
* profile
) {
255 Browser
* browser
= new Browser(TYPE_NORMAL
, profile
);
256 browser
->CreateBrowserWindow();
261 Browser
* Browser::CreateForPopup(Profile
* profile
) {
262 Browser
* browser
= new Browser(TYPE_POPUP
, profile
);
263 browser
->CreateBrowserWindow();
268 Browser
* Browser::CreateForApp(const std::wstring
& app_name
,
270 Browser
* browser
= new Browser(TYPE_APP
, profile
);
271 browser
->app_name_
= app_name
;
272 browser
->CreateBrowserWindow();
276 void Browser::CreateBrowserWindow() {
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();
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:
296 void Browser::OpenEmptyWindow(Profile
* profile
) {
297 Browser
* browser
= Browser::Create(profile
);
298 browser
->AddBlankTab(true);
299 browser
->window()->Show();
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
,
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();
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()) {
332 name
.append(app_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();
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
364 return gfx::Rect(0, 0, 800, 600);
367 gfx::Rect restored_bounds
= override_bounds_
;
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
))
380 gfx::Rect restored_bounds
;
381 bool maximized
= override_maximized_
;
382 WindowSizer::GetBrowserWindowBounds(app_name_
, restored_bounds
,
383 &restored_bounds
, &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 {
396 TabContents
* contents
= tabstrip_model_
.GetSelectedTabContents();
399 // |contents| can be NULL because GetCurrentPageTitle is called by the window
400 // during the window's creation (before tabs have been added).
402 title
= contents
->GetTitle();
403 FormatTitleForDisplay(&title
);
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
416 void Browser::FormatTitleForDisplay(std::wstring
* title
) {
417 size_t current_index
= 0;
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()) {
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())
445 ProcessPendingTabs();
449 void Browser::OnWindowClosing() {
450 if (!ShouldCloseWindow())
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
);
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();
464 session_service
->WindowClosing(session_id());
466 TabRestoreService
* tab_restore_service
= profile()->GetTabRestoreService();
467 if (tab_restore_service
)
468 tab_restore_service
->BrowserClosing(this);
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.";
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
,
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.
494 contents
->WasHidden();
498 TabContents
* Browser::AddTabWithNavigationController(
499 NavigationController
* ctrl
, PageTransition::Type type
) {
500 TabContents
* tc
= ctrl
->active_contents();
501 tabstrip_model_
.AddTabContents(tc
, -1, type
, true);
505 NavigationController
* Browser::AddRestoredTab(
506 const std::vector
<TabNavigation
>& navigations
,
508 int selected_navigation
,
510 NavigationController
* restored_controller
=
511 BuildRestoredNavigationController(navigations
, selected_navigation
);
513 tabstrip_model_
.InsertTabContentsAt(
515 restored_controller
->active_contents(),
517 if (profile_
->HasSessionService()) {
518 SessionService
* session_service
= profile_
->GetSessionService();
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
) {
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);
548 TabContents
* contents
= CreateTabContentsForURL(url
, GURL(), profile_
,
549 PageTransition::LINK
, false,
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();
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();
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
);
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());
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
) {
640 UserMetrics::RecordAction(L
"NewProfileWindowByIndex", profile_
);
641 UserDataManager::Get()->LaunchChromeForProfile(index
);
645 void Browser::CloseWindow() {
646 UserMetrics::RecordAction(L
"CloseWindow", profile_
);
650 void Browser::NewTab() {
651 UserMetrics::RecordAction(L
"NewTab", profile_
);
652 if (type() == TYPE_NORMAL
) {
655 Browser
* b
= GetOrCreateTabbedBrowser();
656 b
->AddBlankTab(true);
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();
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();
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();
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())
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();
752 GURL
url("view-source:" + entry
->url().spec());
753 OpenURL(url
, GURL(), NEW_FOREGROUND_TAB
, PageTransition::LINK
);
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.
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
),
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
)) {
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()) {
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(
867 void Browser::ZoomReset() {
868 UserMetrics::RecordAction(L
"ZoomNormal", profile_
);
869 GetSelectedTabContents()->AsWebContents()->render_view_host()->Zoom(
873 void Browser::ZoomOut() {
874 UserMetrics::RecordAction(L
"ZoomMinus", profile_
);
875 GetSelectedTabContents()->AsWebContents()->render_view_host()->Zoom(
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(),
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
);
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_
);
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,
1010 ///////////////////////////////////////////////////////////////////////////////
1013 void Browser::RegisterPrefs(PrefService
* prefs
) {
1014 prefs
->RegisterDictionaryPref(prefs::kBrowserWindowPlacement
);
1015 prefs
->RegisterIntegerPref(prefs::kOptionsWindowLastTabIndex
, 0);
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);
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
) {
1043 *index_result
= index
;
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())
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!
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;
1093 case IDC_CLOSE_WINDOW
: CloseWindow(); break;
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
);
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;
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;
1167 case IDC_FIND
: Find(); break;
1168 case IDC_FIND_NEXT
: FindNext(); break;
1169 case IDC_FIND_PREVIOUS
: FindPrevious(); break;
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
1196 Personalization::HandleMenuItemClick(profile()); break;
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;
1208 LOG(WARNING
) << "Received Unimplemented Command: " << id
;
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 {
1244 if (BrowserList::GetBrowserCountForType(profile_
, TYPE_NORMAL
) > 1 ||
1246 result
|= TAB_TEAROFF_ACTION
;
1247 if (tab_count() > 1)
1248 result
|= TAB_MOVE_ACTION
;
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
);
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
);
1273 bool Browser::CanDuplicateContentsAt(int index
) {
1274 TabContents
* contents
= GetTabContentsAt(index
);
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
;
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);
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() {
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
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
));
1340 void Browser::CreateHistoricalTab(TabContents
* contents
) {
1341 // We don't create historical tabs for incognito windows or windows without
1343 if (!profile() || profile()->IsOffTheRecord() ||
1344 !profile()->GetTabRestoreService()) {
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();
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
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();
1375 ///////////////////////////////////////////////////////////////////////////////
1376 // Browser, TabStripModelObserver implementation:
1378 void Browser::TabInsertedAt(TabContents
* contents
,
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(
1394 NotificationType::WEB_CONTENTS_DISCONNECTED
,
1395 Source
<TabContents
>(contents
));
1398 void Browser::TabClosingAt(TabContents
* contents
, int index
) {
1399 NavigationController
* controller
= contents
->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(
1419 NotificationType::WEB_CONTENTS_DISCONNECTED
,
1420 Source
<TabContents
>(contents
));
1423 void Browser::TabSelectedAt(TabContents
* old_contents
,
1424 TabContents
* new_contents
,
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();
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
,
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
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
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
)) {
1516 const WebContents
* const web_contents
= current_tab
->AsWebContents();
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
);
1536 Browser
* b
= GetOrCreateTabbedBrowser();
1539 // If we have just created a new browser window, make sure we select the
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();
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,
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
);
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
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.
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(
1624 NotificationType::WEB_CONTENTS_DISCONNECTED
,
1625 Source
<TabContents
>(source
));
1626 NotificationService::current()->AddObserver(
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();
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();
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
);
1701 int index
= tabstrip_model_
.GetIndexOfTabContents(source
);
1702 if (index
== TabStripModel::kNoTab
) {
1703 NOTREACHED() << "CloseContents called for tab not in our strip";
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";
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
);
1735 // TODO(port): Refactor this to win-specific delegate?
1736 void Browser::ContentsMouseEvent(TabContents
* source
, UINT message
) {
1737 if (!GetStatusBubble())
1740 if (source
== GetSelectedTabContents()) {
1741 if (message
== WM_MOUSEMOVE
) {
1742 GetStatusBubble()->MouseMoved();
1743 } else if (message
== WM_MOUSELEAVE
) {
1744 GetStatusBubble()->SetURL(GURL(), std::wstring());
1750 void Browser::UpdateTargetURL(TabContents
* source
, const GURL
& url
) {
1751 if (!GetStatusBubble())
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
);
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
,
1795 bool* proceed_to_fire_unload
) {
1796 if (!is_attempting_to_close_browser_
) {
1797 *proceed_to_fire_unload
= proceed
;
1802 CancelWindowClose();
1803 *proceed_to_fire_unload
= false;
1807 if (RemoveFromSet(&tabs_needing_before_unload_fired_
, tab
)) {
1808 // Now that beforeunload has fired, put the tab on the queue to fire
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;
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
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()));
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);
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
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
,
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.
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
,
2038 SavePackage::IsSavableContents(web_contents
->contents_mime_type()) &&
2039 SavePackage::IsSavableURL(current_tab
->GetURL()));
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
);
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
);
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());
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() {
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
++) {
2140 for (int tab
= 0; tab
< tab_count(); tab
++) {
2141 if (GetTabContentsAt(tab
)->controller() ==
2142 scheduled_updates_
[i
].source
->controller()) {
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
;
2172 updated
->second
|= flags
;
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
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
) {
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
);
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())
2242 SessionService
* session_service
= profile()->GetSessionService();
2243 if (session_service
) {
2244 for (int i
= index
; i
< tab_count(); ++i
) {
2245 TabContents
* contents
= GetTabContentsAt(i
);
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
);
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
2285 // Process beforeunload tabs first. When that queue is empty, process
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
2293 // TODO(ojan): We should add a call to browser_shutdown::OnShutdownStarting
2294 // somewhere around here so that we have accurate measurements of shutdown
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();
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()) {
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
);
2350 browser
= Browser::Create(profile_
);
2354 void Browser::BuildPopupWindow(TabContents
* source
,
2355 TabContents
* new_contents
,
2356 const gfx::Rect
& initial_pos
) {
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
,
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
)),
2377 if (!home_page
.is_valid())
2378 return NewTabUIURL();
2383 void Browser::FindInPage(bool find_next
, bool forward_direction
) {
2384 window_
->ShowFindBar();
2386 GetSelectedTabContents()->AsWebContents()->StartFinding(
2393 void Browser::CloseFrame() {
2398 std::wstring
Browser::ComputeApplicationNameFromURL(const GURL
& url
) {
2400 t
.append(url
.host());
2402 t
.append(url
.path());
2403 return UTF8ToWide(t
);
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
;
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())
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();
2426 prefs
->RegisterDictionaryPref(window_pref
.c_str());