blob: 7997348f75403d8e00d2f7e3919e628d54191865 [file] [log] [blame]
license.botbf09a502008-08-24 00:55:551// 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.
initial.commit09911bf2008-07-26 23:55:294
initial.commit09911bf2008-07-26 23:55:295#include <windows.h>
6#include <shellapi.h>
7
[email protected]15952e462008-11-14 00:29:058#include "chrome/browser/browser.h"
9
initial.commit09911bf2008-07-26 23:55:2910#include "base/command_line.h"
11#include "base/idle_timer.h"
12#include "base/logging.h"
13#include "base/string_util.h"
[email protected]012d2fb2008-09-13 01:30:0514#include "chrome/app/chrome_dll_resource.h"
[email protected]36b6dcb2008-11-12 01:19:5715#include "chrome/app/locales/locale_settings.h"
16#include "chrome/browser/automation/ui_controls.h"
initial.commit09911bf2008-07-26 23:55:2917#include "chrome/browser/browser_list.h"
18#include "chrome/browser/browser_process.h"
19#include "chrome/browser/browser_shutdown.h"
20#include "chrome/browser/browser_url_handler.h"
[email protected]012d2fb2008-09-13 01:30:0521#include "chrome/browser/browser_window.h"
initial.commit09911bf2008-07-26 23:55:2922#include "chrome/browser/cert_store.h"
[email protected]36b6dcb2008-11-12 01:19:5723#include "chrome/browser/character_encoding.h"
[email protected]1eb89e82008-08-15 12:27:0324#include "chrome/browser/debugger/debugger_window.h"
[email protected]2baf83d2008-07-30 05:58:1725#include "chrome/browser/dom_ui/new_tab_ui.h"
[email protected]37936ee2008-09-14 01:09:5026#include "chrome/browser/download/save_package.h"
[email protected]36b6dcb2008-11-12 01:19:5727#include "chrome/browser/history_tab_ui.h"
28#include "chrome/browser/interstitial_page.h"
initial.commit09911bf2008-07-26 23:55:2929#include "chrome/browser/navigation_controller.h"
30#include "chrome/browser/navigation_entry.h"
[email protected]36b6dcb2008-11-12 01:19:5731#include "chrome/browser/options_window.h"
initial.commit09911bf2008-07-26 23:55:2932#include "chrome/browser/plugin_process_host.h"
33#include "chrome/browser/plugin_service.h"
34#include "chrome/browser/profile.h"
initial.commit09911bf2008-07-26 23:55:2935#include "chrome/browser/ssl_error_info.h"
36#include "chrome/browser/site_instance.h"
[email protected]36b6dcb2008-11-12 01:19:5737#include "chrome/browser/task_manager.h"
initial.commit09911bf2008-07-26 23:55:2938#include "chrome/browser/url_fixer_upper.h"
39#include "chrome/browser/user_metrics.h"
40#include "chrome/browser/view_ids.h"
[email protected]36b6dcb2008-11-12 01:19:5741#include "chrome/browser/views/download_tab_view.h"
42#include "chrome/browser/views/go_button.h"
initial.commit09911bf2008-07-26 23:55:2943#include "chrome/browser/views/location_bar_view.h"
[email protected]012d2fb2008-09-13 01:30:0544#include "chrome/browser/views/status_bubble.h"
initial.commit09911bf2008-07-26 23:55:2945#include "chrome/browser/views/toolbar_star_toggle.h"
[email protected]807bfce2008-10-14 16:42:2546#include "chrome/browser/web_contents_view.h"
initial.commit09911bf2008-07-26 23:55:2947#include "chrome/browser/window_sizer.h"
48#include "chrome/common/chrome_constants.h"
49#include "chrome/common/chrome_switches.h"
50#include "chrome/common/l10n_util.h"
51#include "chrome/common/pref_names.h"
52#include "chrome/common/pref_service.h"
[email protected]1eb89e82008-08-15 12:27:0353#include "chrome/common/win_util.h"
initial.commit09911bf2008-07-26 23:55:2954#include "net/base/cookie_monster.h"
55#include "net/base/cookie_policy.h"
56#include "net/base/net_util.h"
57#include "net/base/registry_controlled_domain.h"
58
[email protected]b08de9cd2008-08-27 23:40:2259#include "chromium_strings.h"
initial.commit09911bf2008-07-26 23:55:2960#include "generated_resources.h"
61
[email protected]e1acf6f2008-10-27 20:43:3362using base::TimeDelta;
63
initial.commit09911bf2008-07-26 23:55:2964static BrowserList g_browserlist;
65
66// How long we wait before updating the browser chrome while loading a page.
67static const int kUIUpdateCoalescingTimeMS = 200;
68
69// Idle time before helping prune memory consumption.
70static const int kBrowserReleaseMemoryInterval = 30; // In seconds.
71
72// How much horizontal and vertical offset there is between newly opened
73// windows.
[email protected]eb0c1e42008-08-04 17:58:0074static const int kWindowTilePixels = 20;
initial.commit09911bf2008-07-26 23:55:2975
[email protected]36b6dcb2008-11-12 01:19:5776///////////////////////////////////////////////////////////////////////////////
initial.commit09911bf2008-07-26 23:55:2977
78// A task to reduce the working set of the plugins.
79class ReducePluginsWorkingSetTask : public Task {
80 public:
81 virtual void Run() {
82 for (PluginProcessHostIterator iter; !iter.Done(); ++iter) {
83 PluginProcessHost* plugin = const_cast<PluginProcessHost*>(*iter);
84 DCHECK(plugin->process());
[email protected]176aa482008-11-14 03:25:1585 base::Process process(plugin->process());
initial.commit09911bf2008-07-26 23:55:2986 process.ReduceWorkingSet();
87 }
88 }
89};
90
91// A browser task to run when the user is not using the browser.
92// In our case, we're trying to be nice to the operating system and release
93// memory not in use.
[email protected]aeab57ea2008-08-28 20:50:1294class BrowserIdleTimer : public base::IdleTimer {
initial.commit09911bf2008-07-26 23:55:2995 public:
[email protected]aeab57ea2008-08-28 20:50:1296 BrowserIdleTimer()
97 : base::IdleTimer(TimeDelta::FromSeconds(kBrowserReleaseMemoryInterval),
98 false) {
initial.commit09911bf2008-07-26 23:55:2999 }
100
101 virtual void OnIdle() {
102 // We're idle. Release browser and renderer unused pages.
103
104 // Handle the Browser.
[email protected]176aa482008-11-14 03:25:15105 base::Process process(GetCurrentProcess());
initial.commit09911bf2008-07-26 23:55:29106 process.ReduceWorkingSet();
107
108 // Handle the Renderer(s).
109 RenderProcessHost::iterator renderer_iter;
110 for (renderer_iter = RenderProcessHost::begin(); renderer_iter !=
[email protected]176aa482008-11-14 03:25:15111 RenderProcessHost::end(); renderer_iter++) {
112 base::Process process = renderer_iter->second->process();
initial.commit09911bf2008-07-26 23:55:29113 process.ReduceWorkingSet();
114 }
115
[email protected]36b6dcb2008-11-12 01:19:57116 // Handle the Plugin(s). We need to iterate through the plugin processes
117 // on the IO thread because that thread manages the plugin process
118 // collection.
initial.commit09911bf2008-07-26 23:55:29119 g_browser_process->io_thread()->message_loop()->PostTask(FROM_HERE,
120 new ReducePluginsWorkingSetTask());
121 }
122};
123
[email protected]36b6dcb2008-11-12 01:19:57124///////////////////////////////////////////////////////////////////////////////
initial.commit09911bf2008-07-26 23:55:29125
126struct Browser::UIUpdate {
127 UIUpdate(const TabContents* src, unsigned flags)
128 : source(src),
129 changed_flags(flags) {
130 }
131
132 // The source of the update.
133 const TabContents* source;
134
135 // What changed in the UI.
136 unsigned changed_flags;
137};
138
[email protected]36b6dcb2008-11-12 01:19:57139///////////////////////////////////////////////////////////////////////////////
140// Browser, Constructors, Creation, Showing:
initial.commit09911bf2008-07-26 23:55:29141
[email protected]15952e462008-11-14 00:29:05142Browser::Browser(BrowserType::Type type, Profile* profile)
143 : type_(type),
144 profile_(profile),
[email protected]f3e99e32008-07-30 04:48:39145 window_(NULL),
initial.commit09911bf2008-07-26 23:55:29146 tabstrip_model_(this, profile),
[email protected]15952e462008-11-14 00:29:05147 controller_(this),
initial.commit09911bf2008-07-26 23:55:29148 toolbar_model_(this),
[email protected]15952e462008-11-14 00:29:05149 chrome_updater_factory_(this),
150 is_attempting_to_close_browser_(false),
151 override_maximized_(false),
152 method_factory_(this),
153 idle_task_(new BrowserIdleTimer) {
initial.commit09911bf2008-07-26 23:55:29154 tabstrip_model_.AddObserver(this);
155
[email protected]e83f1682008-09-07 23:57:40156 NotificationService::current()->AddObserver(
157 this, NOTIFY_SSL_STATE_CHANGED, NotificationService::AllSources());
initial.commit09911bf2008-07-26 23:55:29158
initial.commit09911bf2008-07-26 23:55:29159 InitCommandState();
160 BrowserList::AddBrowser(this);
161
162 encoding_auto_detect_.Init(prefs::kWebKitUsesUniversalDetector,
163 profile_->GetPrefs(), NULL);
164
165 // Trim browser memory on idle for low & medium memory models.
166 if (g_browser_process->memory_model() < BrowserProcess::HIGH_MEMORY_MODEL)
167 idle_task_->Start();
initial.commit09911bf2008-07-26 23:55:29168}
169
170Browser::~Browser() {
171 // The tab strip should be empty at this point.
172 DCHECK(tabstrip_model_.empty());
173 tabstrip_model_.RemoveObserver(this);
174
175 BrowserList::RemoveBrowser(this);
176
177 if (!BrowserList::HasBrowserWithProfile(profile_)) {
178 // We're the last browser window with this profile. We need to nuke the
179 // TabRestoreService, which will start the shutdown of the
180 // NavigationControllers and allow for proper shutdown. If we don't do this
181 // chrome won't shutdown cleanly, and may end up crashing when some
182 // thread tries to use the IO thread (or another thread) that is no longer
183 // valid.
184 profile_->ResetTabRestoreService();
185 }
186
187 SessionService* session_service = profile_->GetSessionService();
188 if (session_service)
189 session_service->WindowClosed(session_id_);
190
[email protected]e83f1682008-09-07 23:57:40191 NotificationService::current()->RemoveObserver(
192 this, NOTIFY_SSL_STATE_CHANGED, NotificationService::AllSources());
initial.commit09911bf2008-07-26 23:55:29193
initial.commit09911bf2008-07-26 23:55:29194 if (profile_->IsOffTheRecord() &&
195 !BrowserList::IsOffTheRecordSessionActive()) {
196 // We reuse the OTR cookie store across OTR windows. If the last OTR
197 // window is closed, then we want to wipe the cookie store clean, so when
198 // an OTR window is open again, it starts with an empty cookie store. This
199 // also frees up the memory that the OTR cookies were using. OTR never
200 // loads or writes persistent cookies (there is no backing store), so we
201 // can just delete all of the cookies in the store.
202 profile_->GetRequestContext()->cookie_store()->DeleteAll(false);
203 }
204
205 // There may be pending file dialogs, we need to tell them that we've gone
206 // away so they don't try and call back to us.
207 if (select_file_dialog_.get())
208 select_file_dialog_->ListenerDestroyed();
209}
210
[email protected]15952e462008-11-14 00:29:05211// static
212Browser* Browser::Create(Profile* profile) {
213 Browser* browser = new Browser(BrowserType::TABBED_BROWSER, profile);
214 browser->CreateBrowserWindow();
215 return browser;
216}
[email protected]6104acf2008-11-11 22:27:34217
[email protected]15952e462008-11-14 00:29:05218// static
219Browser* Browser::CreateForPopup(Profile* profile) {
220 Browser* browser = new Browser(BrowserType::BROWSER, profile);
221 browser->CreateBrowserWindow();
222 return browser;
223}
224
225// static
226Browser* Browser::CreateForApp(const std::wstring& app_name,
227 Profile* profile) {
228 Browser* browser = new Browser(BrowserType::APPLICATION, profile);
229 browser->app_name_ = app_name;
230 browser->CreateBrowserWindow();
231 return browser;
232}
233
234void Browser::CreateBrowserWindow() {
235 DCHECK(!window_);
236 window_ = BrowserWindow::CreateBrowserWindow(this);
237
238 // Show the First Run information bubble if we've been told to.
239 PrefService* local_state = g_browser_process->local_state();
240 if (local_state->IsPrefRegistered(prefs::kShouldShowFirstRunBubble) &&
241 local_state->GetBoolean(prefs::kShouldShowFirstRunBubble)) {
242 // Reset the preference so we don't show the bubble for subsequent windows.
243 local_state->ClearPref(prefs::kShouldShowFirstRunBubble);
244 GetLocationBarView()->ShowFirstRunBubble();
initial.commit09911bf2008-07-26 23:55:29245 }
initial.commit09911bf2008-07-26 23:55:29246}
247
[email protected]36b6dcb2008-11-12 01:19:57248///////////////////////////////////////////////////////////////////////////////
249// Browser, Creation Helpers:
250
251// static
[email protected]15952e462008-11-14 00:29:05252void Browser::OpenEmptyWindow(Profile* profile) {
253 Browser* browser = Browser::Create(profile);
[email protected]36b6dcb2008-11-12 01:19:57254 browser->AddBlankTab(true);
[email protected]15952e462008-11-14 00:29:05255 browser->window()->Show();
initial.commit09911bf2008-07-26 23:55:29256}
257
[email protected]36b6dcb2008-11-12 01:19:57258// static
259void Browser::OpenURLOffTheRecord(Profile* profile, const GURL& url) {
260 Profile* off_the_record_profile = profile->GetOffTheRecordProfile();
261 Browser* browser = BrowserList::FindBrowserWithType(
[email protected]15952e462008-11-14 00:29:05262 off_the_record_profile,
263 BrowserType::TABBED_BROWSER);
264 if (!browser)
265 browser = Browser::Create(off_the_record_profile);
[email protected]36b6dcb2008-11-12 01:19:57266 // TODO(eroman): should we have referrer here?
267 browser->AddTabWithURL(url, GURL(), PageTransition::LINK, true, NULL);
[email protected]15952e462008-11-14 00:29:05268 browser->window()->Show();
[email protected]2baf83d2008-07-30 05:58:17269}
270
[email protected]36b6dcb2008-11-12 01:19:57271// static
[email protected]15952e462008-11-14 00:29:05272void Browser::OpenWebApplication(Profile* profile, WebApp* app) {
[email protected]36b6dcb2008-11-12 01:19:57273 const std::wstring& app_name =
274 app->name().empty() ? ComputeApplicationNameFromURL(app->url()) :
275 app->name();
[email protected]36b6dcb2008-11-12 01:19:57276 RegisterAppPrefs(app_name);
[email protected]15952e462008-11-14 00:29:05277
278 Browser* browser = Browser::CreateForApp(app_name, profile);
[email protected]36b6dcb2008-11-12 01:19:57279 browser->AddWebApplicationTab(profile, app, false);
[email protected]15952e462008-11-14 00:29:05280 browser->window()->Show();
initial.commit09911bf2008-07-26 23:55:29281}
282
[email protected]36b6dcb2008-11-12 01:19:57283///////////////////////////////////////////////////////////////////////////////
284// Browser, Command API:
initial.commit09911bf2008-07-26 23:55:29285
[email protected]36b6dcb2008-11-12 01:19:57286bool Browser::SupportsCommand(int id) const {
287 return controller_.SupportsCommand(id);
initial.commit09911bf2008-07-26 23:55:29288}
289
[email protected]36b6dcb2008-11-12 01:19:57290bool Browser::IsCommandEnabled(int id) const {
291 switch (id) {
[email protected]c7c42332008-11-15 01:10:54292 case IDC_BACK:
293 return GetSelectedTabContents()->controller()->CanGoBack();
294 case IDC_FORWARD:
295 return GetSelectedTabContents()->controller()->CanGoForward();
296 case IDC_STOP:
297 return IsCurrentPageLoading();
[email protected]36b6dcb2008-11-12 01:19:57298 default:
[email protected]c7c42332008-11-15 01:10:54299 break;
[email protected]36b6dcb2008-11-12 01:19:57300 }
[email protected]c7c42332008-11-15 01:10:54301 return controller_.IsCommandEnabled(id);
[email protected]36b6dcb2008-11-12 01:19:57302}
303
304///////////////////////////////////////////////////////////////////////////////
[email protected]36b6dcb2008-11-12 01:19:57305// Browser, State Storage and Retrieval for UI:
306
[email protected]bc9a5152008-11-15 00:32:04307std::wstring Browser::GetWindowPlacementKey() const {
[email protected]36b6dcb2008-11-12 01:19:57308 std::wstring name(prefs::kBrowserWindowPlacement);
309 if (!app_name_.empty()) {
310 name.append(L"_");
311 name.append(app_name_);
312 }
[email protected]bc9a5152008-11-15 00:32:04313 return name;
314}
[email protected]36b6dcb2008-11-12 01:19:57315
[email protected]bc9a5152008-11-15 00:32:04316bool Browser::ShouldSaveWindowPlacement() const {
317 // We don't save window position for popups.
318 return type() != BrowserType::BROWSER;
319}
[email protected]36b6dcb2008-11-12 01:19:57320
[email protected]bc9a5152008-11-15 00:32:04321void Browser::SaveWindowPlacement(const gfx::Rect& bounds, bool maximized) {
322 // Save to the session storage service, used when reloading a past session.
323 // Note that we don't want to be the ones who cause lazy initialization of
324 // the session service. This function gets called during initial window
325 // showing, and we don't want to bring in the session service this early.
[email protected]36b6dcb2008-11-12 01:19:57326 if (profile()->HasSessionService()) {
327 SessionService* session_service = profile()->GetSessionService();
328 if (session_service)
329 session_service->SetWindowBounds(session_id_, bounds, maximized);
330 }
331}
332
[email protected]15952e462008-11-14 00:29:05333gfx::Rect Browser::GetSavedWindowBounds() const {
334 CommandLine parsed_command_line;
335 bool record_mode = parsed_command_line.HasSwitch(switches::kRecordMode);
336 bool playback_mode = parsed_command_line.HasSwitch(switches::kPlaybackMode);
337 if (record_mode || playback_mode) {
338 // In playback/record mode we always fix the size of the browser and
339 // move it to (0,0). The reason for this is two reasons: First we want
340 // resize/moves in the playback to still work, and Second we want
341 // playbacks to work (as much as possible) on machines w/ different
342 // screen sizes.
343 return gfx::Rect(0, 0, 800, 600);
344 }
345
346 gfx::Rect restored_bounds = override_bounds_;
347 bool maximized;
348 WindowSizer::GetBrowserWindowBounds(app_name_, restored_bounds,
349 &restored_bounds, &maximized);
350 return restored_bounds;
351}
352
353// TODO(beng): obtain maximized state some other way so we don't need to go
354// through all this hassle.
355bool Browser::GetSavedMaximizedState() const {
356 if (CommandLine().HasSwitch(switches::kStartMaximized))
357 return true;
358
359 gfx::Rect restored_bounds;
360 bool maximized = override_maximized_;
361 WindowSizer::GetBrowserWindowBounds(app_name_, restored_bounds,
362 &restored_bounds, &maximized);
363 return maximized;
[email protected]36b6dcb2008-11-12 01:19:57364}
365
366SkBitmap Browser::GetCurrentPageIcon() const {
[email protected]c7c42332008-11-15 01:10:54367 return GetSelectedTabContents()->GetFavIcon();
[email protected]36b6dcb2008-11-12 01:19:57368}
369
370std::wstring Browser::GetCurrentPageTitle() const {
371 TabContents* contents = tabstrip_model_.GetSelectedTabContents();
372 std::wstring title;
[email protected]c7c42332008-11-15 01:10:54373
374 // |contents| can be NULL because GetCurrentPageTitle is called by the window
375 // during the window's creation (before tabs have been added).
[email protected]36b6dcb2008-11-12 01:19:57376 if (contents) {
377 title = contents->GetTitle();
378 FormatTitleForDisplay(&title);
379 }
380 if (title.empty())
381 title = l10n_util::GetString(IDS_TAB_UNTITLED_TITLE);
382
383 return l10n_util::GetStringF(IDS_BROWSER_WINDOW_TITLE_FORMAT, title);
384}
385
[email protected]afb73882008-11-14 22:40:44386bool Browser::IsCurrentPageLoading() const {
387 return GetSelectedTabContents()->is_loading();
388}
389
[email protected]36b6dcb2008-11-12 01:19:57390// static
391void Browser::FormatTitleForDisplay(std::wstring* title) {
392 size_t current_index = 0;
393 size_t match_index;
394 while ((match_index = title->find(L'\n', current_index)) !=
395 std::wstring::npos) {
396 title->replace(match_index, 1, L"");
397 current_index = match_index;
398 }
399}
400
401///////////////////////////////////////////////////////////////////////////////
402// Browser, OnBeforeUnload handling:
403
404bool Browser::ShouldCloseWindow() {
405 if (HasCompletedUnloadProcessing()) {
406 return true;
407 }
408 is_attempting_to_close_browser_ = true;
409
410 for (int i = 0; i < tab_count(); ++i) {
411 if (tabstrip_model_.TabHasUnloadListener(i)) {
412 TabContents* tab = GetTabContentsAt(i);
413 tabs_needing_before_unload_fired_.push_back(tab);
414 }
415 }
416
417 if (tabs_needing_before_unload_fired_.empty())
418 return true;
419
420 ProcessPendingTabs();
421 return false;
422}
423
424void Browser::OnWindowClosing() {
425 if (!ShouldCloseWindow())
426 return;
427
428 if (BrowserList::size() == 1)
429 browser_shutdown::OnShutdownStarting(browser_shutdown::WINDOW_CLOSE);
430
431 // Don't use HasSessionService here, we want to force creation of the
432 // session service so that user can restore what was open.
433 SessionService* session_service = profile()->GetSessionService();
434 if (session_service)
435 session_service->WindowClosing(session_id());
436
437 CloseAllTabs();
438}
439
440///////////////////////////////////////////////////////////////////////////////
[email protected]36b6dcb2008-11-12 01:19:57441// Browser, Tab adding/showing functions:
442
443TabContents* Browser::AddTabWithURL(
444 const GURL& url, const GURL& referrer, PageTransition::Type transition,
445 bool foreground, SiteInstance* instance) {
446 if (type_ == BrowserType::APPLICATION && tabstrip_model_.count() == 1) {
447 NOTREACHED() << "Cannot add a tab in a mono tab application.";
448 return NULL;
449 }
450
451 GURL url_to_load = url;
452 if (url_to_load.is_empty())
453 url_to_load = GetHomePage();
454 TabContents* contents =
455 CreateTabContentsForURL(url_to_load, referrer, profile_, transition,
456 false, instance);
457 tabstrip_model_.AddTabContents(contents, -1, transition, foreground);
458 // By default, content believes it is not hidden. When adding contents
459 // in the background, tell it that it's hidden.
460 if (!foreground)
461 contents->WasHidden();
462 return contents;
463}
464
465TabContents* Browser::AddWebApplicationTab(Profile* profile,
466 WebApp* web_app,
467 bool lazy) {
468 DCHECK(web_app);
469
470 // TODO(acw): Do we need an "application launched" transition type?
471 // TODO(creis): Should we reuse the current instance (ie. process) here?
472 TabContents* contents =
473 CreateTabContentsForURL(web_app->url(), GURL(), profile,
474 PageTransition::LINK, lazy, NULL);
475 if (contents->AsWebContents())
476 contents->AsWebContents()->SetWebApp(web_app);
477
478 if (lazy) {
479 contents->controller()->LoadURLLazily(
480 web_app->url(), GURL(), PageTransition::LINK, web_app->name(), NULL);
481 }
482 tabstrip_model_.AddTabContents(contents, -1, PageTransition::LINK, !lazy);
483 return contents;
484}
485
486TabContents* Browser::AddTabWithNavigationController(
487 NavigationController* ctrl, PageTransition::Type type) {
488 TabContents* tc = ctrl->active_contents();
489 tabstrip_model_.AddTabContents(tc, -1, type, true);
490 return tc;
491}
492
493NavigationController* Browser::AddRestoredTab(
494 const std::vector<TabNavigation>& navigations,
495 int tab_index,
496 int selected_navigation,
497 bool select) {
498 NavigationController* restored_controller =
499 BuildRestoredNavigationController(navigations, selected_navigation);
500
501 tabstrip_model_.InsertTabContentsAt(
502 tab_index,
503 restored_controller->active_contents(),
504 select, false);
505 if (profile_->HasSessionService()) {
506 SessionService* session_service = profile_->GetSessionService();
507 if (session_service)
508 session_service->TabRestored(restored_controller);
509 }
510 return restored_controller;
511}
512
513void Browser::ReplaceRestoredTab(
514 const std::vector<TabNavigation>& navigations,
515 int selected_navigation) {
516 NavigationController* restored_controller =
517 BuildRestoredNavigationController(navigations, selected_navigation);
518
519 tabstrip_model_.ReplaceNavigationControllerAt(
520 tabstrip_model_.selected_index(),
521 restored_controller);
522}
523
524void Browser::ShowNativeUITab(const GURL& url) {
525 int i, c;
526 TabContents* tc;
527 for (i = 0, c = tabstrip_model_.count(); i < c; ++i) {
528 tc = tabstrip_model_.GetTabContentsAt(i);
529 if (tc->type() == TAB_CONTENTS_NATIVE_UI &&
530 tc->GetURL() == url) {
531 tabstrip_model_.SelectTabContentsAt(i, false);
532 return;
533 }
534 }
535
536 TabContents* contents = CreateTabContentsForURL(url, GURL(), profile_,
537 PageTransition::LINK, false,
538 NULL);
539 AddNewContents(NULL, contents, NEW_FOREGROUND_TAB, gfx::Rect(), true);
540}
541
542///////////////////////////////////////////////////////////////////////////////
543// Browser, Assorted browser commands:
544
545void Browser::GoBack() {
[email protected]fbd77592008-11-12 20:50:27546 UserMetrics::RecordAction(L"Back", profile_);
547
[email protected]36b6dcb2008-11-12 01:19:57548 // If we are showing an interstitial, just hide it.
549 TabContents* current_tab = GetSelectedTabContents();
[email protected]c7c42332008-11-15 01:10:54550 WebContents* web_contents = current_tab->AsWebContents();
551 if (web_contents && web_contents->showing_interstitial_page()) {
552 // Pressing back on an interstitial page means "don't proceed".
553 web_contents->interstitial_page()->DontProceed();
554 return;
[email protected]36b6dcb2008-11-12 01:19:57555 }
[email protected]c7c42332008-11-15 01:10:54556 if (current_tab->controller()->CanGoBack())
557 current_tab->controller()->GoBack();
[email protected]36b6dcb2008-11-12 01:19:57558}
559
560void Browser::GoForward() {
[email protected]fbd77592008-11-12 20:50:27561 UserMetrics::RecordAction(L"Forward", profile_);
[email protected]c7c42332008-11-15 01:10:54562 if (GetSelectedTabContents()->controller()->CanGoForward())
563 GetSelectedTabContents()->controller()->GoForward();
[email protected]36b6dcb2008-11-12 01:19:57564}
565
566void Browser::Reload() {
[email protected]fbd77592008-11-12 20:50:27567 UserMetrics::RecordAction(L"Reload", profile_);
568
[email protected]36b6dcb2008-11-12 01:19:57569 // If we are showing an interstitial, treat this as an OpenURL.
570 TabContents* current_tab = GetSelectedTabContents();
571 if (current_tab) {
572 WebContents* web_contents = current_tab->AsWebContents();
573 if (web_contents && web_contents->showing_interstitial_page()) {
574 NavigationEntry* entry = current_tab->controller()->GetActiveEntry();
575 DCHECK(entry); // Should exist if interstitial is showing.
576 OpenURL(entry->url(), GURL(), CURRENT_TAB, PageTransition::RELOAD);
577 return;
578 }
579 }
580
581 if (current_tab) {
582 // As this is caused by a user action, give the focus to the page.
583 current_tab->Focus();
584 current_tab->controller()->Reload(true);
585 }
586}
587
588void Browser::Stop() {
[email protected]fbd77592008-11-12 20:50:27589 UserMetrics::RecordAction(L"Stop", profile_);
590 GetSelectedTabContents()->AsWebContents()->Stop();
[email protected]36b6dcb2008-11-12 01:19:57591}
592
593void Browser::Home() {
[email protected]fbd77592008-11-12 20:50:27594 UserMetrics::RecordAction(L"Home", profile_);
[email protected]36b6dcb2008-11-12 01:19:57595 GURL homepage_url = GetHomePage();
596 GetSelectedTabContents()->controller()->LoadURL(
597 homepage_url, GURL(), PageTransition::AUTO_BOOKMARK);
598}
599
[email protected]fbd77592008-11-12 20:50:27600void Browser::Go() {
601 UserMetrics::RecordAction(L"Go", profile_);
602 LocationBarView* lbv = GetLocationBarView();
603 if (lbv)
604 lbv->location_entry()->model()->AcceptInput(CURRENT_TAB, false);
605}
606
607void Browser::OpenCurrentURL() {
608 UserMetrics::RecordAction(L"LoadURL", profile_);
609 LocationBarView* lbv = GetLocationBarView();
610 if (lbv) {
611 OpenURL(GURL(lbv->location_input()), GURL(), lbv->disposition(),
612 lbv->transition());
613 } else {
614 OpenURL(GURL(), GURL(), CURRENT_TAB, PageTransition::TYPED);
615 }
616}
617
618void Browser::NewTab() {
619 UserMetrics::RecordAction(L"NewTab", profile_);
620 if (type() == BrowserType::TABBED_BROWSER) {
621 AddBlankTab(true);
622 } else {
623 Browser* b = GetOrCreateTabbedBrowser();
[email protected]fbd77592008-11-12 20:50:27624 b->AddBlankTab(true);
[email protected]15952e462008-11-14 00:29:05625 b->window()->Show();
[email protected]fbd77592008-11-12 20:50:27626 }
627}
628
629void Browser::CloseTab() {
630 UserMetrics::RecordAction(L"CloseTab_Accelerator", profile_);
631 tabstrip_model_.CloseTabContentsAt(tabstrip_model_.selected_index());
632}
633
634void Browser::CloseApp() {
635 UserMetrics::RecordAction(L"CloseWebApp", profile_);
636 tabstrip_model_.CloseTabContentsAt(tabstrip_model_.selected_index());
637}
638
639void Browser::NewWindow() {
640 UserMetrics::RecordAction(L"NewWindow", profile_);
[email protected]15952e462008-11-14 00:29:05641 Browser::OpenEmptyWindow(profile_->GetOriginalProfile());
[email protected]fbd77592008-11-12 20:50:27642}
643
644void Browser::NewIncognitoWindow() {
645 UserMetrics::RecordAction(L"NewIncognitoWindow", profile_);
[email protected]15952e462008-11-14 00:29:05646 Browser::OpenEmptyWindow(profile_->GetOffTheRecordProfile());
[email protected]fbd77592008-11-12 20:50:27647}
648
649void Browser::CloseWindow() {
650 UserMetrics::RecordAction(L"CloseWindow", profile_);
651 window_->Close();
652}
653
654void Browser::SelectNextTab() {
655 UserMetrics::RecordAction(L"SelectNextTab", profile_);
656 tabstrip_model_.SelectNextTab();
657}
658
659void Browser::SelectPreviousTab() {
660 UserMetrics::RecordAction(L"SelectPrevTab", profile_);
661 tabstrip_model_.SelectPreviousTab();
662}
663
664void Browser::SelectNumberedTab(int index) {
665 if (index < tab_count()) {
666 UserMetrics::RecordAction(L"SelectNumberedTab", profile_);
667 tabstrip_model_.SelectTabContentsAt(index, true);
668 }
669}
670
671void Browser::SelectLastTab() {
672 UserMetrics::RecordAction(L"SelectLastTab", profile_);
673 tabstrip_model_.SelectLastTab();
674}
675
676void Browser::DuplicateTab() {
677 UserMetrics::RecordAction(L"Duplicate", profile_);
678 DuplicateContentsAt(selected_index());
679}
680
681void Browser::RestoreTab() {
682 UserMetrics::RecordAction(L"RestoreTab", profile_);
683 TabRestoreService* service = profile_->GetTabRestoreService();
684 if (!service)
685 return;
686
687 const TabRestoreService::Tabs& tabs = service->tabs();
688 if (tabs.empty() || tabs.front().from_last_session)
689 return;
690
691 const TabRestoreService::HistoricalTab& tab = tabs.front();
692 AddRestoredTab(tab.navigations, tab_count(), tab.current_navigation_index,
693 true);
694 service->RemoveHistoricalTabById(tab.id);
695}
696
697void Browser::ConvertPopupToTabbedBrowser() {
698 UserMetrics::RecordAction(L"ShowAsTab", profile_);
699
700 if (type() != BrowserType::BROWSER) {
701 NOTREACHED();
702 return;
703 }
704
705 int tab_strip_index = tabstrip_model_.selected_index();
706 TabContents* contents = tabstrip_model_.DetachTabContentsAt(tab_strip_index);
[email protected]15952e462008-11-14 00:29:05707 Browser* browser = Browser::Create(profile_);
708 browser->tabstrip_model()->AppendTabContents(contents, true);
709 browser->window()->Show();
[email protected]fbd77592008-11-12 20:50:27710}
711
712void Browser::Exit() {
713 UserMetrics::RecordAction(L"Exit", profile_);
714 BrowserList::CloseAllBrowsers(true);
715}
716
717// TODO(devint): http://b/issue?id=1117225 Cut, Copy, and Paste are always
718// enabled in the page menu regardless of whether the command will do
719// anything. When someone selects the menu item, we just act as if they hit
720// the keyboard shortcut for the command by sending the associated key press
721// to windows. The real fix to this bug is to disable the commands when they
722// won't do anything. We'll need something like an overall clipboard command
723// manager to do that.
724
725void Browser::Cut() {
726 UserMetrics::RecordAction(L"Cut", profile_);
727 ui_controls::SendKeyPress(L'X', true, false, false);
728}
729
730void Browser::Copy() {
731 UserMetrics::RecordAction(L"Copy", profile_);
732 ui_controls::SendKeyPress(L'C', true, false, false);
733}
734
735void Browser::CopyCurrentPageURL() {
736 UserMetrics::RecordAction(L"CopyURLToClipBoard", profile_);
[email protected]c7c42332008-11-15 01:10:54737 std::string url = GetSelectedTabContents()->GetURL().spec();
[email protected]fbd77592008-11-12 20:50:27738
739 if (!::OpenClipboard(NULL)) {
740 NOTREACHED();
741 return;
742 }
743
744 if (::EmptyClipboard()) {
745 HGLOBAL text = ::GlobalAlloc(GMEM_MOVEABLE, url.size() + 1);
746 LPSTR ptr = static_cast<LPSTR>(::GlobalLock(text));
747 memcpy(ptr, url.c_str(), url.size());
748 ptr[url.size()] = '\0';
749 ::GlobalUnlock(text);
750
751 ::SetClipboardData(CF_TEXT, text);
752 }
753
754 if (!::CloseClipboard()) {
755 NOTREACHED();
756 }
757}
758
759void Browser::Paste() {
760 UserMetrics::RecordAction(L"Paste", profile_);
761 ui_controls::SendKeyPress(L'V', true, false, false);
762}
763
764void Browser::Find() {
765 UserMetrics::RecordAction(L"Find", profile_);
766 GetSelectedTabContents()->AsWebContents()->view()->FindInPage(*this, false,
767 false);
768}
769
770void Browser::FindNext() {
771 UserMetrics::RecordAction(L"FindNext", profile_);
772 AdvanceFindSelection(true);
773}
774
775void Browser::FindPrevious() {
776 UserMetrics::RecordAction(L"FindPrevious", profile_);
777 AdvanceFindSelection(false);
778}
779
780void Browser::ZoomIn() {
781 UserMetrics::RecordAction(L"ZoomPlus", profile_);
782 GetSelectedTabContents()->AsWebContents()->render_view_host()->Zoom(
783 PageZoom::LARGER);
784}
785
786void Browser::ZoomOut() {
787 UserMetrics::RecordAction(L"ZoomMinus", profile_);
788 GetSelectedTabContents()->AsWebContents()->render_view_host()->Zoom(
789 PageZoom::SMALLER);
790}
791
792void Browser::ZoomReset() {
793 UserMetrics::RecordAction(L"ZoomNormal", profile_);
794 GetSelectedTabContents()->AsWebContents()->render_view_host()->Zoom(
795 PageZoom::STANDARD);
796}
797
[email protected]36b6dcb2008-11-12 01:19:57798void Browser::FocusLocationBar() {
[email protected]fbd77592008-11-12 20:50:27799 UserMetrics::RecordAction(L"FocusLocation", profile_);
800 LocationBarView* lbv = GetLocationBarView();
801 if (lbv) {
802 AutocompleteEditView* aev = lbv->location_entry();
803 aev->SetFocus();
804 aev->SelectAll(true);
805 }
806}
807
808void Browser::FocusSearch() {
809 // TODO(beng): replace this with FocusLocationBar
810 UserMetrics::RecordAction(L"FocusSearch", profile_);
811 LocationBarView* lbv = GetLocationBarView();
812 if (lbv) {
813 AutocompleteEditView* aev = lbv->location_entry();
814 aev->SetUserText(L"?");
815 aev->SetFocus();
816 }
817}
818
819void Browser::FocusToolbar() {
820 UserMetrics::RecordAction(L"FocusToolbar", profile_);
821 window_->FocusToolbar();
[email protected]36b6dcb2008-11-12 01:19:57822}
823
824void Browser::BookmarkCurrentPage() {
[email protected]fbd77592008-11-12 20:50:27825 UserMetrics::RecordAction(L"Star", profile_);
826
[email protected]36b6dcb2008-11-12 01:19:57827 TabContents* tab = GetSelectedTabContents();
[email protected]c7c42332008-11-15 01:10:54828 if (!tab->AsWebContents())
[email protected]36b6dcb2008-11-12 01:19:57829 return;
830
831 WebContents* rvh = tab->AsWebContents();
832 BookmarkModel* model = tab->profile()->GetBookmarkModel();
833 if (!model || !model->IsLoaded())
834 return; // Ignore requests until bookmarks are loaded.
835
836 NavigationEntry* entry = rvh->controller()->GetActiveEntry();
837 if (!entry)
838 return; // Can't star if there is no URL.
839 const GURL& url = entry->display_url();
840 if (url.is_empty() || !url.is_valid())
841 return;
842
843 if (window_->GetStarButton()) {
844 if (!window_->GetStarButton()->is_bubble_showing()) {
845 const bool newly_bookmarked = !model->IsBookmarked(url);
846 if (newly_bookmarked) {
847 model->SetURLStarred(url, entry->title(), true);
848 if (!model->IsBookmarked(url)) {
849 // Starring failed. This shouldn't happen.
850 NOTREACHED();
851 return;
852 }
853 }
854 window_->GetStarButton()->ShowStarBubble(url, newly_bookmarked);
855 }
856 } else if (model->IsBookmarked(url)) {
857 // If we can't find the star button and the user wanted to unstar it,
858 // go ahead and unstar it without showing the bubble.
859 model->SetURLStarred(url, std::wstring(), false);
860 }
861}
862
[email protected]fbd77592008-11-12 20:50:27863void Browser::ViewSource() {
864 UserMetrics::RecordAction(L"ViewSource", profile_);
[email protected]36b6dcb2008-11-12 01:19:57865
[email protected]36b6dcb2008-11-12 01:19:57866 TabContents* current_tab = GetSelectedTabContents();
[email protected]fbd77592008-11-12 20:50:27867 NavigationEntry* entry = current_tab->controller()->GetLastCommittedEntry();
868 if (entry) {
869 GURL url("view-source:" + entry->url().spec());
870 AddTabWithURL(url, GURL(), PageTransition::LINK, true, NULL);
[email protected]36b6dcb2008-11-12 01:19:57871 }
872}
initial.commit09911bf2008-07-26 23:55:29873
[email protected]fbd77592008-11-12 20:50:27874void Browser::ClosePopups() {
875 UserMetrics::RecordAction(L"CloseAllSuppressedPopups", profile_);
876 GetSelectedTabContents()->CloseAllSuppressedPopups();
877}
initial.commit09911bf2008-07-26 23:55:29878
[email protected]fbd77592008-11-12 20:50:27879void Browser::Print() {
880 UserMetrics::RecordAction(L"PrintPreview", profile_);
881 GetSelectedTabContents()->AsWebContents()->PrintPreview();
882}
883
884void Browser::SavePage() {
885 UserMetrics::RecordAction(L"SavePage", profile_);
886 GetSelectedTabContents()->AsWebContents()->OnSavePage();
887}
888
889void Browser::ToggleEncodingAutoDetect() {
890 UserMetrics::RecordAction(L"AutoDetectChange", profile_);
891 encoding_auto_detect_.SetValue(!encoding_auto_detect_.GetValue());
892 // Reload the page so we can try to auto-detect the charset.
893 Reload();
894}
895
896void Browser::OverrideEncoding(int encoding_id) {
897 UserMetrics::RecordAction(L"OverrideEncoding", profile_);
898 const std::wstring selected_encoding =
899 CharacterEncoding::GetCanonicalEncodingNameByCommandId(encoding_id);
900 TabContents* current_tab = GetSelectedTabContents();
[email protected]c7c42332008-11-15 01:10:54901 if (!selected_encoding.empty() && current_tab->AsWebContents())
[email protected]fbd77592008-11-12 20:50:27902 current_tab->AsWebContents()->override_encoding(selected_encoding);
903 // Update the list of recently selected encodings.
904 std::wstring new_selected_encoding_list;
905 if (CharacterEncoding::UpdateRecentlySelectdEncoding(
906 profile_->GetPrefs()->GetString(prefs::kRecentlySelectedEncoding),
907 encoding_id,
908 &new_selected_encoding_list)) {
909 profile_->GetPrefs()->SetString(prefs::kRecentlySelectedEncoding,
910 new_selected_encoding_list);
911 }
[email protected]36b6dcb2008-11-12 01:19:57912}
913
914void Browser::OpenKeywordEditor() {
[email protected]fbd77592008-11-12 20:50:27915 UserMetrics::RecordAction(L"EditSearchEngines", profile_);
[email protected]2d46c842008-11-14 19:24:31916 window_->ShowSearchEnginesDialog();
[email protected]36b6dcb2008-11-12 01:19:57917}
918
919void Browser::OpenClearBrowsingDataDialog() {
[email protected]fbd77592008-11-12 20:50:27920 UserMetrics::RecordAction(L"ClearBrowsingData_ShowDlg", profile_);
[email protected]2d46c842008-11-14 19:24:31921 window_->ShowClearBrowsingDataDialog();
[email protected]36b6dcb2008-11-12 01:19:57922}
923
924void Browser::OpenImportSettingsDialog() {
[email protected]fbd77592008-11-12 20:50:27925 UserMetrics::RecordAction(L"Import_ShowDlg", profile_);
[email protected]2d46c842008-11-14 19:24:31926 window_->ShowImportDialog();
[email protected]36b6dcb2008-11-12 01:19:57927}
928
929void Browser::OpenBugReportDialog() {
[email protected]fbd77592008-11-12 20:50:27930 UserMetrics::RecordAction(L"ReportBug", profile_);
[email protected]2d46c842008-11-14 19:24:31931 window_->ShowReportBugDialog();
[email protected]36b6dcb2008-11-12 01:19:57932}
933
[email protected]fbd77592008-11-12 20:50:27934void Browser::OpenDebuggerWindow() {
935#ifndef CHROME_DEBUGGER_DISABLED
936 UserMetrics::RecordAction(L"Debugger", profile_);
937 TabContents* current_tab = GetSelectedTabContents();
[email protected]fbd77592008-11-12 20:50:27938 if (current_tab->AsWebContents()) {
939 // Only one debugger instance can exist at a time right now.
940 // TODO(erikkay): need an alert, dialog, something
941 // or better yet, fix the one instance limitation
942 if (!DebuggerWindow::DoesDebuggerExist()) {
943 debugger_window_ = new DebuggerWindow();
944 }
945 debugger_window_->Show(current_tab);
[email protected]36b6dcb2008-11-12 01:19:57946 }
[email protected]fbd77592008-11-12 20:50:27947#endif
948}
[email protected]36b6dcb2008-11-12 01:19:57949
[email protected]fbd77592008-11-12 20:50:27950void Browser::OpenJavaScriptConsole() {
951 UserMetrics::RecordAction(L"ShowJSConsole", profile_);
952 GetSelectedTabContents()->AsWebContents()->render_view_host()->
953 ShowJavaScriptConsole();
954}
955
956void Browser::OpenCreateShortcutsDialog() {
957 UserMetrics::RecordAction(L"CreateShortcut", profile_);
958 GetSelectedTabContents()->AsWebContents()->CreateShortcut();
959}
960
961void Browser::OpenPasswordManager() {
[email protected]2d46c842008-11-14 19:24:31962 window_->ShowPasswordManager();
[email protected]fbd77592008-11-12 20:50:27963}
964
965void Browser::OpenAboutChromeDialog() {
966 UserMetrics::RecordAction(L"AboutChrome", profile_);
[email protected]2d46c842008-11-14 19:24:31967 window_->ShowAboutChromeDialog();
[email protected]fbd77592008-11-12 20:50:27968}
969
970void Browser::OpenFile() {
971 UserMetrics::RecordAction(L"OpenFile", profile_);
972 if (!select_file_dialog_.get())
973 select_file_dialog_ = SelectFileDialog::Create(this);
[email protected]2d46c842008-11-14 19:24:31974
975 // TODO(beng): figure out how to juggle this.
976 HWND parent_hwnd = reinterpret_cast<HWND>(window_->GetNativeHandle());
[email protected]fbd77592008-11-12 20:50:27977 select_file_dialog_->SelectFile(SelectFileDialog::SELECT_OPEN_FILE,
[email protected]39a248b02008-11-12 22:10:20978 std::wstring(), std::wstring(),
979 std::wstring(), std::wstring(),
[email protected]2d46c842008-11-14 19:24:31980 parent_hwnd, NULL);
[email protected]fbd77592008-11-12 20:50:27981}
982
983void Browser::OpenTaskManager() {
984 UserMetrics::RecordAction(L"TaskManager", profile_);
985 TaskManager::Open();
986}
987
988void Browser::OpenOptionsDialog() {
989 UserMetrics::RecordAction(L"ShowOptions", profile_);
990 ShowOptionsWindow(OPTIONS_PAGE_DEFAULT, OPTIONS_GROUP_NONE, profile_);
991}
992
993void Browser::OpenHelpTab() {
994 GURL help_url(l10n_util::GetString(IDS_HELP_CONTENT_URL));
995 AddTabWithURL(help_url, GURL(), PageTransition::AUTO_BOOKMARK, true,
996 NULL);
997}
998
999void Browser::ShowHistoryTab() {
1000 UserMetrics::RecordAction(L"ShowHistory", profile_);
1001 ShowNativeUITab(HistoryTabUI::GetURL());
1002}
1003
1004void Browser::ShowDownloadsTab() {
1005 UserMetrics::RecordAction(L"ShowDownloads", profile_);
1006 ShowNativeUITab(DownloadTabUI::GetURL());
1007}
1008
1009void Browser::OpenBookmarksManager() {
1010 UserMetrics::RecordAction(L"ShowBookmarkManager", profile_);
[email protected]2d46c842008-11-14 19:24:311011 window_->ShowBookmarkManager();
[email protected]fbd77592008-11-12 20:50:271012}
1013
1014void Browser::ToggleBookmarksBar() {
1015 UserMetrics::RecordAction(L"ShowBookmarksBar", profile_);
[email protected]2d46c842008-11-14 19:24:311016 window_->ToggleBookmarkBar();
[email protected]36b6dcb2008-11-12 01:19:571017}
1018
1019///////////////////////////////////////////////////////////////////////////////
1020
1021// static
1022void Browser::RegisterPrefs(PrefService* prefs) {
1023 prefs->RegisterDictionaryPref(prefs::kBrowserWindowPlacement);
1024 prefs->RegisterIntegerPref(prefs::kOptionsWindowLastTabIndex, 0);
1025}
1026
1027// static
1028void Browser::RegisterUserPrefs(PrefService* prefs) {
1029 prefs->RegisterStringPref(prefs::kHomePage, L"chrome-internal:");
1030 prefs->RegisterBooleanPref(prefs::kHomePageIsNewTabPage, true);
1031 prefs->RegisterIntegerPref(prefs::kCookieBehavior,
1032 net::CookiePolicy::ALLOW_ALL_COOKIES);
1033 prefs->RegisterBooleanPref(prefs::kShowHomeButton, false);
1034 prefs->RegisterStringPref(prefs::kRecentlySelectedEncoding, L"");
1035 // TODO(peterson): bug #3870 move this to the AutofillManager once it is
1036 // checked-in.
1037 prefs->RegisterBooleanPref(prefs::kFormAutofillEnabled, true);
1038 prefs->RegisterBooleanPref(prefs::kDeleteBrowsingHistory, true);
1039 prefs->RegisterBooleanPref(prefs::kDeleteDownloadHistory, true);
1040 prefs->RegisterBooleanPref(prefs::kDeleteCache, true);
1041 prefs->RegisterBooleanPref(prefs::kDeleteCookies, true);
1042 prefs->RegisterBooleanPref(prefs::kDeletePasswords, false);
1043 prefs->RegisterBooleanPref(prefs::kDeleteFormData, true);
1044 prefs->RegisterIntegerPref(prefs::kDeleteTimePeriod, 0);
1045}
1046
1047// static
1048Browser* Browser::GetBrowserForController(
1049 const NavigationController* controller, int* index_result) {
1050 BrowserList::const_iterator it;
1051 for (it = BrowserList::begin(); it != BrowserList::end(); ++it) {
1052 int index = (*it)->tabstrip_model_.GetIndexOfController(controller);
1053 if (index != TabStripModel::kNoTab) {
1054 if (index_result)
1055 *index_result = index;
1056 return *it;
1057 }
1058 }
1059
1060 return NULL;
1061}
1062
1063///////////////////////////////////////////////////////////////////////////////
1064// Browser, CommandHandler implementation:
1065
1066void Browser::ExecuteCommand(int id) {
[email protected]c7c42332008-11-15 01:10:541067 DCHECK(IsCommandEnabled(id)) << "Invalid or disabled command";
[email protected]36b6dcb2008-11-12 01:19:571068
[email protected]fbd77592008-11-12 20:50:271069 // The order of commands in this switch statement must match the function
1070 // declaration order in browser.h!
[email protected]36b6dcb2008-11-12 01:19:571071 switch (id) {
[email protected]fbd77592008-11-12 20:50:271072 case IDC_BACK: GoBack(); break;
1073 case IDC_FORWARD: GoForward(); break;
1074 case IDC_RELOAD: Reload(); break;
1075 case IDC_STOP: Stop(); break;
1076 case IDC_HOME: Home(); break;
1077 case IDC_GO: Go(); break;
1078 case IDC_OPENURL: OpenCurrentURL(); break;
[email protected]36b6dcb2008-11-12 01:19:571079
[email protected]fbd77592008-11-12 20:50:271080 case IDC_NEWTAB: NewTab(); break;
1081 case IDC_CLOSETAB: CloseTab(); break;
1082 case IDC_CLOSE_WEB_APP: CloseApp(); break;
1083 case IDC_NEWWINDOW: NewWindow(); break;
1084 case IDC_GOOFFTHERECORD: NewIncognitoWindow(); break;
1085 case IDC_CLOSEWINDOW: CloseWindow(); break;
1086 case IDC_SELECT_NEXT_TAB: SelectNextTab(); break;
1087 case IDC_SELECT_PREV_TAB: SelectPreviousTab(); break;
[email protected]36b6dcb2008-11-12 01:19:571088 case IDC_SELECT_TAB_0:
1089 case IDC_SELECT_TAB_1:
1090 case IDC_SELECT_TAB_2:
1091 case IDC_SELECT_TAB_3:
1092 case IDC_SELECT_TAB_4:
1093 case IDC_SELECT_TAB_5:
1094 case IDC_SELECT_TAB_6:
[email protected]fbd77592008-11-12 20:50:271095 case IDC_SELECT_TAB_7: SelectNumberedTab(id - IDC_SELECT_TAB_0); break;
1096 case IDC_SELECT_LAST_TAB: SelectLastTab(); break;
1097 case IDC_DUPLICATE: DuplicateTab(); break;
1098 case IDC_RESTORE_TAB: RestoreTab(); break;
1099 case IDC_SHOW_AS_TAB: ConvertPopupToTabbedBrowser(); break;
1100 case IDC_EXIT: Exit(); break;
[email protected]36b6dcb2008-11-12 01:19:571101
[email protected]fbd77592008-11-12 20:50:271102 case IDC_CUT: Cut(); break;
1103 case IDC_COPY: Copy(); break;
1104 case IDC_COPY_URL: CopyCurrentPageURL(); break;
1105 case IDC_PASTE: Paste(); break;
[email protected]36b6dcb2008-11-12 01:19:571106
[email protected]fbd77592008-11-12 20:50:271107 case IDC_FIND: Find(); break;
1108 case IDC_FIND_NEXT: FindNext(); break;
1109 case IDC_FIND_PREVIOUS: FindPrevious(); break;
[email protected]36b6dcb2008-11-12 01:19:571110
[email protected]fbd77592008-11-12 20:50:271111 case IDC_ZOOM_PLUS: ZoomIn(); break;
1112 case IDC_ZOOM_MINUS: ZoomOut(); break;
1113 case IDC_ZOOM_NORMAL: ZoomReset(); break;
[email protected]36b6dcb2008-11-12 01:19:571114
[email protected]fbd77592008-11-12 20:50:271115 case IDC_FOCUS_LOCATION: FocusLocationBar(); break;
1116 case IDC_FOCUS_SEARCH: FocusSearch(); break;
1117 case IDC_FOCUS_TOOLBAR: FocusToolbar(); break;
[email protected]36b6dcb2008-11-12 01:19:571118
[email protected]fbd77592008-11-12 20:50:271119 case IDC_STAR: BookmarkCurrentPage(); break;
1120 case IDC_VIEWSOURCE: ViewSource(); break;
1121 case IDC_CLOSEPOPUPS: ClosePopups(); break;
1122 case IDC_PRINT: Print(); break;
1123 case IDC_SAVEPAGE: SavePage(); break;
1124 case IDC_ENCODING_AUTO_DETECT: ToggleEncodingAutoDetect(); break;
[email protected]36b6dcb2008-11-12 01:19:571125 case IDC_ENCODING_UTF8:
1126 case IDC_ENCODING_UTF16LE:
1127 case IDC_ENCODING_ISO88591:
1128 case IDC_ENCODING_WINDOWS1252:
1129 case IDC_ENCODING_GB2312:
1130 case IDC_ENCODING_GB18030:
1131 case IDC_ENCODING_BIG5HKSCS:
1132 case IDC_ENCODING_BIG5:
1133 case IDC_ENCODING_KOREAN:
1134 case IDC_ENCODING_SHIFTJIS:
1135 case IDC_ENCODING_ISO2022JP:
1136 case IDC_ENCODING_EUCJP:
1137 case IDC_ENCODING_THAI:
1138 case IDC_ENCODING_ISO885915:
1139 case IDC_ENCODING_MACINTOSH:
1140 case IDC_ENCODING_ISO88592:
1141 case IDC_ENCODING_WINDOWS1250:
1142 case IDC_ENCODING_ISO88595:
1143 case IDC_ENCODING_WINDOWS1251:
1144 case IDC_ENCODING_KOI8R:
1145 case IDC_ENCODING_KOI8U:
1146 case IDC_ENCODING_ISO88597:
1147 case IDC_ENCODING_WINDOWS1253:
1148 case IDC_ENCODING_ISO88594:
1149 case IDC_ENCODING_ISO885913:
1150 case IDC_ENCODING_WINDOWS1257:
1151 case IDC_ENCODING_ISO88593:
1152 case IDC_ENCODING_ISO885910:
1153 case IDC_ENCODING_ISO885914:
1154 case IDC_ENCODING_ISO885916:
1155 case IDC_ENCODING_ISO88599:
1156 case IDC_ENCODING_WINDOWS1254:
1157 case IDC_ENCODING_ISO88596:
1158 case IDC_ENCODING_WINDOWS1256:
1159 case IDC_ENCODING_ISO88598:
1160 case IDC_ENCODING_WINDOWS1255:
[email protected]fbd77592008-11-12 20:50:271161 case IDC_ENCODING_WINDOWS1258: OverrideEncoding(id); break;
[email protected]36b6dcb2008-11-12 01:19:571162
[email protected]fbd77592008-11-12 20:50:271163 case IDC_EDIT_SEARCH_ENGINES: OpenKeywordEditor(); break;
1164 case IDC_CLEAR_BROWSING_DATA: OpenClearBrowsingDataDialog(); break;
1165 case IDC_IMPORT_SETTINGS: OpenImportSettingsDialog(); break;
1166 case IDS_COMMANDS_REPORTBUG: OpenBugReportDialog(); break;
1167 case IDC_DEBUGGER: OpenDebuggerWindow(); break;
1168 case IDC_SHOW_JS_CONSOLE: OpenJavaScriptConsole(); break;
1169 case IDC_CREATE_SHORTCUT: OpenCreateShortcutsDialog(); break;
1170 case IDC_VIEW_PASSWORDS: OpenPasswordManager(); break;
1171 case IDC_ABOUT: OpenAboutChromeDialog(); break;
1172 case IDC_OPENFILE: OpenFile(); break;
1173 case IDC_TASKMANAGER: OpenTaskManager(); break;
1174 case IDC_OPTIONS: OpenOptionsDialog(); break;
1175 case IDC_HELPMENU: OpenHelpTab(); break;
1176 case IDC_SHOW_HISTORY: ShowHistoryTab(); break;
1177 case IDC_SHOW_DOWNLOADS: ShowDownloadsTab(); break;
1178 case IDC_SHOW_BOOKMARK_MANAGER: OpenBookmarksManager(); break;
1179 case IDC_SHOW_BOOKMARKS_BAR: ToggleBookmarksBar(); break;
[email protected]36b6dcb2008-11-12 01:19:571180
1181 default:
[email protected]fbd77592008-11-12 20:50:271182 LOG(WARNING) << "Received Unimplemented Command: " << id;
1183 break;
[email protected]36b6dcb2008-11-12 01:19:571184 }
1185}
1186
1187///////////////////////////////////////////////////////////////////////////////
1188// Browser, TabStripModelDelegate implementation:
1189
[email protected]15952e462008-11-14 00:29:051190GURL Browser::GetBlankTabURL() const {
1191 return NewTabUIURL();
1192}
1193
[email protected]36b6dcb2008-11-12 01:19:571194void Browser::CreateNewStripWithContents(TabContents* detached_contents,
[email protected]2d46c842008-11-14 19:24:311195 const gfx::Rect& window_bounds) {
[email protected]36b6dcb2008-11-12 01:19:571196 DCHECK(type_ == BrowserType::TABBED_BROWSER);
[email protected]2d46c842008-11-14 19:24:311197
[email protected]36b6dcb2008-11-12 01:19:571198 // Create an empty new browser window the same size as the old one.
[email protected]15952e462008-11-14 00:29:051199 Browser* browser = new Browser(BrowserType::TABBED_BROWSER, profile_);
[email protected]2d46c842008-11-14 19:24:311200 browser->set_override_bounds(window_bounds);
[email protected]15952e462008-11-14 00:29:051201 browser->CreateBrowserWindow();
1202 browser->tabstrip_model()->AppendTabContents(detached_contents, true);
1203 browser->window()->Show();
[email protected]36b6dcb2008-11-12 01:19:571204
1205 // When we detach a tab we need to make sure any associated Find window moves
[email protected]2d46c842008-11-14 19:24:311206 // along with it to its new home (basically we just make new_window the
1207 // parent of the Find window).
[email protected]36b6dcb2008-11-12 01:19:571208 // TODO(brettw) this could probably be improved, see
1209 // WebContentsView::ReparentFindWindow for more.
1210 if (detached_contents->AsWebContents())
[email protected]15952e462008-11-14 00:29:051211 detached_contents->AsWebContents()->view()->ReparentFindWindow(browser);
[email protected]36b6dcb2008-11-12 01:19:571212}
1213
1214int Browser::GetDragActions() const {
1215 int result = 0;
1216 if (BrowserList::GetBrowserCountForType(profile_,
1217 BrowserType::TABBED_BROWSER) > 1 ||
1218 tab_count() > 1)
1219 result |= TAB_TEAROFF_ACTION;
1220 if (tab_count() > 1)
1221 result |= TAB_MOVE_ACTION;
1222 return result;
1223}
1224
1225TabContents* Browser::CreateTabContentsForURL(
1226 const GURL& url, const GURL& referrer, Profile* profile,
1227 PageTransition::Type transition, bool defer_load,
1228 SiteInstance* instance) const {
1229 // Create an appropriate tab contents.
1230 GURL real_url = url;
1231 TabContentsType type = TabContents::TypeForURL(&real_url);
1232 DCHECK(type != TAB_CONTENTS_UNKNOWN_TYPE);
1233
[email protected]2d46c842008-11-14 19:24:311234 HWND parent_hwnd = reinterpret_cast<HWND>(window_->GetNativeHandle());
1235 TabContents* contents = TabContents::CreateWithType(type, parent_hwnd,
1236 profile, instance);
[email protected]36b6dcb2008-11-12 01:19:571237 contents->SetupController(profile);
1238
1239 if (!defer_load) {
1240 // Load the initial URL before adding the new tab contents to the tab strip
1241 // so that the tab contents has navigation state.
1242 contents->controller()->LoadURL(url, referrer, transition);
1243 }
1244
1245 return contents;
1246}
1247
1248bool Browser::CanDuplicateContentsAt(int index) {
1249 TabContents* contents = GetTabContentsAt(index);
1250 DCHECK(contents);
1251
1252 NavigationController* nc = contents->controller();
1253 return nc ? (nc->active_contents() && nc->GetLastCommittedEntry()) : false;
1254}
1255
1256void Browser::DuplicateContentsAt(int index) {
1257 TabContents* contents = GetTabContentsAt(index);
1258 TabContents* new_contents = NULL;
1259 DCHECK(contents);
1260
1261 if (type_ == BrowserType::TABBED_BROWSER) {
1262 // If this is a tabbed browser, just create a duplicate tab inside the same
1263 // window next to the tab being duplicated.
[email protected]2d46c842008-11-14 19:24:311264 HWND parent_hwnd = reinterpret_cast<HWND>(window_->GetNativeHandle());
[email protected]36b6dcb2008-11-12 01:19:571265 new_contents = contents->controller()->Clone(
[email protected]2d46c842008-11-14 19:24:311266 parent_hwnd)->active_contents();
[email protected]36b6dcb2008-11-12 01:19:571267 // If you duplicate a tab that is not selected, we need to make sure to
1268 // select the tab being duplicated so that DetermineInsertionIndex returns
1269 // the right index (if tab 5 is selected and we right-click tab 1 we want
1270 // the new tab to appear in index position 2, not 6).
1271 if (tabstrip_model_.selected_index() != index)
1272 tabstrip_model_.SelectTabContentsAt(index, true);
1273 tabstrip_model_.AddTabContents(new_contents, index + 1,
1274 PageTransition::LINK, true);
1275 } else {
[email protected]15952e462008-11-14 00:29:051276 Browser* browser = NULL;
1277 if (type_ == BrowserType::APPLICATION) {
1278 browser = Browser::CreateForApp(app_name_, profile_);
1279 } else if (type_ == BrowserType::BROWSER) {
1280 browser = Browser::CreateForPopup(profile_);
1281 }
[email protected]36b6dcb2008-11-12 01:19:571282
1283 // We need to show the browser now. Otherwise ContainerWin assumes the
1284 // TabContents is invisible and won't size it.
[email protected]15952e462008-11-14 00:29:051285 browser->window()->Show();
[email protected]36b6dcb2008-11-12 01:19:571286
1287 // The page transition below is only for the purpose of inserting the tab.
[email protected]2d46c842008-11-14 19:24:311288 HWND parent_hwnd = reinterpret_cast<HWND>(window_->GetNativeHandle());
[email protected]15952e462008-11-14 00:29:051289 new_contents = browser->AddTabWithNavigationController(
[email protected]2d46c842008-11-14 19:24:311290 contents->controller()->Clone(parent_hwnd),
[email protected]36b6dcb2008-11-12 01:19:571291 PageTransition::LINK);
[email protected]36b6dcb2008-11-12 01:19:571292 }
1293
1294 if (profile_->HasSessionService()) {
1295 SessionService* session_service = profile_->GetSessionService();
1296 if (session_service)
1297 session_service->TabRestored(new_contents->controller());
1298 }
1299}
1300
[email protected]36b6dcb2008-11-12 01:19:571301void Browser::CloseFrameAfterDragSession() {
1302 // This is scheduled to run after we return to the message loop because
1303 // otherwise the frame will think the drag session is still active and ignore
1304 // the request.
1305 MessageLoop::current()->PostTask(FROM_HERE,
1306 method_factory_.NewRunnableMethod(&Browser::CloseFrame));
initial.commit09911bf2008-07-26 23:55:291307}
1308
[email protected]2d46c842008-11-14 19:24:311309///////////////////////////////////////////////////////////////////////////////
[email protected]36b6dcb2008-11-12 01:19:571310// Browser, TabStripModelObserver implementation:
1311
1312void Browser::TabInsertedAt(TabContents* contents,
1313 int index,
1314 bool foreground) {
1315 contents->set_delegate(this);
1316 contents->controller()->SetWindowID(session_id());
1317
1318 SyncHistoryWithTabs(tabstrip_model_.GetIndexOfTabContents(contents));
1319
1320 // When a tab is dropped into a tab strip we need to make sure that the
1321 // associated Find window is moved along with it. We therefore change the
1322 // parent of the Find window (if the parent is already correctly set this
1323 // does nothing).
1324 // TODO(brettw) this could probably be improved, see
1325 // WebContentsView::ReparentFindWindow for more.
1326 if (contents->AsWebContents())
1327 contents->AsWebContents()->view()->ReparentFindWindow(this);
1328
1329 // If the tab crashes in the beforeunload or unload handler, it won't be
1330 // able to ack. But we know we can close it.
1331 NotificationService::current()->
1332 AddObserver(this, NOTIFY_WEB_CONTENTS_DISCONNECTED,
1333 Source<TabContents>(contents));
1334}
1335
1336void Browser::TabClosingAt(TabContents* contents, int index) {
1337 NavigationController* controller = contents->controller();
1338 DCHECK(controller);
1339 NotificationService::current()->
1340 Notify(NOTIFY_TAB_CLOSING,
1341 Source<NavigationController>(controller),
1342 NotificationService::NoDetails());
1343
1344 // Sever the TabContents' connection back to us.
1345 contents->set_delegate(NULL);
1346}
1347
1348void Browser::TabDetachedAt(TabContents* contents, int index) {
1349 contents->set_delegate(NULL);
1350 if (!tabstrip_model_.closing_all())
1351 SyncHistoryWithTabs(0);
1352
1353 RemoveScheduledUpdatesFor(contents);
1354
1355 NotificationService::current()->
1356 RemoveObserver(this, NOTIFY_WEB_CONTENTS_DISCONNECTED,
1357 Source<TabContents>(contents));
1358}
1359
1360void Browser::TabSelectedAt(TabContents* old_contents,
1361 TabContents* new_contents,
1362 int index,
1363 bool user_gesture) {
1364 DCHECK(old_contents != new_contents);
1365
1366 // If we have any update pending, do it now.
1367 if (!chrome_updater_factory_.empty() && old_contents)
1368 ProcessPendingUIUpdates();
1369
1370 LocationBarView* location_bar = GetLocationBarView();
1371 if (old_contents) {
1372 // Save what the user's currently typing, so it can be restored when we
1373 // switch back to this tab.
1374 if (location_bar)
1375 location_bar->location_entry()->SaveStateToTab(old_contents);
1376 }
1377
1378 // Propagate the profile to the location bar.
1379 UpdateToolbar(true);
1380
1381 // Force the go/stop button to change.
1382 if (new_contents->AsWebContents()) {
1383 GetGoButton()->ChangeMode(
1384 new_contents->is_loading() ? GoButton::MODE_STOP : GoButton::MODE_GO);
1385 } else {
1386 GetGoButton()->ChangeMode(GoButton::MODE_GO);
1387 }
1388
1389 // Update other parts of the toolbar.
1390 UpdateNavigationCommands();
1391
1392 // Reset the status bubble.
1393 GetStatusBubble()->Hide();
1394
1395 // Show the loading state (if any).
1396 GetStatusBubble()->SetStatus(GetSelectedTabContents()->GetStatusText());
1397
1398 // Update sessions. Don't force creation of sessions. If sessions doesn't
1399 // exist, the change will be picked up by sessions when created.
1400 if (profile_->HasSessionService()) {
1401 SessionService* session_service = profile_->GetSessionService();
1402 if (session_service && !tabstrip_model_.closing_all()) {
[email protected]2d46c842008-11-14 19:24:311403 session_service->SetSelectedTabInWindow(
1404 session_id(), tabstrip_model_.selected_index());
[email protected]36b6dcb2008-11-12 01:19:571405 }
1406 }
1407}
1408
1409void Browser::TabMoved(TabContents* contents,
1410 int from_index,
1411 int to_index) {
1412 DCHECK(from_index >= 0 && to_index >= 0);
1413 // Notify the history service.
1414 SyncHistoryWithTabs(std::min(from_index, to_index));
1415}
1416
1417void Browser::TabStripEmpty() {
1418 // Close the frame after we return to the message loop (not immediately,
1419 // otherwise it will destroy this object before the stack has a chance to
1420 // cleanly unwind.)
1421 // Note: This will be called several times if TabStripEmpty is called several
1422 // times. This is because it does not close the window if tabs are
1423 // still present.
1424 // NOTE: If you change to be immediate (no invokeLater) then you'll need to
1425 // update BrowserList::CloseAllBrowsers.
1426 MessageLoop::current()->PostTask(FROM_HERE,
1427 method_factory_.NewRunnableMethod(&Browser::CloseFrame));
1428}
1429
1430///////////////////////////////////////////////////////////////////////////////
1431// Browser, TabContentsDelegate implementation:
initial.commit09911bf2008-07-26 23:55:291432
1433void Browser::OpenURLFromTab(TabContents* source,
[email protected]c0588052008-10-27 23:01:501434 const GURL& url, const GURL& referrer,
initial.commit09911bf2008-07-26 23:55:291435 WindowOpenDisposition disposition,
[email protected]e38f40152008-09-12 23:08:301436 PageTransition::Type transition) {
initial.commit09911bf2008-07-26 23:55:291437 // No code for these yet
1438 DCHECK((disposition != NEW_POPUP) && (disposition != SAVE_TO_DISK));
1439
1440 TabContents* current_tab = source ? source : GetSelectedTabContents();
1441 bool source_tab_was_frontmost = (current_tab == GetSelectedTabContents());
1442 TabContents* new_contents = NULL;
1443
1444 // If the URL is part of the same web site, then load it in the same
1445 // SiteInstance (and thus the same process). This is an optimization to
1446 // reduce process overhead; it is not necessary for compatibility. (That is,
1447 // the new tab will not have script connections to the previous tab, so it
1448 // does not need to be part of the same SiteInstance or BrowsingInstance.)
1449 // Default to loading in a new SiteInstance and BrowsingInstance.
1450 // TODO(creis): should this apply to applications?
1451 SiteInstance* instance = NULL;
1452 // Don't use this logic when "--process-per-tab" is specified.
1453 if (!CommandLine().HasSwitch(switches::kProcessPerTab)) {
1454 if (current_tab) {
1455 const WebContents* const web_contents = current_tab->AsWebContents();
1456 if (web_contents) {
1457 const GURL& current_url = web_contents->GetURL();
1458 if (SiteInstance::IsSameWebSite(current_url, url))
[email protected]e9ba4472008-09-14 15:42:431459 instance = web_contents->GetSiteInstance();
initial.commit09911bf2008-07-26 23:55:291460 }
1461 }
1462 }
1463
1464 // If this is an application we can only have one tab so a new tab always
1465 // goes into a tabbed browser window.
1466 if (disposition != NEW_WINDOW && type_ == BrowserType::APPLICATION) {
1467 // If the disposition is OFF_THE_RECORD we don't want to create a new
1468 // browser that will itself create another OTR browser. This will result in
1469 // a browser leak (and crash below because no tab is created or selected).
1470 if (disposition == OFF_THE_RECORD) {
1471 OpenURLOffTheRecord(profile_, url);
1472 return;
1473 }
1474
1475 Browser* b = GetOrCreateTabbedBrowser();
1476 DCHECK(b);
1477
1478 // If we have just created a new browser window, make sure we select the
1479 // tab.
1480 if (b->tab_count() == 0 && disposition == NEW_BACKGROUND_TAB)
1481 disposition = NEW_FOREGROUND_TAB;
1482
[email protected]c0588052008-10-27 23:01:501483 b->OpenURL(url, referrer, disposition, transition);
[email protected]15952e462008-11-14 00:29:051484 b->window()->Show();
initial.commit09911bf2008-07-26 23:55:291485 return;
1486 }
1487
1488 if (profile_->IsOffTheRecord() && disposition == OFF_THE_RECORD)
1489 disposition = NEW_FOREGROUND_TAB;
1490
1491 if (disposition == NEW_WINDOW) {
[email protected]15952e462008-11-14 00:29:051492 Browser* browser = Browser::Create(profile_);
1493 new_contents = browser->AddTabWithURL(url, referrer, transition, true,
1494 instance);
1495 browser->window()->Show();
initial.commit09911bf2008-07-26 23:55:291496 } else if ((disposition == CURRENT_TAB) && current_tab) {
1497 if (transition == PageTransition::TYPED ||
1498 transition == PageTransition::AUTO_BOOKMARK ||
1499 transition == PageTransition::GENERATED ||
1500 transition == PageTransition::START_PAGE) {
[email protected]968e56ae2008-08-04 18:39:281501 // Don't forget the openers if this tab is a New Tab page opened at the
1502 // end of the TabStrip (e.g. by pressing Ctrl+T). Give the user one
1503 // navigation of one of these transition types before resetting the
1504 // opener relationships (this allows for the use case of opening a new
1505 // tab to do a quick look-up of something while viewing a tab earlier in
1506 // the strip). We can make this heuristic more permissive if need be.
1507 // TODO(beng): (http://b/1306495) write unit tests for this once this
1508 // object is unit-testable.
1509 int current_tab_index =
1510 tabstrip_model_.GetIndexOfTabContents(current_tab);
1511 bool forget_openers =
1512 !(current_tab->type() == TAB_CONTENTS_NEW_TAB_UI &&
1513 current_tab_index == (tab_count() - 1) &&
1514 current_tab->controller()->GetEntryCount() == 1);
1515 if (forget_openers) {
1516 // If the user navigates the current tab to another page in any way
1517 // other than by clicking a link, we want to pro-actively forget all
1518 // TabStrip opener relationships since we assume they're beginning a
1519 // different task by reusing the current tab.
1520 tabstrip_model_.ForgetAllOpeners();
1521 // In this specific case we also want to reset the group relationship,
1522 // since it is now technically invalid.
1523 tabstrip_model_.ForgetGroup(current_tab);
1524 }
initial.commit09911bf2008-07-26 23:55:291525 }
[email protected]c0588052008-10-27 23:01:501526 current_tab->controller()->LoadURL(url, referrer, transition);
[email protected]2d46c842008-11-14 19:24:311527 // The TabContents might have changed as part of the navigation (ex: new
1528 // tab page can become WebContents).
initial.commit09911bf2008-07-26 23:55:291529 new_contents = current_tab->controller()->active_contents();
1530 GetStatusBubble()->Hide();
1531
1532 // Synchronously update the location bar. This allows us to immediately
1533 // have the URL bar update when the user types something, rather than
1534 // going through the normal system of ScheduleUIUpdate which has a delay.
[email protected]36b6dcb2008-11-12 01:19:571535 UpdateToolbar(false);
initial.commit09911bf2008-07-26 23:55:291536 } else if (disposition == OFF_THE_RECORD) {
1537 OpenURLOffTheRecord(profile_, url);
1538 return;
1539 } else if (disposition != SUPPRESS_OPEN) {
[email protected]15952e462008-11-14 00:29:051540 new_contents = AddTabWithURL(url, referrer, transition,
1541 disposition != NEW_BACKGROUND_TAB, instance);
initial.commit09911bf2008-07-26 23:55:291542 }
1543
1544 if (disposition != NEW_BACKGROUND_TAB && source_tab_was_frontmost) {
[email protected]2baf83d2008-07-30 05:58:171545 // Give the focus to the newly navigated tab, if the source tab was
1546 // front-most.
initial.commit09911bf2008-07-26 23:55:291547 new_contents->Focus();
1548 }
1549}
1550
1551void Browser::NavigationStateChanged(const TabContents* source,
1552 unsigned changed_flags) {
initial.commit09911bf2008-07-26 23:55:291553 // Only update the UI when something visible has changed.
[email protected]e83f1682008-09-07 23:57:401554 if (changed_flags)
initial.commit09911bf2008-07-26 23:55:291555 ScheduleUIUpdate(source, changed_flags);
1556
1557 // We don't schedule updates to the navigation commands since they will only
1558 // change once per navigation, so we don't have to worry about flickering.
[email protected]e83f1682008-09-07 23:57:401559 if (changed_flags & TabContents::INVALIDATE_URL)
initial.commit09911bf2008-07-26 23:55:291560 UpdateNavigationCommands();
initial.commit09911bf2008-07-26 23:55:291561}
1562
1563void Browser::ReplaceContents(TabContents* source, TabContents* new_contents) {
1564 source->set_delegate(NULL);
1565 new_contents->set_delegate(this);
1566
1567 RemoveScheduledUpdatesFor(source);
1568
1569 int index = tabstrip_model_.GetIndexOfTabContents(source);
1570 tabstrip_model_.ReplaceTabContentsAt(index, new_contents);
[email protected]8f673f3a2008-08-05 22:34:281571
1572 if (is_attempting_to_close_browser_) {
1573 // Need to do this asynchronously as it will close the tab, which is
1574 // currently on the call stack above us.
1575 MessageLoop::current()->PostTask(FROM_HERE,
[email protected]8a2ce5a2008-08-11 23:43:081576 method_factory_.NewRunnableMethod(&Browser::ClearUnloadState,
[email protected]8f673f3a2008-08-05 22:34:281577 Source<TabContents>(source).ptr()));
1578 }
1579 // Need to remove ourselves as an observer for disconnection on the replaced
1580 // TabContents, since we only care to fire onbeforeunload handlers on active
1581 // Tabs. Make sure an observer is added for the replacement TabContents.
1582 NotificationService::current()->
1583 RemoveObserver(this, NOTIFY_WEB_CONTENTS_DISCONNECTED,
1584 Source<TabContents>(source));
1585 NotificationService::current()->
1586 AddObserver(this, NOTIFY_WEB_CONTENTS_DISCONNECTED,
1587 Source<TabContents>(new_contents));
1588
initial.commit09911bf2008-07-26 23:55:291589}
1590
1591void Browser::AddNewContents(TabContents* source,
1592 TabContents* new_contents,
1593 WindowOpenDisposition disposition,
1594 const gfx::Rect& initial_pos,
1595 bool user_gesture) {
1596 DCHECK(disposition != SAVE_TO_DISK); // No code for this yet
1597
1598 // If this is an application we can only have one tab so we need to process
1599 // this in tabbed browser window.
1600 if (tabstrip_model_.count() > 0 &&
1601 disposition != NEW_WINDOW && disposition != NEW_POPUP &&
1602 type_ != BrowserType::TABBED_BROWSER) {
1603 Browser* b = GetOrCreateTabbedBrowser();
1604 DCHECK(b);
1605 PageTransition::Type transition = PageTransition::LINK;
1606 // If we were called from an "installed webapp" we want to emulate the code
1607 // that is run from browser_init.cc for links from external applications.
1608 // This means we need to open the tab with the START PAGE transition.
1609 // AddNewContents doesn't support this but the TabStripModel's
1610 // AddTabContents method does.
1611 if (type_ == BrowserType::APPLICATION)
1612 transition = PageTransition::START_PAGE;
1613 b->tabstrip_model()->AddTabContents(new_contents, -1, transition, true);
[email protected]15952e462008-11-14 00:29:051614 b->window()->Show();
initial.commit09911bf2008-07-26 23:55:291615 return;
1616 }
1617
1618 if (disposition == NEW_POPUP) {
1619 BuildPopupWindow(source, new_contents, initial_pos);
1620 } else if (disposition == NEW_WINDOW) {
[email protected]15952e462008-11-14 00:29:051621 Browser* browser = Browser::Create(profile_);
1622 browser->AddNewContents(source, new_contents, NEW_FOREGROUND_TAB,
1623 initial_pos, user_gesture);
1624 browser->window()->Show();
initial.commit09911bf2008-07-26 23:55:291625 } else if (disposition == CURRENT_TAB) {
1626 ReplaceContents(source, new_contents);
1627 } else if (disposition != SUPPRESS_OPEN) {
1628 tabstrip_model_.AddTabContents(new_contents, -1, PageTransition::LINK,
1629 disposition == NEW_FOREGROUND_TAB);
1630 }
1631}
1632
initial.commit09911bf2008-07-26 23:55:291633void Browser::ActivateContents(TabContents* contents) {
1634 tabstrip_model_.SelectTabContentsAt(
1635 tabstrip_model_.GetIndexOfTabContents(contents), false);
[email protected]f3e99e32008-07-30 04:48:391636 window_->Activate();
initial.commit09911bf2008-07-26 23:55:291637}
1638
initial.commit09911bf2008-07-26 23:55:291639void Browser::LoadingStateChanged(TabContents* source) {
[email protected]afb73882008-11-14 22:40:441640 window_->UpdateLoadingAnimations(tabstrip_model_.TabsAreLoading());
[email protected]f3e99e32008-07-30 04:48:391641 window_->UpdateTitleBar();
initial.commit09911bf2008-07-26 23:55:291642
1643 // Let the go button know that it should change appearance if possible.
1644 if (source == GetSelectedTabContents()) {
1645 GetGoButton()->ScheduleChangeMode(
1646 source->is_loading() ? GoButton::MODE_STOP : GoButton::MODE_GO);
1647
1648 GetStatusBubble()->SetStatus(GetSelectedTabContents()->GetStatusText());
1649 }
1650}
1651
1652void Browser::CloseContents(TabContents* source) {
[email protected]04b4a6c2008-08-02 00:44:471653 if (is_attempting_to_close_browser_) {
1654 // If we're trying to close the browser, just clear the state related to
1655 // waiting for unload to fire. Don't actually try to close the tab as it
1656 // will go down the slow shutdown path instead of the fast path of killing
1657 // all the renderer processes.
[email protected]8a2ce5a2008-08-11 23:43:081658 ClearUnloadState(source);
[email protected]04b4a6c2008-08-02 00:44:471659 return;
1660 }
1661
initial.commit09911bf2008-07-26 23:55:291662 int index = tabstrip_model_.GetIndexOfTabContents(source);
1663 if (index == TabStripModel::kNoTab) {
1664 NOTREACHED() << "CloseContents called for tab not in our strip";
1665 return;
1666 }
1667 tabstrip_model_.CloseTabContentsAt(index);
1668}
1669
[email protected]15e8abe2008-08-20 22:40:401670void Browser::MoveContents(TabContents* source, const gfx::Rect& pos) {
[email protected]999aa602008-11-11 21:57:561671 if (type() != BrowserType::BROWSER) {
initial.commit09911bf2008-07-26 23:55:291672 NOTREACHED() << "moving invalid browser type";
1673 return;
1674 }
[email protected]2d46c842008-11-14 19:24:311675 window_->SetBounds(pos);
initial.commit09911bf2008-07-26 23:55:291676}
1677
1678bool Browser::IsPopup(TabContents* source) {
1679 // A non-tabbed BROWSER is an unconstrained popup.
[email protected]999aa602008-11-11 21:57:561680 return (type() == BrowserType::BROWSER);
initial.commit09911bf2008-07-26 23:55:291681}
1682
[email protected]36b6dcb2008-11-12 01:19:571683void Browser::ToolbarSizeChanged(TabContents* source, bool is_animating) {
1684 if (source == GetSelectedTabContents() || source == NULL) {
1685 // This will refresh the shelf if needed.
1686 window_->SelectedTabToolbarSizeChanged(is_animating);
1687 }
1688}
1689
1690void Browser::URLStarredChanged(TabContents* source, bool starred) {
1691 if (source == GetSelectedTabContents())
1692 SetStarredButtonToggled(starred);
1693}
1694
1695void Browser::ContentsMouseEvent(TabContents* source, UINT message) {
1696 if (source == GetSelectedTabContents()) {
1697 if (message == WM_MOUSEMOVE) {
1698 GetStatusBubble()->MouseMoved();
1699 } else if (message == WM_MOUSELEAVE) {
1700 GetStatusBubble()->SetURL(GURL(), std::wstring());
1701 }
1702 }
1703}
1704
1705void Browser::UpdateTargetURL(TabContents* source, const GURL& url) {
1706 if (source == GetSelectedTabContents()) {
1707 PrefService* prefs = profile_->GetPrefs();
1708 GetStatusBubble()->SetURL(url, prefs->GetString(prefs::kAcceptLanguages));
1709 }
1710}
1711
1712void Browser::ContentsZoomChange(bool zoom_in) {
1713 controller_.ExecuteCommand(zoom_in ? IDC_ZOOM_PLUS : IDC_ZOOM_MINUS);
1714}
1715
1716bool Browser::IsApplication() const {
1717 return type_ == BrowserType::APPLICATION;
1718}
1719
1720void Browser::ConvertContentsToApplication(TabContents* contents) {
1721 if (!contents->AsWebContents() || !contents->AsWebContents()->web_app()) {
1722 NOTREACHED();
1723 return;
1724 }
1725
1726 int index = tabstrip_model_.GetIndexOfTabContents(contents);
1727 if (index < 0)
1728 return;
1729
1730 WebApp* app = contents->AsWebContents()->web_app();
1731 const std::wstring& app_name =
1732 app->name().empty() ? ComputeApplicationNameFromURL(app->url()) :
1733 app->name();
1734 RegisterAppPrefs(app_name);
1735
1736 tabstrip_model_.DetachTabContentsAt(index);
[email protected]15952e462008-11-14 00:29:051737 Browser* browser = Browser::CreateForApp(app_name, profile_);
1738 browser->tabstrip_model()->AppendTabContents(contents, true);
1739 browser->window()->Show();
[email protected]36b6dcb2008-11-12 01:19:571740}
1741
1742void Browser::ContentsStateChanged(TabContents* source) {
1743 int index = tabstrip_model_.GetIndexOfTabContents(source);
1744 if (index != TabStripModel::kNoTab)
1745 tabstrip_model_.UpdateTabContentsStateAt(index);
1746}
1747
1748bool Browser::ShouldDisplayURLField() {
1749 return !IsApplication();
1750}
1751
1752void Browser::BeforeUnloadFired(TabContents* tab,
1753 bool proceed,
1754 bool* proceed_to_fire_unload) {
1755 if (!is_attempting_to_close_browser_) {
1756 *proceed_to_fire_unload = proceed;
1757 return;
1758 }
1759
1760 if (!proceed) {
1761 CancelWindowClose();
1762 *proceed_to_fire_unload = false;
1763 return;
1764 }
1765
1766 if (RemoveFromVector(&tabs_needing_before_unload_fired_, tab)) {
[email protected]2d46c842008-11-14 19:24:311767 // Now that beforeunload has fired, put the tab on the queue to fire
1768 // unload.
[email protected]36b6dcb2008-11-12 01:19:571769 tabs_needing_unload_fired_.push_back(tab);
1770 ProcessPendingTabs();
1771 // We want to handle firing the unload event ourselves since we want to
1772 // fire all the beforeunload events before attempting to fire the unload
1773 // events should the user cancel closing the browser.
1774 *proceed_to_fire_unload = false;
1775 return;
1776 }
1777
1778 *proceed_to_fire_unload = true;
1779}
1780
initial.commit09911bf2008-07-26 23:55:291781void Browser::ShowHtmlDialog(HtmlDialogContentsDelegate* delegate,
[email protected]2d46c842008-11-14 19:24:311782 void* parent_window) {
1783 window_->ShowHTMLDialog(delegate, parent_window);
initial.commit09911bf2008-07-26 23:55:291784}
1785
[email protected]36b6dcb2008-11-12 01:19:571786///////////////////////////////////////////////////////////////////////////////
1787// Browser, SelectFileDialog::Listener implementation:
1788
1789void Browser::FileSelected(const std::wstring& path, void* params) {
1790 GURL file_url = net::FilePathToFileURL(path);
1791 if (!file_url.is_empty())
1792 OpenURL(file_url, GURL(), CURRENT_TAB, PageTransition::TYPED);
1793}
1794
1795///////////////////////////////////////////////////////////////////////////////
1796// Browser, NotificationObserver implementation:
1797
initial.commit09911bf2008-07-26 23:55:291798void Browser::Observe(NotificationType type,
1799 const NotificationSource& source,
1800 const NotificationDetails& details) {
[email protected]e83f1682008-09-07 23:57:401801 switch (type) {
[email protected]e83f1682008-09-07 23:57:401802 case NOTIFY_WEB_CONTENTS_DISCONNECTED:
1803 if (is_attempting_to_close_browser_) {
1804 // Need to do this asynchronously as it will close the tab, which is
1805 // currently on the call stack above us.
1806 MessageLoop::current()->PostTask(FROM_HERE,
1807 method_factory_.NewRunnableMethod(&Browser::ClearUnloadState,
1808 Source<TabContents>(source).ptr()));
1809 }
1810 break;
1811
1812 case NOTIFY_SSL_STATE_CHANGED:
1813 // When the current tab's SSL state changes, we need to update the URL
[email protected]90e8d062008-09-08 02:26:321814 // bar to reflect the new state. Note that it's possible for the selected
1815 // tab contents to be NULL. This is because we listen for all sources
1816 // (NavigationControllers) for convenience, so the notification could
1817 // actually be for a different window while we're doing asynchronous
1818 // closing of this one.
1819 if (GetSelectedTabContents() &&
1820 GetSelectedTabContents()->controller() ==
[email protected]e83f1682008-09-07 23:57:401821 Source<NavigationController>(source).ptr())
[email protected]36b6dcb2008-11-12 01:19:571822 UpdateToolbar(false);
[email protected]e83f1682008-09-07 23:57:401823 break;
1824
1825 default:
1826 NOTREACHED() << "Got a notification we didn't register for.";
initial.commit09911bf2008-07-26 23:55:291827 }
1828}
1829
[email protected]36b6dcb2008-11-12 01:19:571830///////////////////////////////////////////////////////////////////////////////
1831// Browser, Command and state updating (private):
1832
1833void Browser::InitCommandState() {
1834 // All browser commands whose state isn't set automagically some other way
1835 // (like Back & Forward with initial page load) must have their state
1836 // initialized here, otherwise they will be forever disabled.
1837
1838 controller_.UpdateCommandEnabled(IDC_STOP, true);
1839 controller_.UpdateCommandEnabled(IDC_RELOAD, true);
1840 controller_.UpdateCommandEnabled(IDC_HOME,
1841 type() == BrowserType::TABBED_BROWSER);
1842 controller_.UpdateCommandEnabled(IDC_GO, true);
1843 controller_.UpdateCommandEnabled(IDC_NEWTAB, true);
1844 controller_.UpdateCommandEnabled(IDC_CLOSETAB, true);
1845 controller_.UpdateCommandEnabled(IDC_NEWWINDOW, true);
1846 controller_.UpdateCommandEnabled(IDC_CLOSEWINDOW, true);
1847 controller_.UpdateCommandEnabled(IDC_FOCUS_LOCATION, true);
1848 controller_.UpdateCommandEnabled(IDC_FOCUS_SEARCH, true);
1849 controller_.UpdateCommandEnabled(IDC_FOCUS_TOOLBAR, true);
1850 controller_.UpdateCommandEnabled(IDC_STAR, true);
1851 controller_.UpdateCommandEnabled(IDC_OPENURL, true);
1852 controller_.UpdateCommandEnabled(IDC_SHOWALLTABS_NEXT, true);
1853 controller_.UpdateCommandEnabled(IDC_SHOWALLTABS_PREV, true);
1854 controller_.UpdateCommandEnabled(IDC_SHOWALLTABS, true);
1855 controller_.UpdateCommandEnabled(IDC_CUT, true);
1856 controller_.UpdateCommandEnabled(IDC_COPY, true);
1857 controller_.UpdateCommandEnabled(IDC_PASTE, true);
1858 controller_.UpdateCommandEnabled(IDC_FIND, true);
1859 controller_.UpdateCommandEnabled(IDC_FIND_NEXT, true);
1860 controller_.UpdateCommandEnabled(IDC_FIND_PREVIOUS, true);
1861 controller_.UpdateCommandEnabled(IDS_COMMANDS_REPORTBUG, true);
1862 controller_.UpdateCommandEnabled(IDC_SHOW_JS_CONSOLE, true);
1863 controller_.UpdateCommandEnabled(IDC_SELECT_NEXT_TAB, true);
1864 controller_.UpdateCommandEnabled(IDC_SELECT_PREV_TAB, true);
1865 controller_.UpdateCommandEnabled(IDC_SELECT_TAB_0, true);
1866 controller_.UpdateCommandEnabled(IDC_SELECT_TAB_1, true);
1867 controller_.UpdateCommandEnabled(IDC_SELECT_TAB_2, true);
1868 controller_.UpdateCommandEnabled(IDC_SELECT_TAB_3, true);
1869 controller_.UpdateCommandEnabled(IDC_SELECT_TAB_4, true);
1870 controller_.UpdateCommandEnabled(IDC_SELECT_TAB_5, true);
1871 controller_.UpdateCommandEnabled(IDC_SELECT_TAB_6, true);
1872 controller_.UpdateCommandEnabled(IDC_SELECT_TAB_7, true);
1873 controller_.UpdateCommandEnabled(IDC_SELECT_LAST_TAB, true);
1874 controller_.UpdateCommandEnabled(IDC_VIEWSOURCE, true);
1875 controller_.UpdateCommandEnabled(IDC_CREATE_SHORTCUT, false);
1876 controller_.UpdateCommandEnabled(IDC_EDIT_SEARCH_ENGINES, true);
1877 controller_.UpdateCommandEnabled(IDC_ZOOM_PLUS, true);
1878 controller_.UpdateCommandEnabled(IDC_ZOOM_MINUS, true);
1879 controller_.UpdateCommandEnabled(IDC_ZOOM_NORMAL, true);
1880 controller_.UpdateCommandEnabled(IDC_OPENFILE, true);
1881 controller_.UpdateCommandEnabled(IDC_TASKMANAGER, true);
1882 controller_.UpdateCommandEnabled(IDC_CLOSEPOPUPS, true);
1883 controller_.UpdateCommandEnabled(IDC_PRINT, true);
1884 controller_.UpdateCommandEnabled(IDC_COPY_URL, true);
1885 controller_.UpdateCommandEnabled(IDC_DUPLICATE, true);
1886 controller_.UpdateCommandEnabled(IDC_GOOFFTHERECORD, true);
1887 controller_.UpdateCommandEnabled(IDC_VIEW_PASSWORDS, true);
1888 controller_.UpdateCommandEnabled(IDC_IMPORT_SETTINGS, true);
1889 controller_.UpdateCommandEnabled(IDC_CLEAR_BROWSING_DATA, true);
1890 controller_.UpdateCommandEnabled(IDC_ABOUT, true);
1891 controller_.UpdateCommandEnabled(IDC_SHOW_HISTORY, true);
1892 controller_.UpdateCommandEnabled(IDC_SHOW_BOOKMARKS_BAR, true);
1893 controller_.UpdateCommandEnabled(IDC_SHOW_BOOKMARK_MANAGER, true);
1894 controller_.UpdateCommandEnabled(IDC_SHOW_DOWNLOADS, true);
1895 controller_.UpdateCommandEnabled(IDC_ENCODING, true);
1896 controller_.UpdateCommandEnabled(IDC_ENCODING_AUTO_DETECT, true);
1897 controller_.UpdateCommandEnabled(IDC_ENCODING_UTF8, true);
1898 controller_.UpdateCommandEnabled(IDC_ENCODING_UTF16LE, true);
1899 controller_.UpdateCommandEnabled(IDC_ENCODING_ISO88591, true);
1900 controller_.UpdateCommandEnabled(IDC_ENCODING_WINDOWS1252, true);
1901 controller_.UpdateCommandEnabled(IDC_ENCODING_GB2312, true);
1902 controller_.UpdateCommandEnabled(IDC_ENCODING_GB18030, true);
1903 controller_.UpdateCommandEnabled(IDC_ENCODING_BIG5HKSCS, true);
1904 controller_.UpdateCommandEnabled(IDC_ENCODING_BIG5, true);
1905 controller_.UpdateCommandEnabled(IDC_ENCODING_THAI, true);
1906 controller_.UpdateCommandEnabled(IDC_ENCODING_KOREAN, true);
1907 controller_.UpdateCommandEnabled(IDC_ENCODING_SHIFTJIS, true);
1908 controller_.UpdateCommandEnabled(IDC_ENCODING_ISO2022JP, true);
1909 controller_.UpdateCommandEnabled(IDC_ENCODING_EUCJP, true);
1910 controller_.UpdateCommandEnabled(IDC_ENCODING_ISO885915, true);
1911 controller_.UpdateCommandEnabled(IDC_ENCODING_MACINTOSH, true);
1912 controller_.UpdateCommandEnabled(IDC_ENCODING_ISO88592, true);
1913 controller_.UpdateCommandEnabled(IDC_ENCODING_WINDOWS1250, true);
1914 controller_.UpdateCommandEnabled(IDC_ENCODING_ISO88595, true);
1915 controller_.UpdateCommandEnabled(IDC_ENCODING_WINDOWS1251, true);
1916 controller_.UpdateCommandEnabled(IDC_ENCODING_KOI8R, true);
1917 controller_.UpdateCommandEnabled(IDC_ENCODING_KOI8U, true);
1918 controller_.UpdateCommandEnabled(IDC_ENCODING_ISO88597, true);
1919 controller_.UpdateCommandEnabled(IDC_ENCODING_WINDOWS1253, true);
1920 controller_.UpdateCommandEnabled(IDC_ENCODING_ISO88594, true);
1921 controller_.UpdateCommandEnabled(IDC_ENCODING_ISO885913, true);
1922 controller_.UpdateCommandEnabled(IDC_ENCODING_WINDOWS1257, true);
1923 controller_.UpdateCommandEnabled(IDC_ENCODING_ISO88593, true);
1924 controller_.UpdateCommandEnabled(IDC_ENCODING_ISO885910, true);
1925 controller_.UpdateCommandEnabled(IDC_ENCODING_ISO885914, true);
1926 controller_.UpdateCommandEnabled(IDC_ENCODING_ISO885916, true);
1927 controller_.UpdateCommandEnabled(IDC_ENCODING_ISO88599, true);
1928 controller_.UpdateCommandEnabled(IDC_ENCODING_WINDOWS1254, true);
1929 controller_.UpdateCommandEnabled(IDC_ENCODING_ISO88596, true);
1930 controller_.UpdateCommandEnabled(IDC_ENCODING_WINDOWS1256, true);
1931 controller_.UpdateCommandEnabled(IDC_ENCODING_ISO88598, true);
1932 controller_.UpdateCommandEnabled(IDC_ENCODING_WINDOWS1255, true);
1933 controller_.UpdateCommandEnabled(IDC_ENCODING_WINDOWS1258, true);
1934 controller_.UpdateCommandEnabled(IDC_OPTIONS, true);
1935 controller_.UpdateCommandEnabled(IDC_CLOSE_WEB_APP,
1936 type() != BrowserType::TABBED_BROWSER);
1937 controller_.UpdateCommandEnabled(IDC_SHOW_AS_TAB,
1938 type() == BrowserType::BROWSER);
1939 controller_.UpdateCommandEnabled(
1940 IDC_RESTORE_TAB, (!profile_->IsOffTheRecord() &&
1941 type() == BrowserType::TABBED_BROWSER));
1942 controller_.UpdateCommandEnabled(IDC_EXIT, true);
1943 // the debugger doesn't work in single process mode
1944 controller_.UpdateCommandEnabled(IDC_DEBUGGER,
1945 !RenderProcessHost::run_renderer_in_process());
1946 controller_.UpdateCommandEnabled(IDC_DEVELOPER, true);
1947 controller_.UpdateCommandEnabled(IDC_HELPMENU, true);
1948}
1949
initial.commit09911bf2008-07-26 23:55:291950void Browser::UpdateNavigationCommands() {
[email protected]c7c42332008-11-15 01:10:541951 TabContents* current_tab = GetSelectedTabContents();
initial.commit09911bf2008-07-26 23:55:291952 NavigationController* nc = current_tab->controller();
1953 controller_.UpdateCommandEnabled(IDC_BACK, nc->CanGoBack());
1954 controller_.UpdateCommandEnabled(IDC_FORWARD, nc->CanGoForward());
1955
[email protected]c7c42332008-11-15 01:10:541956 WebContents* web_contents = current_tab->AsWebContents();
initial.commit09911bf2008-07-26 23:55:291957
1958 if (web_contents) {
1959 controller_.UpdateCommandEnabled(IDC_STAR, true);
1960 SetStarredButtonToggled(web_contents->is_starred());
1961
1962 // View-source should not be enabled if already in view-source mode.
1963 controller_.UpdateCommandEnabled(IDC_VIEWSOURCE,
1964 current_tab->type() != TAB_CONTENTS_VIEW_SOURCE &&
1965 current_tab->controller()->GetActiveEntry());
1966
1967 controller_.UpdateCommandEnabled(IDC_ZOOM, true);
1968 bool enable_encoding =
1969 SavePackage::IsSavableContents(web_contents->contents_mime_type()) &&
1970 SavePackage::IsSavableURL(current_tab->GetURL());
1971 controller_.UpdateCommandEnabled(IDC_ENCODING, enable_encoding);
1972
1973 controller_.UpdateCommandEnabled(IDC_SAVEPAGE,
1974 SavePackage::IsSavableURL(current_tab->GetURL()));
1975 controller_.UpdateCommandEnabled(IDC_SHOW_JS_CONSOLE, true);
[email protected]fbd77592008-11-12 20:50:271976 controller_.UpdateCommandEnabled(IDC_FIND, true);
1977 controller_.UpdateCommandEnabled(IDC_FIND_NEXT, true);
1978 controller_.UpdateCommandEnabled(IDC_FIND_PREVIOUS, true);
1979 controller_.UpdateCommandEnabled(IDC_ZOOM_PLUS, true);
1980 controller_.UpdateCommandEnabled(IDC_ZOOM_MINUS, true);
1981 controller_.UpdateCommandEnabled(IDC_ZOOM_NORMAL, true);
1982 controller_.UpdateCommandEnabled(IDC_STOP, true);
1983 controller_.UpdateCommandEnabled(IDC_SHOW_JS_CONSOLE, true);
1984 controller_.UpdateCommandEnabled(IDC_PRINT, true);
initial.commit09911bf2008-07-26 23:55:291985 } else {
1986 controller_.UpdateCommandEnabled(IDC_VIEWSOURCE, false);
1987 controller_.UpdateCommandEnabled(IDC_SHOW_JS_CONSOLE, false);
1988
1989 // Both disable the starring button and ensure it doesn't show a star.
1990 controller_.UpdateCommandEnabled(IDC_STAR, false);
1991 SetStarredButtonToggled(false);
1992 controller_.UpdateCommandEnabled(IDC_ZOOM, false);
1993 controller_.UpdateCommandEnabled(IDC_ENCODING, false);
1994
1995 controller_.UpdateCommandEnabled(IDC_SAVEPAGE, false);
[email protected]fbd77592008-11-12 20:50:271996 controller_.UpdateCommandEnabled(IDC_FIND, false);
1997 controller_.UpdateCommandEnabled(IDC_FIND_NEXT, false);
1998 controller_.UpdateCommandEnabled(IDC_FIND_PREVIOUS, false);
1999 controller_.UpdateCommandEnabled(IDC_ZOOM_PLUS, false);
2000 controller_.UpdateCommandEnabled(IDC_ZOOM_MINUS, false);
2001 controller_.UpdateCommandEnabled(IDC_ZOOM_NORMAL, false);
2002 controller_.UpdateCommandEnabled(IDC_STOP, false);
2003 controller_.UpdateCommandEnabled(IDC_SHOW_JS_CONSOLE, false);
2004 controller_.UpdateCommandEnabled(IDC_PRINT, false);
initial.commit09911bf2008-07-26 23:55:292005 }
2006
2007 controller_.UpdateCommandEnabled(IDC_CREATE_SHORTCUT,
2008 current_tab->type() == TAB_CONTENTS_WEB &&
2009 !current_tab->GetFavIcon().isNull());
initial.commit09911bf2008-07-26 23:55:292010 controller_.UpdateCommandEnabled(IDC_DUPLICATE,
2011 CanDuplicateContentsAt(selected_index()));
initial.commit09911bf2008-07-26 23:55:292012}
2013
[email protected]36b6dcb2008-11-12 01:19:572014void Browser::SetStarredButtonToggled(bool starred) {
2015 window_->GetStarButton()->SetToggled(starred);
initial.commit09911bf2008-07-26 23:55:292016}
2017
[email protected]36b6dcb2008-11-12 01:19:572018///////////////////////////////////////////////////////////////////////////////
2019// Browser, UI update coalescing and handling (private):
2020
2021void Browser::UpdateToolbar(bool should_restore_state) {
2022 window_->UpdateToolbar(GetSelectedTabContents(), should_restore_state);
initial.commit09911bf2008-07-26 23:55:292023}
2024
[email protected]36b6dcb2008-11-12 01:19:572025void Browser::ScheduleUIUpdate(const TabContents* source,
2026 unsigned changed_flags) {
2027 // Synchronously update the URL.
2028 if (changed_flags & TabContents::INVALIDATE_URL &&
2029 source == GetSelectedTabContents()) {
2030 // Only update the URL for the current tab. Note that we do not update
2031 // the navigation commands since those would have already been updated
2032 // synchronously by NavigationStateChanged.
2033 UpdateToolbar(false);
2034
2035 if (changed_flags == TabContents::INVALIDATE_URL)
2036 return; // Just had an update URL and nothing else.
2037 }
2038
2039 // Save the dirty bits.
2040 scheduled_updates_.push_back(UIUpdate(source, changed_flags));
2041
2042 if (chrome_updater_factory_.empty()) {
2043 // No task currently scheduled, start another.
2044 MessageLoop::current()->PostDelayedTask(FROM_HERE,
2045 chrome_updater_factory_.NewRunnableMethod(
2046 &Browser::ProcessPendingUIUpdates),
2047 kUIUpdateCoalescingTimeMS);
2048 }
2049}
2050
2051void Browser::ProcessPendingUIUpdates() {
2052#ifndef NDEBUG
2053 // Validate that all tabs we have pending updates for exist. This is scary
2054 // because the pending list must be kept in sync with any detached or
2055 // deleted tabs. This code does not dereference any TabContents pointers.
2056 for (size_t i = 0; i < scheduled_updates_.size(); i++) {
2057 bool found = false;
2058 for (int tab = 0; tab < tab_count(); tab++) {
2059 if (GetTabContentsAt(tab)->controller() ==
2060 scheduled_updates_[i].source->controller()) {
2061 found = true;
2062 break;
2063 }
2064 }
2065 DCHECK(found);
2066 }
2067#endif
2068
2069 chrome_updater_factory_.RevokeAll();
2070
[email protected]2d46c842008-11-14 19:24:312071 // We could have many updates for the same thing in the queue. This map
2072 // tracks the bits of the stuff we've already updated for each TabContents so
2073 // we don't update again.
[email protected]36b6dcb2008-11-12 01:19:572074 typedef std::map<const TabContents*, unsigned> UpdateTracker;
2075 UpdateTracker updated_stuff;
2076
2077 for (size_t i = 0; i < scheduled_updates_.size(); i++) {
2078 // Do not dereference |contents|, it may be out-of-date!
2079 const TabContents* contents = scheduled_updates_[i].source;
2080 unsigned flags = scheduled_updates_[i].changed_flags;
2081
2082 // Remove any bits we have already updated, and save the new bits.
2083 UpdateTracker::iterator updated = updated_stuff.find(contents);
2084 if (updated != updated_stuff.end()) {
2085 // Turn off bits already set.
2086 flags &= ~updated->second;
2087 if (!flags)
2088 continue;
2089
2090 updated->second |= flags;
2091 } else {
2092 updated_stuff[contents] = flags;
2093 }
2094
2095 // Updates to the title or favicon require a tab repaint. However, the
2096 // inverse is not true since updates to the title also update the window
2097 // title.
2098 bool invalidate_tab = false;
2099 if (flags & TabContents::INVALIDATE_TITLE ||
2100 flags & TabContents::INVALIDATE_FAVICON) {
2101 invalidate_tab = true;
2102
2103 // Anything that repaints the tab means the favicon is updated.
2104 updated_stuff[contents] |= TabContents::INVALIDATE_FAVICON;
2105 }
2106
2107 // Updating the URL happens synchronously in ScheduleUIUpdate.
2108
2109 if (flags & TabContents::INVALIDATE_LOAD)
2110 GetStatusBubble()->SetStatus(GetSelectedTabContents()->GetStatusText());
2111
2112 if (invalidate_tab) { // INVALIDATE_TITLE or INVALIDATE_FAVICON.
2113 tabstrip_model_.UpdateTabContentsStateAt(
2114 tabstrip_model_.GetIndexOfController(contents->controller()));
2115 window_->UpdateTitleBar();
2116
2117 if (contents == GetSelectedTabContents()) {
2118 TabContents* current_tab = GetSelectedTabContents();
2119 controller_.UpdateCommandEnabled(IDC_CREATE_SHORTCUT,
2120 current_tab->type() == TAB_CONTENTS_WEB &&
2121 !current_tab->GetFavIcon().isNull());
2122 }
2123 }
2124
2125 // We don't need to process INVALIDATE_STATE, since that's not visible.
2126 }
2127
2128 scheduled_updates_.clear();
2129}
2130
2131void Browser::RemoveScheduledUpdatesFor(TabContents* contents) {
2132 if (!contents)
2133 return;
2134
2135 // Remove any pending UI updates for the detached tab.
2136 UpdateVector::iterator cur_update = scheduled_updates_.begin();
2137 while (cur_update != scheduled_updates_.end()) {
2138 if (cur_update->source == contents) {
2139 cur_update = scheduled_updates_.erase(cur_update);
2140 } else {
2141 ++cur_update;
initial.commit09911bf2008-07-26 23:55:292142 }
2143 }
2144}
2145
[email protected]36b6dcb2008-11-12 01:19:572146///////////////////////////////////////////////////////////////////////////////
2147// Browser, Getters for UI (private):
initial.commit09911bf2008-07-26 23:55:292148
[email protected]36b6dcb2008-11-12 01:19:572149LocationBarView* Browser::GetLocationBarView() const {
2150 return window_->GetLocationBarView();
initial.commit09911bf2008-07-26 23:55:292151}
2152
2153GoButton* Browser::GetGoButton() {
[email protected]195442e2008-07-31 22:41:282154 return window_->GetGoButton();
initial.commit09911bf2008-07-26 23:55:292155}
2156
[email protected]36b6dcb2008-11-12 01:19:572157StatusBubble* Browser::GetStatusBubble() {
2158 return window_->GetStatusBubble();
initial.commit09911bf2008-07-26 23:55:292159}
2160
[email protected]36b6dcb2008-11-12 01:19:572161///////////////////////////////////////////////////////////////////////////////
2162// Browser, Session restore functions (private):
initial.commit09911bf2008-07-26 23:55:292163
2164void Browser::SyncHistoryWithTabs(int index) {
2165 if (!profile()->HasSessionService())
2166 return;
2167 SessionService* session_service = profile()->GetSessionService();
2168 if (session_service) {
2169 for (int i = index; i < tab_count(); ++i) {
2170 TabContents* contents = GetTabContentsAt(i);
2171 if (contents) {
2172 session_service->SetTabIndexInWindow(
2173 session_id(), contents->controller()->session_id(), i);
2174 }
2175 }
2176 }
2177}
2178
[email protected]36b6dcb2008-11-12 01:19:572179NavigationController* Browser::BuildRestoredNavigationController(
2180 const std::vector<TabNavigation>& navigations,
2181 int selected_navigation) {
2182 if (!navigations.empty()) {
2183 DCHECK(selected_navigation >= 0 &&
2184 selected_navigation < static_cast<int>(navigations.size()));
2185 // We should have a valid URL, if we don't fall back to the default.
2186 GURL url = navigations[selected_navigation].url;
2187 if (url.is_empty())
2188 url = GetHomePage();
2189
2190 // Create a NavigationController. This constructor creates the appropriate
2191 // set of TabContents.
[email protected]2d46c842008-11-14 19:24:312192 HWND parent_hwnd = reinterpret_cast<HWND>(window_->GetNativeHandle());
[email protected]36b6dcb2008-11-12 01:19:572193 return new NavigationController(
[email protected]2d46c842008-11-14 19:24:312194 profile_, navigations, selected_navigation, parent_hwnd);
[email protected]36b6dcb2008-11-12 01:19:572195 } else {
2196 // No navigations. Create a tab with about:blank.
2197 TabContents* contents =
2198 CreateTabContentsForURL(GURL("about:blank"), GURL(), profile_,
2199 PageTransition::START_PAGE, false, NULL);
2200 return new NavigationController(contents, profile_);
initial.commit09911bf2008-07-26 23:55:292201 }
2202}
2203
[email protected]36b6dcb2008-11-12 01:19:572204///////////////////////////////////////////////////////////////////////////////
2205// Browser, OnBeforeUnload handling (private):
initial.commit09911bf2008-07-26 23:55:292206
[email protected]04b4a6c2008-08-02 00:44:472207void Browser::ProcessPendingTabs() {
2208 DCHECK(is_attempting_to_close_browser_);
initial.commit09911bf2008-07-26 23:55:292209
[email protected]04b4a6c2008-08-02 00:44:472210 if (HasCompletedUnloadProcessing()) {
2211 // We've finished all the unload events and can proceed to close the
2212 // browser.
2213 OnWindowClosing();
initial.commit09911bf2008-07-26 23:55:292214 return;
2215 }
2216
[email protected]04b4a6c2008-08-02 00:44:472217 // Process beforeunload tabs first. When that queue is empty, process
2218 // unload tabs.
[email protected]04b4a6c2008-08-02 00:44:472219 if (!tabs_needing_before_unload_fired_.empty()) {
2220 TabContents* tab = tabs_needing_before_unload_fired_.back();
[email protected]1f5af4442008-09-25 22:11:062221 tab->AsWebContents()->render_view_host()->FirePageBeforeUnload();
[email protected]04b4a6c2008-08-02 00:44:472222 } else if (!tabs_needing_unload_fired_.empty()) {
initial.commit09911bf2008-07-26 23:55:292223 // We've finished firing all beforeunload events and can proceed with unload
2224 // events.
2225 // TODO(ojan): We should add a call to browser_shutdown::OnShutdownStarting
2226 // somewhere around here so that we have accurate measurements of shutdown
2227 // time.
[email protected]04b4a6c2008-08-02 00:44:472228 // TODO(ojan): We can probably fire all the unload events in parallel and
2229 // get a perf benefit from that in the cases where the tab hangs in it's
2230 // unload handler or takes a long time to page in.
2231 TabContents* tab = tabs_needing_unload_fired_.back();
[email protected]1f5af4442008-09-25 22:11:062232 tab->AsWebContents()->render_view_host()->FirePageUnload();
initial.commit09911bf2008-07-26 23:55:292233 } else {
[email protected]04b4a6c2008-08-02 00:44:472234 NOTREACHED();
initial.commit09911bf2008-07-26 23:55:292235 }
2236}
2237
[email protected]04b4a6c2008-08-02 00:44:472238bool Browser::HasCompletedUnloadProcessing() {
2239 return is_attempting_to_close_browser_ &&
2240 tabs_needing_before_unload_fired_.empty() &&
2241 tabs_needing_unload_fired_.empty();
2242}
2243
2244void Browser::CancelWindowClose() {
2245 DCHECK(is_attempting_to_close_browser_);
2246 // Only cancelling beforeunload should be able to cancel the window's close.
2247 // So there had better be a tab that we think needs beforeunload fired.
2248 DCHECK(!tabs_needing_before_unload_fired_.empty());
2249
[email protected]8f673f3a2008-08-05 22:34:282250 tabs_needing_before_unload_fired_.clear();
2251 tabs_needing_unload_fired_.clear();
[email protected]04b4a6c2008-08-02 00:44:472252
2253 is_attempting_to_close_browser_ = false;
2254}
2255
[email protected]2d46c842008-11-14 19:24:312256bool Browser::RemoveFromVector(UnloadListenerVector* vector,
2257 TabContents* tab) {
[email protected]04b4a6c2008-08-02 00:44:472258 DCHECK(is_attempting_to_close_browser_);
2259
2260 for (UnloadListenerVector::iterator it = vector->begin();
2261 it != vector->end();
2262 ++it) {
2263 if (*it == tab) {
2264 vector->erase(it);
2265 return true;
2266 }
2267 }
2268 return false;
2269}
initial.commit09911bf2008-07-26 23:55:292270
[email protected]36b6dcb2008-11-12 01:19:572271void Browser::ClearUnloadState(TabContents* tab) {
2272 DCHECK(is_attempting_to_close_browser_);
2273 RemoveFromVector(&tabs_needing_before_unload_fired_, tab);
2274 RemoveFromVector(&tabs_needing_unload_fired_, tab);
2275 ProcessPendingTabs();
initial.commit09911bf2008-07-26 23:55:292276}
2277
[email protected]36b6dcb2008-11-12 01:19:572278///////////////////////////////////////////////////////////////////////////////
2279// Browser, Assorted utility functions (private):
initial.commit09911bf2008-07-26 23:55:292280
initial.commit09911bf2008-07-26 23:55:292281Browser* Browser::GetOrCreateTabbedBrowser() {
2282 Browser* browser = BrowserList::FindBrowserWithType(
2283 profile_, BrowserType::TABBED_BROWSER);
[email protected]15952e462008-11-14 00:29:052284 if (!browser)
2285 browser = Browser::Create(profile_);
initial.commit09911bf2008-07-26 23:55:292286 return browser;
2287}
2288
initial.commit09911bf2008-07-26 23:55:292289void Browser::BuildPopupWindow(TabContents* source,
2290 TabContents* new_contents,
2291 const gfx::Rect& initial_pos) {
[email protected]a0e073f2008-08-24 18:25:112292 BrowserType::Type type =
2293 type_ == BrowserType::APPLICATION ? type_ : BrowserType::BROWSER;
[email protected]15952e462008-11-14 00:29:052294 Browser* browser = new Browser(type, profile_);
2295 browser->set_override_bounds(initial_pos);
2296 browser->CreateBrowserWindow();
2297 // TODO(beng): See if this can be made to use
2298 // TabStripModel::AppendTabContents.
2299 browser->AddNewContents(source, new_contents, NEW_FOREGROUND_TAB,
2300 gfx::Rect(), true);
2301 browser->window()->Show();
initial.commit09911bf2008-07-26 23:55:292302}
2303
[email protected]36b6dcb2008-11-12 01:19:572304GURL Browser::GetHomePage() {
[email protected]15952e462008-11-14 00:29:052305 if (profile_->GetPrefs()->GetBoolean(prefs::kHomePageIsNewTabPage))
[email protected]36b6dcb2008-11-12 01:19:572306 return NewTabUIURL();
[email protected]15952e462008-11-14 00:29:052307 GURL home_page = GURL(URLFixerUpper::FixupURL(
2308 profile_->GetPrefs()->GetString(prefs::kHomePage),
2309 std::wstring()));
2310 if (!home_page.is_valid())
2311 return NewTabUIURL();
2312 return home_page;
[email protected]36b6dcb2008-11-12 01:19:572313}
initial.commit09911bf2008-07-26 23:55:292314
[email protected]fbd77592008-11-12 20:50:272315void Browser::AdvanceFindSelection(bool forward_direction) {
2316 GetSelectedTabContents()->AsWebContents()->view()->FindInPage(
2317 *this, true, forward_direction);
2318}
2319
[email protected]36b6dcb2008-11-12 01:19:572320void Browser::CloseFrame() {
2321 window_->Close();
initial.commit09911bf2008-07-26 23:55:292322}
2323
2324// static
2325std::wstring Browser::ComputeApplicationNameFromURL(const GURL& url) {
2326 std::string t;
2327 t.append(url.host());
2328 t.append("_");
2329 t.append(url.path());
2330 return UTF8ToWide(t);
2331}
2332
2333// static
initial.commit09911bf2008-07-26 23:55:292334void Browser::RegisterAppPrefs(const std::wstring& app_name) {
2335 // A set of apps that we've already started.
2336 static std::set<std::wstring>* g_app_names = NULL;
2337
2338 if (!g_app_names)
2339 g_app_names = new std::set<std::wstring>;
2340
2341 // Only register once for each app name.
2342 if (g_app_names->find(app_name) != g_app_names->end())
2343 return;
2344 g_app_names->insert(app_name);
2345
2346 // We need to register the window position pref.
2347 std::wstring window_pref(prefs::kBrowserWindowPlacement);
2348 window_pref.append(L"_");
2349 window_pref.append(app_name);
2350 PrefService* prefs = g_browser_process->local_state();
2351 DCHECK(prefs);
2352
2353 prefs->RegisterDictionaryPref(window_pref.c_str());
2354}