blob: 6f5cb5904daaa93ffff0ee582a174a832b2222d2 [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]5e495462008-11-20 23:07:4125#include "chrome/browser/dock_info.h"
[email protected]2baf83d2008-07-30 05:58:1726#include "chrome/browser/dom_ui/new_tab_ui.h"
[email protected]37936ee2008-09-14 01:09:5027#include "chrome/browser/download/save_package.h"
[email protected]36b6dcb2008-11-12 01:19:5728#include "chrome/browser/history_tab_ui.h"
29#include "chrome/browser/interstitial_page.h"
initial.commit09911bf2008-07-26 23:55:2930#include "chrome/browser/navigation_controller.h"
31#include "chrome/browser/navigation_entry.h"
[email protected]36b6dcb2008-11-12 01:19:5732#include "chrome/browser/options_window.h"
initial.commit09911bf2008-07-26 23:55:2933#include "chrome/browser/plugin_process_host.h"
34#include "chrome/browser/plugin_service.h"
35#include "chrome/browser/profile.h"
[email protected]169627b2008-12-06 19:30:1936#include "chrome/browser/sessions/session_service.h"
initial.commit09911bf2008-07-26 23:55:2937#include "chrome/browser/ssl_error_info.h"
38#include "chrome/browser/site_instance.h"
[email protected]36b6dcb2008-11-12 01:19:5739#include "chrome/browser/task_manager.h"
initial.commit09911bf2008-07-26 23:55:2940#include "chrome/browser/url_fixer_upper.h"
[email protected]f2530062008-12-03 23:52:0341#include "chrome/browser/user_data_manager.h"
initial.commit09911bf2008-07-26 23:55:2942#include "chrome/browser/user_metrics.h"
43#include "chrome/browser/view_ids.h"
[email protected]36b6dcb2008-11-12 01:19:5744#include "chrome/browser/views/download_tab_view.h"
45#include "chrome/browser/views/go_button.h"
initial.commit09911bf2008-07-26 23:55:2946#include "chrome/browser/views/location_bar_view.h"
[email protected]f2530062008-12-03 23:52:0347#include "chrome/browser/views/new_profile_dialog.h"
48#include "chrome/browser/views/select_profile_dialog.h"
[email protected]012d2fb2008-09-13 01:30:0549#include "chrome/browser/views/status_bubble.h"
initial.commit09911bf2008-07-26 23:55:2950#include "chrome/browser/views/toolbar_star_toggle.h"
[email protected]807bfce2008-10-14 16:42:2551#include "chrome/browser/web_contents_view.h"
initial.commit09911bf2008-07-26 23:55:2952#include "chrome/browser/window_sizer.h"
53#include "chrome/common/chrome_constants.h"
54#include "chrome/common/chrome_switches.h"
55#include "chrome/common/l10n_util.h"
56#include "chrome/common/pref_names.h"
57#include "chrome/common/pref_service.h"
[email protected]1eb89e82008-08-15 12:27:0358#include "chrome/common/win_util.h"
initial.commit09911bf2008-07-26 23:55:2959#include "net/base/cookie_monster.h"
60#include "net/base/cookie_policy.h"
61#include "net/base/net_util.h"
62#include "net/base/registry_controlled_domain.h"
63
[email protected]b08de9cd2008-08-27 23:40:2264#include "chromium_strings.h"
initial.commit09911bf2008-07-26 23:55:2965#include "generated_resources.h"
66
[email protected]e1acf6f2008-10-27 20:43:3367using base::TimeDelta;
68
initial.commit09911bf2008-07-26 23:55:2969static BrowserList g_browserlist;
70
71// How long we wait before updating the browser chrome while loading a page.
72static const int kUIUpdateCoalescingTimeMS = 200;
73
74// Idle time before helping prune memory consumption.
75static const int kBrowserReleaseMemoryInterval = 30; // In seconds.
76
77// How much horizontal and vertical offset there is between newly opened
78// windows.
[email protected]eb0c1e42008-08-04 17:58:0079static const int kWindowTilePixels = 20;
initial.commit09911bf2008-07-26 23:55:2980
[email protected]36b6dcb2008-11-12 01:19:5781///////////////////////////////////////////////////////////////////////////////
initial.commit09911bf2008-07-26 23:55:2982
83// A task to reduce the working set of the plugins.
84class ReducePluginsWorkingSetTask : public Task {
85 public:
86 virtual void Run() {
87 for (PluginProcessHostIterator iter; !iter.Done(); ++iter) {
88 PluginProcessHost* plugin = const_cast<PluginProcessHost*>(*iter);
89 DCHECK(plugin->process());
[email protected]176aa482008-11-14 03:25:1590 base::Process process(plugin->process());
initial.commit09911bf2008-07-26 23:55:2991 process.ReduceWorkingSet();
92 }
93 }
94};
95
96// A browser task to run when the user is not using the browser.
97// In our case, we're trying to be nice to the operating system and release
98// memory not in use.
[email protected]aeab57ea2008-08-28 20:50:1299class BrowserIdleTimer : public base::IdleTimer {
initial.commit09911bf2008-07-26 23:55:29100 public:
[email protected]aeab57ea2008-08-28 20:50:12101 BrowserIdleTimer()
102 : base::IdleTimer(TimeDelta::FromSeconds(kBrowserReleaseMemoryInterval),
103 false) {
initial.commit09911bf2008-07-26 23:55:29104 }
105
106 virtual void OnIdle() {
107 // We're idle. Release browser and renderer unused pages.
108
109 // Handle the Browser.
[email protected]176aa482008-11-14 03:25:15110 base::Process process(GetCurrentProcess());
initial.commit09911bf2008-07-26 23:55:29111 process.ReduceWorkingSet();
112
113 // Handle the Renderer(s).
114 RenderProcessHost::iterator renderer_iter;
115 for (renderer_iter = RenderProcessHost::begin(); renderer_iter !=
[email protected]176aa482008-11-14 03:25:15116 RenderProcessHost::end(); renderer_iter++) {
117 base::Process process = renderer_iter->second->process();
initial.commit09911bf2008-07-26 23:55:29118 process.ReduceWorkingSet();
119 }
120
[email protected]36b6dcb2008-11-12 01:19:57121 // Handle the Plugin(s). We need to iterate through the plugin processes
122 // on the IO thread because that thread manages the plugin process
123 // collection.
initial.commit09911bf2008-07-26 23:55:29124 g_browser_process->io_thread()->message_loop()->PostTask(FROM_HERE,
125 new ReducePluginsWorkingSetTask());
126 }
127};
128
[email protected]36b6dcb2008-11-12 01:19:57129///////////////////////////////////////////////////////////////////////////////
initial.commit09911bf2008-07-26 23:55:29130
131struct Browser::UIUpdate {
132 UIUpdate(const TabContents* src, unsigned flags)
133 : source(src),
134 changed_flags(flags) {
135 }
136
137 // The source of the update.
138 const TabContents* source;
139
140 // What changed in the UI.
141 unsigned changed_flags;
142};
143
[email protected]36b6dcb2008-11-12 01:19:57144///////////////////////////////////////////////////////////////////////////////
145// Browser, Constructors, Creation, Showing:
initial.commit09911bf2008-07-26 23:55:29146
[email protected]299dabd2008-11-19 02:27:16147Browser::Browser(Type type, Profile* profile)
[email protected]15952e462008-11-14 00:29:05148 : type_(type),
149 profile_(profile),
[email protected]f3e99e32008-07-30 04:48:39150 window_(NULL),
initial.commit09911bf2008-07-26 23:55:29151 tabstrip_model_(this, profile),
[email protected]15952e462008-11-14 00:29:05152 controller_(this),
initial.commit09911bf2008-07-26 23:55:29153 toolbar_model_(this),
[email protected]15952e462008-11-14 00:29:05154 chrome_updater_factory_(this),
155 is_attempting_to_close_browser_(false),
156 override_maximized_(false),
157 method_factory_(this),
158 idle_task_(new BrowserIdleTimer) {
initial.commit09911bf2008-07-26 23:55:29159 tabstrip_model_.AddObserver(this);
160
[email protected]e83f1682008-09-07 23:57:40161 NotificationService::current()->AddObserver(
162 this, NOTIFY_SSL_STATE_CHANGED, NotificationService::AllSources());
initial.commit09911bf2008-07-26 23:55:29163
initial.commit09911bf2008-07-26 23:55:29164 InitCommandState();
165 BrowserList::AddBrowser(this);
166
167 encoding_auto_detect_.Init(prefs::kWebKitUsesUniversalDetector,
168 profile_->GetPrefs(), NULL);
169
170 // Trim browser memory on idle for low & medium memory models.
171 if (g_browser_process->memory_model() < BrowserProcess::HIGH_MEMORY_MODEL)
172 idle_task_->Start();
initial.commit09911bf2008-07-26 23:55:29173}
174
175Browser::~Browser() {
176 // The tab strip should be empty at this point.
177 DCHECK(tabstrip_model_.empty());
178 tabstrip_model_.RemoveObserver(this);
179
180 BrowserList::RemoveBrowser(this);
181
182 if (!BrowserList::HasBrowserWithProfile(profile_)) {
183 // We're the last browser window with this profile. We need to nuke the
184 // TabRestoreService, which will start the shutdown of the
185 // NavigationControllers and allow for proper shutdown. If we don't do this
186 // chrome won't shutdown cleanly, and may end up crashing when some
187 // thread tries to use the IO thread (or another thread) that is no longer
188 // valid.
189 profile_->ResetTabRestoreService();
190 }
191
192 SessionService* session_service = profile_->GetSessionService();
193 if (session_service)
194 session_service->WindowClosed(session_id_);
195
[email protected]d8375fd2008-11-25 22:45:39196 TabRestoreService* tab_restore_service = profile()->GetTabRestoreService();
197 if (tab_restore_service)
198 tab_restore_service->BrowserClosed(this);
199
[email protected]e83f1682008-09-07 23:57:40200 NotificationService::current()->RemoveObserver(
201 this, NOTIFY_SSL_STATE_CHANGED, NotificationService::AllSources());
initial.commit09911bf2008-07-26 23:55:29202
initial.commit09911bf2008-07-26 23:55:29203 if (profile_->IsOffTheRecord() &&
204 !BrowserList::IsOffTheRecordSessionActive()) {
205 // We reuse the OTR cookie store across OTR windows. If the last OTR
206 // window is closed, then we want to wipe the cookie store clean, so when
207 // an OTR window is open again, it starts with an empty cookie store. This
208 // also frees up the memory that the OTR cookies were using. OTR never
209 // loads or writes persistent cookies (there is no backing store), so we
210 // can just delete all of the cookies in the store.
211 profile_->GetRequestContext()->cookie_store()->DeleteAll(false);
212 }
213
214 // There may be pending file dialogs, we need to tell them that we've gone
215 // away so they don't try and call back to us.
216 if (select_file_dialog_.get())
217 select_file_dialog_->ListenerDestroyed();
218}
219
[email protected]15952e462008-11-14 00:29:05220// static
221Browser* Browser::Create(Profile* profile) {
[email protected]299dabd2008-11-19 02:27:16222 Browser* browser = new Browser(TYPE_NORMAL, profile);
[email protected]15952e462008-11-14 00:29:05223 browser->CreateBrowserWindow();
224 return browser;
225}
[email protected]6104acf2008-11-11 22:27:34226
[email protected]15952e462008-11-14 00:29:05227// static
228Browser* Browser::CreateForPopup(Profile* profile) {
[email protected]299dabd2008-11-19 02:27:16229 Browser* browser = new Browser(TYPE_POPUP, profile);
[email protected]15952e462008-11-14 00:29:05230 browser->CreateBrowserWindow();
231 return browser;
232}
233
234// static
235Browser* Browser::CreateForApp(const std::wstring& app_name,
236 Profile* profile) {
[email protected]299dabd2008-11-19 02:27:16237 Browser* browser = new Browser(TYPE_APP, profile);
[email protected]15952e462008-11-14 00:29:05238 browser->app_name_ = app_name;
239 browser->CreateBrowserWindow();
240 return browser;
241}
242
243void Browser::CreateBrowserWindow() {
244 DCHECK(!window_);
245 window_ = BrowserWindow::CreateBrowserWindow(this);
246
247 // Show the First Run information bubble if we've been told to.
248 PrefService* local_state = g_browser_process->local_state();
[email protected]be3877f2009-01-14 15:51:10249 if (!local_state)
250 return;
[email protected]15952e462008-11-14 00:29:05251 if (local_state->IsPrefRegistered(prefs::kShouldShowFirstRunBubble) &&
252 local_state->GetBoolean(prefs::kShouldShowFirstRunBubble)) {
253 // Reset the preference so we don't show the bubble for subsequent windows.
254 local_state->ClearPref(prefs::kShouldShowFirstRunBubble);
255 GetLocationBarView()->ShowFirstRunBubble();
initial.commit09911bf2008-07-26 23:55:29256 }
initial.commit09911bf2008-07-26 23:55:29257}
258
[email protected]36b6dcb2008-11-12 01:19:57259///////////////////////////////////////////////////////////////////////////////
260// Browser, Creation Helpers:
261
262// static
[email protected]15952e462008-11-14 00:29:05263void Browser::OpenEmptyWindow(Profile* profile) {
264 Browser* browser = Browser::Create(profile);
[email protected]36b6dcb2008-11-12 01:19:57265 browser->AddBlankTab(true);
[email protected]15952e462008-11-14 00:29:05266 browser->window()->Show();
initial.commit09911bf2008-07-26 23:55:29267}
268
[email protected]36b6dcb2008-11-12 01:19:57269// static
270void Browser::OpenURLOffTheRecord(Profile* profile, const GURL& url) {
271 Profile* off_the_record_profile = profile->GetOffTheRecordProfile();
272 Browser* browser = BrowserList::FindBrowserWithType(
[email protected]15952e462008-11-14 00:29:05273 off_the_record_profile,
[email protected]299dabd2008-11-19 02:27:16274 TYPE_NORMAL);
[email protected]15952e462008-11-14 00:29:05275 if (!browser)
276 browser = Browser::Create(off_the_record_profile);
[email protected]36b6dcb2008-11-12 01:19:57277 // TODO(eroman): should we have referrer here?
278 browser->AddTabWithURL(url, GURL(), PageTransition::LINK, true, NULL);
[email protected]15952e462008-11-14 00:29:05279 browser->window()->Show();
[email protected]2baf83d2008-07-30 05:58:17280}
281
[email protected]36b6dcb2008-11-12 01:19:57282// static
[email protected]15952e462008-11-14 00:29:05283void Browser::OpenWebApplication(Profile* profile, WebApp* app) {
[email protected]36b6dcb2008-11-12 01:19:57284 const std::wstring& app_name =
285 app->name().empty() ? ComputeApplicationNameFromURL(app->url()) :
286 app->name();
[email protected]36b6dcb2008-11-12 01:19:57287 RegisterAppPrefs(app_name);
[email protected]15952e462008-11-14 00:29:05288
289 Browser* browser = Browser::CreateForApp(app_name, profile);
[email protected]36b6dcb2008-11-12 01:19:57290 browser->AddWebApplicationTab(profile, app, false);
[email protected]15952e462008-11-14 00:29:05291 browser->window()->Show();
initial.commit09911bf2008-07-26 23:55:29292}
293
[email protected]36b6dcb2008-11-12 01:19:57294///////////////////////////////////////////////////////////////////////////////
295// Browser, Command API:
initial.commit09911bf2008-07-26 23:55:29296
[email protected]36b6dcb2008-11-12 01:19:57297bool Browser::SupportsCommand(int id) const {
298 return controller_.SupportsCommand(id);
initial.commit09911bf2008-07-26 23:55:29299}
300
[email protected]36b6dcb2008-11-12 01:19:57301bool Browser::IsCommandEnabled(int id) const {
[email protected]5b0295eb2f2008-11-16 03:03:13302 // No commands are enabled if there is not yet any selected tab.
[email protected]e673f6c2008-12-09 21:24:11303 // TODO(pkasting): It seems like we should not need this, because either
304 // most/all commands should not have been enabled yet anyway or the ones that
305 // are enabled should be global, or safe themselves against having no selected
306 // tab. However, Ben says he tried removing this before and got lots of
307 // crashes, e.g. from Windows sending WM_COMMANDs at random times during
308 // window construction. This probably could use closer examination someday.
[email protected]5b0295eb2f2008-11-16 03:03:13309 if (!GetSelectedTabContents())
310 return false;
311
[email protected]c7c42332008-11-15 01:10:54312 return controller_.IsCommandEnabled(id);
[email protected]36b6dcb2008-11-12 01:19:57313}
314
315///////////////////////////////////////////////////////////////////////////////
[email protected]36b6dcb2008-11-12 01:19:57316// Browser, State Storage and Retrieval for UI:
317
[email protected]bc9a5152008-11-15 00:32:04318std::wstring Browser::GetWindowPlacementKey() const {
[email protected]36b6dcb2008-11-12 01:19:57319 std::wstring name(prefs::kBrowserWindowPlacement);
320 if (!app_name_.empty()) {
321 name.append(L"_");
322 name.append(app_name_);
323 }
[email protected]bc9a5152008-11-15 00:32:04324 return name;
325}
[email protected]36b6dcb2008-11-12 01:19:57326
[email protected]bc9a5152008-11-15 00:32:04327bool Browser::ShouldSaveWindowPlacement() const {
328 // We don't save window position for popups.
[email protected]299dabd2008-11-19 02:27:16329 return type() != TYPE_POPUP;
[email protected]bc9a5152008-11-15 00:32:04330}
[email protected]36b6dcb2008-11-12 01:19:57331
[email protected]bc9a5152008-11-15 00:32:04332void Browser::SaveWindowPlacement(const gfx::Rect& bounds, bool maximized) {
333 // Save to the session storage service, used when reloading a past session.
334 // Note that we don't want to be the ones who cause lazy initialization of
335 // the session service. This function gets called during initial window
336 // showing, and we don't want to bring in the session service this early.
[email protected]36b6dcb2008-11-12 01:19:57337 if (profile()->HasSessionService()) {
338 SessionService* session_service = profile()->GetSessionService();
339 if (session_service)
340 session_service->SetWindowBounds(session_id_, bounds, maximized);
341 }
342}
343
[email protected]15952e462008-11-14 00:29:05344gfx::Rect Browser::GetSavedWindowBounds() const {
345 CommandLine parsed_command_line;
346 bool record_mode = parsed_command_line.HasSwitch(switches::kRecordMode);
347 bool playback_mode = parsed_command_line.HasSwitch(switches::kPlaybackMode);
348 if (record_mode || playback_mode) {
349 // In playback/record mode we always fix the size of the browser and
350 // move it to (0,0). The reason for this is two reasons: First we want
351 // resize/moves in the playback to still work, and Second we want
352 // playbacks to work (as much as possible) on machines w/ different
353 // screen sizes.
354 return gfx::Rect(0, 0, 800, 600);
355 }
356
357 gfx::Rect restored_bounds = override_bounds_;
358 bool maximized;
359 WindowSizer::GetBrowserWindowBounds(app_name_, restored_bounds,
360 &restored_bounds, &maximized);
361 return restored_bounds;
362}
363
364// TODO(beng): obtain maximized state some other way so we don't need to go
365// through all this hassle.
366bool Browser::GetSavedMaximizedState() const {
367 if (CommandLine().HasSwitch(switches::kStartMaximized))
368 return true;
369
370 gfx::Rect restored_bounds;
371 bool maximized = override_maximized_;
372 WindowSizer::GetBrowserWindowBounds(app_name_, restored_bounds,
373 &restored_bounds, &maximized);
374 return maximized;
[email protected]36b6dcb2008-11-12 01:19:57375}
376
377SkBitmap Browser::GetCurrentPageIcon() const {
[email protected]ce5348a82008-12-18 18:36:23378 TabContents* contents = GetSelectedTabContents();
379 // |contents| can be NULL since GetCurrentPageIcon() is called by the window
380 // during the window's creation (before tabs have been added).
381 return contents ? contents->GetFavIcon() : SkBitmap();
[email protected]36b6dcb2008-11-12 01:19:57382}
383
384std::wstring Browser::GetCurrentPageTitle() const {
385 TabContents* contents = tabstrip_model_.GetSelectedTabContents();
386 std::wstring title;
[email protected]c7c42332008-11-15 01:10:54387
388 // |contents| can be NULL because GetCurrentPageTitle is called by the window
389 // during the window's creation (before tabs have been added).
[email protected]36b6dcb2008-11-12 01:19:57390 if (contents) {
391 title = contents->GetTitle();
392 FormatTitleForDisplay(&title);
393 }
394 if (title.empty())
395 title = l10n_util::GetString(IDS_TAB_UNTITLED_TITLE);
396
397 return l10n_util::GetStringF(IDS_BROWSER_WINDOW_TITLE_FORMAT, title);
398}
399
400// static
401void Browser::FormatTitleForDisplay(std::wstring* title) {
402 size_t current_index = 0;
403 size_t match_index;
404 while ((match_index = title->find(L'\n', current_index)) !=
405 std::wstring::npos) {
406 title->replace(match_index, 1, L"");
407 current_index = match_index;
408 }
409}
410
411///////////////////////////////////////////////////////////////////////////////
412// Browser, OnBeforeUnload handling:
413
414bool Browser::ShouldCloseWindow() {
415 if (HasCompletedUnloadProcessing()) {
416 return true;
417 }
418 is_attempting_to_close_browser_ = true;
419
420 for (int i = 0; i < tab_count(); ++i) {
421 if (tabstrip_model_.TabHasUnloadListener(i)) {
422 TabContents* tab = GetTabContentsAt(i);
[email protected]06b42f032008-12-03 18:43:05423 tabs_needing_before_unload_fired_.insert(tab);
[email protected]36b6dcb2008-11-12 01:19:57424 }
425 }
426
427 if (tabs_needing_before_unload_fired_.empty())
428 return true;
429
430 ProcessPendingTabs();
431 return false;
432}
433
434void Browser::OnWindowClosing() {
435 if (!ShouldCloseWindow())
436 return;
437
438 if (BrowserList::size() == 1)
439 browser_shutdown::OnShutdownStarting(browser_shutdown::WINDOW_CLOSE);
440
441 // Don't use HasSessionService here, we want to force creation of the
442 // session service so that user can restore what was open.
443 SessionService* session_service = profile()->GetSessionService();
444 if (session_service)
445 session_service->WindowClosing(session_id());
446
[email protected]d8375fd2008-11-25 22:45:39447 TabRestoreService* tab_restore_service = profile()->GetTabRestoreService();
448 if (tab_restore_service)
449 tab_restore_service->BrowserClosing(this);
450
[email protected]36b6dcb2008-11-12 01:19:57451 CloseAllTabs();
452}
453
454///////////////////////////////////////////////////////////////////////////////
[email protected]36b6dcb2008-11-12 01:19:57455// Browser, Tab adding/showing functions:
456
457TabContents* Browser::AddTabWithURL(
458 const GURL& url, const GURL& referrer, PageTransition::Type transition,
459 bool foreground, SiteInstance* instance) {
[email protected]299dabd2008-11-19 02:27:16460 if (type_ == TYPE_APP && tabstrip_model_.count() == 1) {
[email protected]36b6dcb2008-11-12 01:19:57461 NOTREACHED() << "Cannot add a tab in a mono tab application.";
462 return NULL;
463 }
464
465 GURL url_to_load = url;
466 if (url_to_load.is_empty())
467 url_to_load = GetHomePage();
468 TabContents* contents =
469 CreateTabContentsForURL(url_to_load, referrer, profile_, transition,
470 false, instance);
471 tabstrip_model_.AddTabContents(contents, -1, transition, foreground);
472 // By default, content believes it is not hidden. When adding contents
473 // in the background, tell it that it's hidden.
474 if (!foreground)
475 contents->WasHidden();
476 return contents;
477}
478
479TabContents* Browser::AddWebApplicationTab(Profile* profile,
480 WebApp* web_app,
481 bool lazy) {
482 DCHECK(web_app);
483
484 // TODO(acw): Do we need an "application launched" transition type?
485 // TODO(creis): Should we reuse the current instance (ie. process) here?
486 TabContents* contents =
487 CreateTabContentsForURL(web_app->url(), GURL(), profile,
488 PageTransition::LINK, lazy, NULL);
[email protected]64ff7942008-12-17 18:11:23489 WebContents* web_contents = contents->AsWebContents();
490 if (web_contents)
491 web_contents->SetWebApp(web_app);
[email protected]36b6dcb2008-11-12 01:19:57492
493 if (lazy) {
494 contents->controller()->LoadURLLazily(
495 web_app->url(), GURL(), PageTransition::LINK, web_app->name(), NULL);
496 }
497 tabstrip_model_.AddTabContents(contents, -1, PageTransition::LINK, !lazy);
498 return contents;
499}
500
501TabContents* Browser::AddTabWithNavigationController(
502 NavigationController* ctrl, PageTransition::Type type) {
503 TabContents* tc = ctrl->active_contents();
504 tabstrip_model_.AddTabContents(tc, -1, type, true);
505 return tc;
506}
507
508NavigationController* Browser::AddRestoredTab(
509 const std::vector<TabNavigation>& navigations,
510 int tab_index,
511 int selected_navigation,
512 bool select) {
513 NavigationController* restored_controller =
514 BuildRestoredNavigationController(navigations, selected_navigation);
515
516 tabstrip_model_.InsertTabContentsAt(
517 tab_index,
518 restored_controller->active_contents(),
519 select, false);
520 if (profile_->HasSessionService()) {
521 SessionService* session_service = profile_->GetSessionService();
522 if (session_service)
523 session_service->TabRestored(restored_controller);
524 }
525 return restored_controller;
526}
527
528void Browser::ReplaceRestoredTab(
529 const std::vector<TabNavigation>& navigations,
530 int selected_navigation) {
531 NavigationController* restored_controller =
532 BuildRestoredNavigationController(navigations, selected_navigation);
533
534 tabstrip_model_.ReplaceNavigationControllerAt(
535 tabstrip_model_.selected_index(),
536 restored_controller);
537}
538
539void Browser::ShowNativeUITab(const GURL& url) {
540 int i, c;
541 TabContents* tc;
542 for (i = 0, c = tabstrip_model_.count(); i < c; ++i) {
543 tc = tabstrip_model_.GetTabContentsAt(i);
544 if (tc->type() == TAB_CONTENTS_NATIVE_UI &&
545 tc->GetURL() == url) {
546 tabstrip_model_.SelectTabContentsAt(i, false);
547 return;
548 }
549 }
550
551 TabContents* contents = CreateTabContentsForURL(url, GURL(), profile_,
552 PageTransition::LINK, false,
553 NULL);
554 AddNewContents(NULL, contents, NEW_FOREGROUND_TAB, gfx::Rect(), true);
555}
556
557///////////////////////////////////////////////////////////////////////////////
558// Browser, Assorted browser commands:
559
560void Browser::GoBack() {
[email protected]fbd77592008-11-12 20:50:27561 UserMetrics::RecordAction(L"Back", profile_);
562
[email protected]36b6dcb2008-11-12 01:19:57563 // If we are showing an interstitial, just hide it.
564 TabContents* current_tab = GetSelectedTabContents();
[email protected]c7c42332008-11-15 01:10:54565 WebContents* web_contents = current_tab->AsWebContents();
[email protected]a3a1d142008-12-19 00:42:30566 if (web_contents && web_contents->interstitial_page()) {
567 // The GoBack() case is a special case when an interstitial is shown because
568 // the "previous" page is still available, just hidden by the interstitial.
569 // We treat the back as a "Don't proceed", this hides the interstitial and
570 // reveals the previous page.
[email protected]c7c42332008-11-15 01:10:54571 web_contents->interstitial_page()->DontProceed();
572 return;
[email protected]36b6dcb2008-11-12 01:19:57573 }
[email protected]c7c42332008-11-15 01:10:54574 if (current_tab->controller()->CanGoBack())
575 current_tab->controller()->GoBack();
[email protected]36b6dcb2008-11-12 01:19:57576}
577
578void Browser::GoForward() {
[email protected]fbd77592008-11-12 20:50:27579 UserMetrics::RecordAction(L"Forward", profile_);
[email protected]c7c42332008-11-15 01:10:54580 if (GetSelectedTabContents()->controller()->CanGoForward())
581 GetSelectedTabContents()->controller()->GoForward();
[email protected]36b6dcb2008-11-12 01:19:57582}
583
584void Browser::Reload() {
[email protected]fbd77592008-11-12 20:50:27585 UserMetrics::RecordAction(L"Reload", profile_);
586
[email protected]36b6dcb2008-11-12 01:19:57587 // If we are showing an interstitial, treat this as an OpenURL.
588 TabContents* current_tab = GetSelectedTabContents();
589 if (current_tab) {
590 WebContents* web_contents = current_tab->AsWebContents();
591 if (web_contents && web_contents->showing_interstitial_page()) {
592 NavigationEntry* entry = current_tab->controller()->GetActiveEntry();
593 DCHECK(entry); // Should exist if interstitial is showing.
594 OpenURL(entry->url(), GURL(), CURRENT_TAB, PageTransition::RELOAD);
595 return;
596 }
597 }
598
599 if (current_tab) {
600 // As this is caused by a user action, give the focus to the page.
601 current_tab->Focus();
602 current_tab->controller()->Reload(true);
603 }
604}
605
[email protected]36b6dcb2008-11-12 01:19:57606void Browser::Home() {
[email protected]fbd77592008-11-12 20:50:27607 UserMetrics::RecordAction(L"Home", profile_);
[email protected]36b6dcb2008-11-12 01:19:57608 GURL homepage_url = GetHomePage();
609 GetSelectedTabContents()->controller()->LoadURL(
610 homepage_url, GURL(), PageTransition::AUTO_BOOKMARK);
611}
612
[email protected]fbd77592008-11-12 20:50:27613void Browser::OpenCurrentURL() {
614 UserMetrics::RecordAction(L"LoadURL", profile_);
615 LocationBarView* lbv = GetLocationBarView();
616 if (lbv) {
617 OpenURL(GURL(lbv->location_input()), GURL(), lbv->disposition(),
618 lbv->transition());
[email protected]fbd77592008-11-12 20:50:27619 }
620}
621
[email protected]84214982008-12-10 18:49:10622void Browser::Go() {
623 UserMetrics::RecordAction(L"Go", profile_);
624 LocationBarView* lbv = GetLocationBarView();
625 if (lbv)
626 lbv->location_entry()->model()->AcceptInput(CURRENT_TAB, false);
627}
628
629void Browser::Stop() {
630 UserMetrics::RecordAction(L"Stop", profile_);
[email protected]0daf94732008-12-17 01:08:33631 GetSelectedTabContents()->Stop();
[email protected]84214982008-12-10 18:49:10632}
633
634void Browser::NewWindow() {
635 UserMetrics::RecordAction(L"NewWindow", profile_);
636 Browser::OpenEmptyWindow(profile_->GetOriginalProfile());
637}
638
639void Browser::NewIncognitoWindow() {
640 UserMetrics::RecordAction(L"NewIncognitoWindow", profile_);
641 Browser::OpenEmptyWindow(profile_->GetOffTheRecordProfile());
642}
643
644void Browser::NewProfileWindowByIndex(int index) {
645 UserMetrics::RecordAction(L"NewProfileWindowByIndex", profile_);
646 UserDataManager::Get()->LaunchChromeForProfile(index);
647}
648
649void Browser::CloseWindow() {
650 UserMetrics::RecordAction(L"CloseWindow", profile_);
651 window_->Close();
652}
653
[email protected]fbd77592008-11-12 20:50:27654void Browser::NewTab() {
655 UserMetrics::RecordAction(L"NewTab", profile_);
[email protected]299dabd2008-11-19 02:27:16656 if (type() == TYPE_NORMAL) {
[email protected]fbd77592008-11-12 20:50:27657 AddBlankTab(true);
658 } else {
659 Browser* b = GetOrCreateTabbedBrowser();
[email protected]fbd77592008-11-12 20:50:27660 b->AddBlankTab(true);
[email protected]15952e462008-11-14 00:29:05661 b->window()->Show();
[email protected]fbd77592008-11-12 20:50:27662 }
663}
664
665void Browser::CloseTab() {
666 UserMetrics::RecordAction(L"CloseTab_Accelerator", profile_);
667 tabstrip_model_.CloseTabContentsAt(tabstrip_model_.selected_index());
668}
669
[email protected]fbd77592008-11-12 20:50:27670void Browser::SelectNextTab() {
671 UserMetrics::RecordAction(L"SelectNextTab", profile_);
672 tabstrip_model_.SelectNextTab();
673}
674
675void Browser::SelectPreviousTab() {
676 UserMetrics::RecordAction(L"SelectPrevTab", profile_);
677 tabstrip_model_.SelectPreviousTab();
678}
679
680void Browser::SelectNumberedTab(int index) {
681 if (index < tab_count()) {
682 UserMetrics::RecordAction(L"SelectNumberedTab", profile_);
683 tabstrip_model_.SelectTabContentsAt(index, true);
684 }
685}
686
687void Browser::SelectLastTab() {
688 UserMetrics::RecordAction(L"SelectLastTab", profile_);
689 tabstrip_model_.SelectLastTab();
690}
691
692void Browser::DuplicateTab() {
693 UserMetrics::RecordAction(L"Duplicate", profile_);
694 DuplicateContentsAt(selected_index());
695}
696
697void Browser::RestoreTab() {
698 UserMetrics::RecordAction(L"RestoreTab", profile_);
699 TabRestoreService* service = profile_->GetTabRestoreService();
700 if (!service)
701 return;
702
[email protected]d8375fd2008-11-25 22:45:39703 service->RestoreMostRecentEntry(this);
[email protected]fbd77592008-11-12 20:50:27704}
705
706void Browser::ConvertPopupToTabbedBrowser() {
707 UserMetrics::RecordAction(L"ShowAsTab", profile_);
[email protected]fbd77592008-11-12 20:50:27708 int tab_strip_index = tabstrip_model_.selected_index();
709 TabContents* contents = tabstrip_model_.DetachTabContentsAt(tab_strip_index);
[email protected]15952e462008-11-14 00:29:05710 Browser* browser = Browser::Create(profile_);
711 browser->tabstrip_model()->AppendTabContents(contents, true);
712 browser->window()->Show();
[email protected]fbd77592008-11-12 20:50:27713}
714
715void Browser::Exit() {
716 UserMetrics::RecordAction(L"Exit", profile_);
717 BrowserList::CloseAllBrowsers(true);
718}
719
[email protected]36b6dcb2008-11-12 01:19:57720void Browser::BookmarkCurrentPage() {
[email protected]fbd77592008-11-12 20:50:27721 UserMetrics::RecordAction(L"Star", profile_);
722
[email protected]36b6dcb2008-11-12 01:19:57723 TabContents* tab = GetSelectedTabContents();
[email protected]c7c42332008-11-15 01:10:54724 if (!tab->AsWebContents())
[email protected]36b6dcb2008-11-12 01:19:57725 return;
726
727 WebContents* rvh = tab->AsWebContents();
728 BookmarkModel* model = tab->profile()->GetBookmarkModel();
729 if (!model || !model->IsLoaded())
730 return; // Ignore requests until bookmarks are loaded.
731
732 NavigationEntry* entry = rvh->controller()->GetActiveEntry();
733 if (!entry)
734 return; // Can't star if there is no URL.
735 const GURL& url = entry->display_url();
736 if (url.is_empty() || !url.is_valid())
737 return;
738
739 if (window_->GetStarButton()) {
740 if (!window_->GetStarButton()->is_bubble_showing()) {
741 const bool newly_bookmarked = !model->IsBookmarked(url);
742 if (newly_bookmarked) {
743 model->SetURLStarred(url, entry->title(), true);
744 if (!model->IsBookmarked(url)) {
745 // Starring failed. This shouldn't happen.
746 NOTREACHED();
747 return;
748 }
749 }
750 window_->GetStarButton()->ShowStarBubble(url, newly_bookmarked);
751 }
752 } else if (model->IsBookmarked(url)) {
753 // If we can't find the star button and the user wanted to unstar it,
754 // go ahead and unstar it without showing the bubble.
755 model->SetURLStarred(url, std::wstring(), false);
756 }
757}
758
[email protected]fbd77592008-11-12 20:50:27759void Browser::ViewSource() {
760 UserMetrics::RecordAction(L"ViewSource", profile_);
[email protected]36b6dcb2008-11-12 01:19:57761
[email protected]36b6dcb2008-11-12 01:19:57762 TabContents* current_tab = GetSelectedTabContents();
[email protected]fbd77592008-11-12 20:50:27763 NavigationEntry* entry = current_tab->controller()->GetLastCommittedEntry();
764 if (entry) {
765 GURL url("view-source:" + entry->url().spec());
[email protected]749eea042009-01-05 22:35:54766 OpenURL(url, GURL(), NEW_FOREGROUND_TAB, PageTransition::LINK);
[email protected]36b6dcb2008-11-12 01:19:57767 }
768}
initial.commit09911bf2008-07-26 23:55:29769
[email protected]fbd77592008-11-12 20:50:27770void Browser::ClosePopups() {
771 UserMetrics::RecordAction(L"CloseAllSuppressedPopups", profile_);
772 GetSelectedTabContents()->CloseAllSuppressedPopups();
773}
initial.commit09911bf2008-07-26 23:55:29774
[email protected]fbd77592008-11-12 20:50:27775void Browser::Print() {
776 UserMetrics::RecordAction(L"PrintPreview", profile_);
777 GetSelectedTabContents()->AsWebContents()->PrintPreview();
778}
779
780void Browser::SavePage() {
781 UserMetrics::RecordAction(L"SavePage", profile_);
782 GetSelectedTabContents()->AsWebContents()->OnSavePage();
783}
784
785void Browser::ToggleEncodingAutoDetect() {
786 UserMetrics::RecordAction(L"AutoDetectChange", profile_);
787 encoding_auto_detect_.SetValue(!encoding_auto_detect_.GetValue());
788 // Reload the page so we can try to auto-detect the charset.
789 Reload();
790}
791
792void Browser::OverrideEncoding(int encoding_id) {
793 UserMetrics::RecordAction(L"OverrideEncoding", profile_);
794 const std::wstring selected_encoding =
795 CharacterEncoding::GetCanonicalEncodingNameByCommandId(encoding_id);
[email protected]64ff7942008-12-17 18:11:23796 WebContents* current_web_contents = GetSelectedTabContents()->AsWebContents();
797 if (!selected_encoding.empty() && current_web_contents)
798 current_web_contents->override_encoding(selected_encoding);
[email protected]fbd77592008-11-12 20:50:27799 // Update the list of recently selected encodings.
800 std::wstring new_selected_encoding_list;
801 if (CharacterEncoding::UpdateRecentlySelectdEncoding(
802 profile_->GetPrefs()->GetString(prefs::kRecentlySelectedEncoding),
803 encoding_id,
804 &new_selected_encoding_list)) {
805 profile_->GetPrefs()->SetString(prefs::kRecentlySelectedEncoding,
806 new_selected_encoding_list);
807 }
[email protected]36b6dcb2008-11-12 01:19:57808}
809
[email protected]84214982008-12-10 18:49:10810// TODO(devint): http://b/issue?id=1117225 Cut, Copy, and Paste are always
811// enabled in the page menu regardless of whether the command will do
812// anything. When someone selects the menu item, we just act as if they hit
813// the keyboard shortcut for the command by sending the associated key press
814// to windows. The real fix to this bug is to disable the commands when they
815// won't do anything. We'll need something like an overall clipboard command
816// manager to do that.
817
818void Browser::Cut() {
819 UserMetrics::RecordAction(L"Cut", profile_);
820 ui_controls::SendKeyPress(L'X', true, false, false);
[email protected]36b6dcb2008-11-12 01:19:57821}
822
[email protected]84214982008-12-10 18:49:10823void Browser::Copy() {
824 UserMetrics::RecordAction(L"Copy", profile_);
825 ui_controls::SendKeyPress(L'C', true, false, false);
[email protected]36b6dcb2008-11-12 01:19:57826}
827
[email protected]84214982008-12-10 18:49:10828void Browser::CopyCurrentPageURL() {
829 UserMetrics::RecordAction(L"CopyURLToClipBoard", profile_);
830 std::string url = GetSelectedTabContents()->GetURL().spec();
831
832 if (!::OpenClipboard(NULL)) {
833 NOTREACHED();
834 return;
835 }
836
837 if (::EmptyClipboard()) {
838 HGLOBAL text = ::GlobalAlloc(GMEM_MOVEABLE, url.size() + 1);
839 LPSTR ptr = static_cast<LPSTR>(::GlobalLock(text));
840 memcpy(ptr, url.c_str(), url.size());
841 ptr[url.size()] = '\0';
842 ::GlobalUnlock(text);
843
844 ::SetClipboardData(CF_TEXT, text);
845 }
846
847 if (!::CloseClipboard()) {
848 NOTREACHED();
849 }
[email protected]36b6dcb2008-11-12 01:19:57850}
851
[email protected]84214982008-12-10 18:49:10852void Browser::Paste() {
853 UserMetrics::RecordAction(L"Paste", profile_);
854 ui_controls::SendKeyPress(L'V', true, false, false);
855}
856
857void Browser::Find() {
858 UserMetrics::RecordAction(L"Find", profile_);
859 GetSelectedTabContents()->AsWebContents()->view()->FindInPage(*this, false,
860 false);
861}
862
863void Browser::FindNext() {
864 UserMetrics::RecordAction(L"FindNext", profile_);
865 AdvanceFindSelection(true);
866}
867
868void Browser::FindPrevious() {
869 UserMetrics::RecordAction(L"FindPrevious", profile_);
870 AdvanceFindSelection(false);
871}
872
873void Browser::ZoomIn() {
874 UserMetrics::RecordAction(L"ZoomPlus", profile_);
875 GetSelectedTabContents()->AsWebContents()->render_view_host()->Zoom(
876 PageZoom::LARGER);
877}
878
879void Browser::ZoomReset() {
880 UserMetrics::RecordAction(L"ZoomNormal", profile_);
881 GetSelectedTabContents()->AsWebContents()->render_view_host()->Zoom(
882 PageZoom::STANDARD);
883}
884
885void Browser::ZoomOut() {
886 UserMetrics::RecordAction(L"ZoomMinus", profile_);
887 GetSelectedTabContents()->AsWebContents()->render_view_host()->Zoom(
888 PageZoom::SMALLER);
889}
890
891void Browser::FocusToolbar() {
892 UserMetrics::RecordAction(L"FocusToolbar", profile_);
893 window_->FocusToolbar();
894}
895
896void Browser::FocusLocationBar() {
897 UserMetrics::RecordAction(L"FocusLocation", profile_);
898 LocationBarView* lbv = GetLocationBarView();
899 if (lbv) {
900 AutocompleteEditView* aev = lbv->location_entry();
901 aev->SetFocus();
902 aev->SelectAll(true);
903 }
904}
905
906void Browser::FocusSearch() {
907 // TODO(beng): replace this with FocusLocationBar
908 UserMetrics::RecordAction(L"FocusSearch", profile_);
909 LocationBarView* lbv = GetLocationBarView();
910 if (lbv) {
911 AutocompleteEditView* aev = lbv->location_entry();
912 aev->SetUserText(L"?");
913 aev->SetFocus();
914 }
915}
916
917void Browser::OpenFile() {
918 UserMetrics::RecordAction(L"OpenFile", profile_);
919 if (!select_file_dialog_.get())
920 select_file_dialog_ = SelectFileDialog::Create(this);
921
922 // TODO(beng): figure out how to juggle this.
923 HWND parent_hwnd = reinterpret_cast<HWND>(window_->GetNativeHandle());
924 select_file_dialog_->SelectFile(SelectFileDialog::SELECT_OPEN_FILE,
925 std::wstring(), std::wstring(),
926 std::wstring(), std::wstring(),
927 parent_hwnd, NULL);
928}
929
930void Browser::OpenCreateShortcutsDialog() {
931 UserMetrics::RecordAction(L"CreateShortcut", profile_);
932 GetSelectedTabContents()->AsWebContents()->CreateShortcut();
[email protected]36b6dcb2008-11-12 01:19:57933}
934
[email protected]fbd77592008-11-12 20:50:27935void Browser::OpenDebuggerWindow() {
936#ifndef CHROME_DEBUGGER_DISABLED
937 UserMetrics::RecordAction(L"Debugger", profile_);
938 TabContents* current_tab = GetSelectedTabContents();
[email protected]fbd77592008-11-12 20:50:27939 if (current_tab->AsWebContents()) {
940 // Only one debugger instance can exist at a time right now.
941 // TODO(erikkay): need an alert, dialog, something
942 // or better yet, fix the one instance limitation
[email protected]64ff7942008-12-17 18:11:23943 if (!DebuggerWindow::DoesDebuggerExist())
[email protected]fbd77592008-11-12 20:50:27944 debugger_window_ = new DebuggerWindow();
[email protected]fbd77592008-11-12 20:50:27945 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
[email protected]84214982008-12-10 18:49:10956void Browser::OpenTaskManager() {
957 UserMetrics::RecordAction(L"TaskManager", profile_);
958 TaskManager::Open();
959}
960
961void Browser::OpenSelectProfileDialog() {
962 UserMetrics::RecordAction(L"SelectProfile", profile_);
963 SelectProfileDialog::RunDialog();
964}
965
966void Browser::OpenNewProfileDialog() {
967 UserMetrics::RecordAction(L"CreateProfile", profile_);
968 NewProfileDialog::RunDialog();
969}
970
971void Browser::OpenBugReportDialog() {
972 UserMetrics::RecordAction(L"ReportBug", profile_);
973 window_->ShowReportBugDialog();
974}
975
976void Browser::ToggleBookmarkBar() {
977 UserMetrics::RecordAction(L"ShowBookmarksBar", profile_);
978 window_->ToggleBookmarkBar();
979}
980
981void Browser::ShowHistoryTab() {
982 UserMetrics::RecordAction(L"ShowHistory", profile_);
983 ShowNativeUITab(HistoryTabUI::GetURL());
984}
985
986void Browser::OpenBookmarkManager() {
987 UserMetrics::RecordAction(L"ShowBookmarkManager", profile_);
988 window_->ShowBookmarkManager();
989}
990
991void Browser::ShowDownloadsTab() {
992 UserMetrics::RecordAction(L"ShowDownloads", profile_);
993 ShowNativeUITab(DownloadTabUI::GetURL());
994}
995
996void Browser::OpenClearBrowsingDataDialog() {
997 UserMetrics::RecordAction(L"ClearBrowsingData_ShowDlg", profile_);
998 window_->ShowClearBrowsingDataDialog();
999}
1000
1001void Browser::OpenImportSettingsDialog() {
1002 UserMetrics::RecordAction(L"Import_ShowDlg", profile_);
1003 window_->ShowImportDialog();
1004}
1005
1006void Browser::OpenOptionsDialog() {
1007 UserMetrics::RecordAction(L"ShowOptions", profile_);
1008 ShowOptionsWindow(OPTIONS_PAGE_DEFAULT, OPTIONS_GROUP_NONE, profile_);
1009}
1010
1011void Browser::OpenKeywordEditor() {
1012 UserMetrics::RecordAction(L"EditSearchEngines", profile_);
1013 window_->ShowSearchEnginesDialog();
[email protected]fbd77592008-11-12 20:50:271014}
1015
1016void Browser::OpenPasswordManager() {
[email protected]2d46c842008-11-14 19:24:311017 window_->ShowPasswordManager();
[email protected]fbd77592008-11-12 20:50:271018}
1019
1020void Browser::OpenAboutChromeDialog() {
1021 UserMetrics::RecordAction(L"AboutChrome", profile_);
[email protected]2d46c842008-11-14 19:24:311022 window_->ShowAboutChromeDialog();
[email protected]fbd77592008-11-12 20:50:271023}
1024
[email protected]fbd77592008-11-12 20:50:271025void Browser::OpenHelpTab() {
1026 GURL help_url(l10n_util::GetString(IDS_HELP_CONTENT_URL));
1027 AddTabWithURL(help_url, GURL(), PageTransition::AUTO_BOOKMARK, true,
1028 NULL);
1029}
1030
[email protected]36b6dcb2008-11-12 01:19:571031///////////////////////////////////////////////////////////////////////////////
1032
1033// static
1034void Browser::RegisterPrefs(PrefService* prefs) {
1035 prefs->RegisterDictionaryPref(prefs::kBrowserWindowPlacement);
1036 prefs->RegisterIntegerPref(prefs::kOptionsWindowLastTabIndex, 0);
1037}
1038
1039// static
1040void Browser::RegisterUserPrefs(PrefService* prefs) {
1041 prefs->RegisterStringPref(prefs::kHomePage, L"chrome-internal:");
1042 prefs->RegisterBooleanPref(prefs::kHomePageIsNewTabPage, true);
1043 prefs->RegisterIntegerPref(prefs::kCookieBehavior,
1044 net::CookiePolicy::ALLOW_ALL_COOKIES);
1045 prefs->RegisterBooleanPref(prefs::kShowHomeButton, false);
1046 prefs->RegisterStringPref(prefs::kRecentlySelectedEncoding, L"");
1047 // TODO(peterson): bug #3870 move this to the AutofillManager once it is
1048 // checked-in.
1049 prefs->RegisterBooleanPref(prefs::kFormAutofillEnabled, true);
1050 prefs->RegisterBooleanPref(prefs::kDeleteBrowsingHistory, true);
1051 prefs->RegisterBooleanPref(prefs::kDeleteDownloadHistory, true);
1052 prefs->RegisterBooleanPref(prefs::kDeleteCache, true);
1053 prefs->RegisterBooleanPref(prefs::kDeleteCookies, true);
1054 prefs->RegisterBooleanPref(prefs::kDeletePasswords, false);
1055 prefs->RegisterBooleanPref(prefs::kDeleteFormData, true);
1056 prefs->RegisterIntegerPref(prefs::kDeleteTimePeriod, 0);
1057}
1058
1059// static
1060Browser* Browser::GetBrowserForController(
1061 const NavigationController* controller, int* index_result) {
1062 BrowserList::const_iterator it;
1063 for (it = BrowserList::begin(); it != BrowserList::end(); ++it) {
1064 int index = (*it)->tabstrip_model_.GetIndexOfController(controller);
1065 if (index != TabStripModel::kNoTab) {
1066 if (index_result)
1067 *index_result = index;
1068 return *it;
1069 }
1070 }
1071
1072 return NULL;
1073}
1074
1075///////////////////////////////////////////////////////////////////////////////
1076// Browser, CommandHandler implementation:
1077
1078void Browser::ExecuteCommand(int id) {
[email protected]c7c42332008-11-15 01:10:541079 DCHECK(IsCommandEnabled(id)) << "Invalid or disabled command";
[email protected]36b6dcb2008-11-12 01:19:571080
[email protected]fbd77592008-11-12 20:50:271081 // The order of commands in this switch statement must match the function
1082 // declaration order in browser.h!
[email protected]36b6dcb2008-11-12 01:19:571083 switch (id) {
[email protected]84214982008-12-10 18:49:101084 // Navigation commands
[email protected]cb525c82008-12-08 23:04:541085 case IDC_BACK: GoBack(); break;
1086 case IDC_FORWARD: GoForward(); break;
1087 case IDC_RELOAD: Reload(); break;
[email protected]cb525c82008-12-08 23:04:541088 case IDC_HOME: Home(); break;
[email protected]cb525c82008-12-08 23:04:541089 case IDC_OPEN_CURRENT_URL: OpenCurrentURL(); break;
[email protected]84214982008-12-10 18:49:101090 case IDC_GO: Go(); break;
1091 case IDC_STOP: Stop(); break;
[email protected]36b6dcb2008-11-12 01:19:571092
[email protected]84214982008-12-10 18:49:101093 // Window management commands
[email protected]cb525c82008-12-08 23:04:541094 case IDC_NEW_WINDOW: NewWindow(); break;
1095 case IDC_NEW_INCOGNITO_WINDOW: NewIncognitoWindow(); break;
[email protected]84214982008-12-10 18:49:101096 case IDC_NEW_WINDOW_PROFILE_0:
1097 case IDC_NEW_WINDOW_PROFILE_1:
1098 case IDC_NEW_WINDOW_PROFILE_2:
1099 case IDC_NEW_WINDOW_PROFILE_3:
1100 case IDC_NEW_WINDOW_PROFILE_4:
1101 case IDC_NEW_WINDOW_PROFILE_5:
1102 case IDC_NEW_WINDOW_PROFILE_6:
1103 case IDC_NEW_WINDOW_PROFILE_7:
1104 case IDC_NEW_WINDOW_PROFILE_8:
1105 NewProfileWindowByIndex(id - IDC_NEW_WINDOW_PROFILE_0); break;
[email protected]cb525c82008-12-08 23:04:541106 case IDC_CLOSE_WINDOW: CloseWindow(); break;
[email protected]84214982008-12-10 18:49:101107 case IDC_NEW_TAB: NewTab(); break;
1108 case IDC_CLOSE_TAB: CloseTab(); break;
[email protected]cb525c82008-12-08 23:04:541109 case IDC_SELECT_NEXT_TAB: SelectNextTab(); break;
1110 case IDC_SELECT_PREVIOUS_TAB: SelectPreviousTab(); break;
[email protected]36b6dcb2008-11-12 01:19:571111 case IDC_SELECT_TAB_0:
1112 case IDC_SELECT_TAB_1:
1113 case IDC_SELECT_TAB_2:
1114 case IDC_SELECT_TAB_3:
1115 case IDC_SELECT_TAB_4:
1116 case IDC_SELECT_TAB_5:
1117 case IDC_SELECT_TAB_6:
[email protected]cb525c82008-12-08 23:04:541118 case IDC_SELECT_TAB_7: SelectNumberedTab(id - IDC_SELECT_TAB_0);
1119 break;
1120 case IDC_SELECT_LAST_TAB: SelectLastTab(); break;
1121 case IDC_DUPLICATE_TAB: DuplicateTab(); break;
1122 case IDC_RESTORE_TAB: RestoreTab(); break;
1123 case IDC_SHOW_AS_TAB: ConvertPopupToTabbedBrowser(); break;
1124 case IDC_EXIT: Exit(); break;
[email protected]36b6dcb2008-11-12 01:19:571125
[email protected]84214982008-12-10 18:49:101126 // Page-related commands
[email protected]cb525c82008-12-08 23:04:541127 case IDC_STAR: BookmarkCurrentPage(); break;
1128 case IDC_VIEW_SOURCE: ViewSource(); break;
1129 case IDC_CLOSE_POPUPS: ClosePopups(); break;
1130 case IDC_PRINT: Print(); break;
1131 case IDC_SAVE_PAGE: SavePage(); break;
1132 case IDC_ENCODING_AUTO_DETECT: ToggleEncodingAutoDetect(); break;
[email protected]36b6dcb2008-11-12 01:19:571133 case IDC_ENCODING_UTF8:
1134 case IDC_ENCODING_UTF16LE:
1135 case IDC_ENCODING_ISO88591:
1136 case IDC_ENCODING_WINDOWS1252:
[email protected]1c5bf632008-12-11 20:30:491137 case IDC_ENCODING_GBK:
[email protected]36b6dcb2008-11-12 01:19:571138 case IDC_ENCODING_GB18030:
1139 case IDC_ENCODING_BIG5HKSCS:
1140 case IDC_ENCODING_BIG5:
1141 case IDC_ENCODING_KOREAN:
1142 case IDC_ENCODING_SHIFTJIS:
1143 case IDC_ENCODING_ISO2022JP:
1144 case IDC_ENCODING_EUCJP:
1145 case IDC_ENCODING_THAI:
1146 case IDC_ENCODING_ISO885915:
1147 case IDC_ENCODING_MACINTOSH:
1148 case IDC_ENCODING_ISO88592:
1149 case IDC_ENCODING_WINDOWS1250:
1150 case IDC_ENCODING_ISO88595:
1151 case IDC_ENCODING_WINDOWS1251:
1152 case IDC_ENCODING_KOI8R:
1153 case IDC_ENCODING_KOI8U:
1154 case IDC_ENCODING_ISO88597:
1155 case IDC_ENCODING_WINDOWS1253:
1156 case IDC_ENCODING_ISO88594:
1157 case IDC_ENCODING_ISO885913:
1158 case IDC_ENCODING_WINDOWS1257:
1159 case IDC_ENCODING_ISO88593:
1160 case IDC_ENCODING_ISO885910:
1161 case IDC_ENCODING_ISO885914:
1162 case IDC_ENCODING_ISO885916:
[email protected]36b6dcb2008-11-12 01:19:571163 case IDC_ENCODING_WINDOWS1254:
1164 case IDC_ENCODING_ISO88596:
1165 case IDC_ENCODING_WINDOWS1256:
1166 case IDC_ENCODING_ISO88598:
1167 case IDC_ENCODING_WINDOWS1255:
[email protected]cb525c82008-12-08 23:04:541168 case IDC_ENCODING_WINDOWS1258: OverrideEncoding(id); break;
[email protected]36b6dcb2008-11-12 01:19:571169
[email protected]84214982008-12-10 18:49:101170 // Clipboard commands
1171 case IDC_CUT: Cut(); break;
1172 case IDC_COPY: Copy(); break;
1173 case IDC_COPY_URL: CopyCurrentPageURL(); break;
1174 case IDC_PASTE: Paste(); break;
1175
1176 // Find-in-page
1177 case IDC_FIND: Find(); break;
1178 case IDC_FIND_NEXT: FindNext(); break;
1179 case IDC_FIND_PREVIOUS: FindPrevious(); break;
1180
1181 // Zoom
1182 case IDC_ZOOM_PLUS: ZoomIn(); break;
1183 case IDC_ZOOM_NORMAL: ZoomReset(); break;
1184 case IDC_ZOOM_MINUS: ZoomOut(); break;
1185
1186 // Focus various bits of UI
1187 case IDC_FOCUS_TOOLBAR: FocusToolbar(); break;
1188 case IDC_FOCUS_LOCATION: FocusLocationBar(); break;
1189 case IDC_FOCUS_SEARCH: FocusSearch(); break;
1190
1191 // Show various bits of UI
1192 case IDC_OPEN_FILE: OpenFile(); break;
1193 case IDC_CREATE_SHORTCUTS: OpenCreateShortcutsDialog(); break;
[email protected]cb525c82008-12-08 23:04:541194 case IDC_DEBUGGER: OpenDebuggerWindow(); break;
1195 case IDC_JS_CONSOLE: OpenJavaScriptConsole(); break;
[email protected]cb525c82008-12-08 23:04:541196 case IDC_TASK_MANAGER: OpenTaskManager(); break;
[email protected]cb525c82008-12-08 23:04:541197 case IDC_SELECT_PROFILE: OpenSelectProfileDialog(); break;
1198 case IDC_NEW_PROFILE: OpenNewProfileDialog(); break;
[email protected]84214982008-12-10 18:49:101199 case IDC_REPORT_BUG: OpenBugReportDialog(); break;
1200 case IDC_SHOW_BOOKMARK_BAR: ToggleBookmarkBar(); break;
1201 case IDC_SHOW_HISTORY: ShowHistoryTab(); break;
1202 case IDC_SHOW_BOOKMARK_MANAGER: OpenBookmarkManager(); break;
1203 case IDC_SHOW_DOWNLOADS: ShowDownloadsTab(); break;
1204 case IDC_CLEAR_BROWSING_DATA: OpenClearBrowsingDataDialog(); break;
1205 case IDC_IMPORT_SETTINGS: OpenImportSettingsDialog(); break;
1206 case IDC_OPTIONS: OpenOptionsDialog(); break;
1207 case IDC_EDIT_SEARCH_ENGINES: OpenKeywordEditor(); break;
1208 case IDC_VIEW_PASSWORDS: OpenPasswordManager(); break;
1209 case IDC_ABOUT: OpenAboutChromeDialog(); break;
1210 case IDC_HELP_PAGE: OpenHelpTab(); break;
[email protected]36b6dcb2008-11-12 01:19:571211
1212 default:
[email protected]84214982008-12-10 18:49:101213 LOG(WARNING) << "Received Unimplemented Command: " << id;
[email protected]fbd77592008-11-12 20:50:271214 break;
[email protected]36b6dcb2008-11-12 01:19:571215 }
1216}
1217
1218///////////////////////////////////////////////////////////////////////////////
1219// Browser, TabStripModelDelegate implementation:
1220
[email protected]15952e462008-11-14 00:29:051221GURL Browser::GetBlankTabURL() const {
1222 return NewTabUIURL();
1223}
1224
[email protected]36b6dcb2008-11-12 01:19:571225void Browser::CreateNewStripWithContents(TabContents* detached_contents,
[email protected]5e495462008-11-20 23:07:411226 const gfx::Rect& window_bounds,
1227 const DockInfo& dock_info) {
[email protected]299dabd2008-11-19 02:27:161228 DCHECK(type_ == TYPE_NORMAL);
[email protected]adf650f2008-12-09 16:10:061229
[email protected]5e495462008-11-20 23:07:411230 gfx::Rect new_window_bounds = window_bounds;
1231 bool maximize = false;
1232 if (dock_info.GetNewWindowBounds(&new_window_bounds, &maximize))
1233 dock_info.AdjustOtherWindowBounds();
1234
[email protected]36b6dcb2008-11-12 01:19:571235 // Create an empty new browser window the same size as the old one.
[email protected]299dabd2008-11-19 02:27:161236 Browser* browser = new Browser(TYPE_NORMAL, profile_);
[email protected]5e495462008-11-20 23:07:411237 browser->set_override_bounds(new_window_bounds);
1238 browser->set_override_maximized(maximize);
[email protected]15952e462008-11-14 00:29:051239 browser->CreateBrowserWindow();
1240 browser->tabstrip_model()->AppendTabContents(detached_contents, true);
[email protected]159f7762008-12-19 14:58:271241 // Make sure the loading state is updated correctly, otherwise the throbber
1242 // won't start if the page is loading.
1243 browser->LoadingStateChanged(detached_contents);
[email protected]15952e462008-11-14 00:29:051244 browser->window()->Show();
[email protected]36b6dcb2008-11-12 01:19:571245
1246 // When we detach a tab we need to make sure any associated Find window moves
[email protected]2d46c842008-11-14 19:24:311247 // along with it to its new home (basically we just make new_window the
1248 // parent of the Find window).
[email protected]36b6dcb2008-11-12 01:19:571249 // TODO(brettw) this could probably be improved, see
1250 // WebContentsView::ReparentFindWindow for more.
[email protected]64ff7942008-12-17 18:11:231251 WebContents* web_contents = detached_contents->AsWebContents();
1252 if (web_contents)
1253 web_contents->view()->ReparentFindWindow(browser);
[email protected]36b6dcb2008-11-12 01:19:571254}
1255
1256int Browser::GetDragActions() const {
1257 int result = 0;
[email protected]299dabd2008-11-19 02:27:161258 if (BrowserList::GetBrowserCountForType(profile_, TYPE_NORMAL) > 1 ||
[email protected]36b6dcb2008-11-12 01:19:571259 tab_count() > 1)
1260 result |= TAB_TEAROFF_ACTION;
1261 if (tab_count() > 1)
1262 result |= TAB_MOVE_ACTION;
1263 return result;
1264}
1265
1266TabContents* Browser::CreateTabContentsForURL(
1267 const GURL& url, const GURL& referrer, Profile* profile,
1268 PageTransition::Type transition, bool defer_load,
1269 SiteInstance* instance) const {
1270 // Create an appropriate tab contents.
1271 GURL real_url = url;
1272 TabContentsType type = TabContents::TypeForURL(&real_url);
1273 DCHECK(type != TAB_CONTENTS_UNKNOWN_TYPE);
1274
[email protected]ec322ff2008-11-19 22:53:301275 TabContents* contents = TabContents::CreateWithType(type, profile, instance);
[email protected]36b6dcb2008-11-12 01:19:571276 contents->SetupController(profile);
1277
1278 if (!defer_load) {
1279 // Load the initial URL before adding the new tab contents to the tab strip
1280 // so that the tab contents has navigation state.
1281 contents->controller()->LoadURL(url, referrer, transition);
1282 }
1283
1284 return contents;
1285}
1286
1287bool Browser::CanDuplicateContentsAt(int index) {
1288 TabContents* contents = GetTabContentsAt(index);
1289 DCHECK(contents);
1290
1291 NavigationController* nc = contents->controller();
1292 return nc ? (nc->active_contents() && nc->GetLastCommittedEntry()) : false;
1293}
1294
1295void Browser::DuplicateContentsAt(int index) {
1296 TabContents* contents = GetTabContentsAt(index);
1297 TabContents* new_contents = NULL;
1298 DCHECK(contents);
1299
[email protected]299dabd2008-11-19 02:27:161300 if (type_ == TYPE_NORMAL) {
[email protected]36b6dcb2008-11-12 01:19:571301 // If this is a tabbed browser, just create a duplicate tab inside the same
1302 // window next to the tab being duplicated.
[email protected]ec322ff2008-11-19 22:53:301303 new_contents = contents->controller()->Clone()->active_contents();
[email protected]36b6dcb2008-11-12 01:19:571304 // If you duplicate a tab that is not selected, we need to make sure to
1305 // select the tab being duplicated so that DetermineInsertionIndex returns
1306 // the right index (if tab 5 is selected and we right-click tab 1 we want
1307 // the new tab to appear in index position 2, not 6).
1308 if (tabstrip_model_.selected_index() != index)
1309 tabstrip_model_.SelectTabContentsAt(index, true);
1310 tabstrip_model_.AddTabContents(new_contents, index + 1,
1311 PageTransition::LINK, true);
1312 } else {
[email protected]15952e462008-11-14 00:29:051313 Browser* browser = NULL;
[email protected]299dabd2008-11-19 02:27:161314 if (type_ == TYPE_APP) {
[email protected]15952e462008-11-14 00:29:051315 browser = Browser::CreateForApp(app_name_, profile_);
[email protected]299dabd2008-11-19 02:27:161316 } else if (type_ == TYPE_POPUP) {
[email protected]15952e462008-11-14 00:29:051317 browser = Browser::CreateForPopup(profile_);
1318 }
[email protected]36b6dcb2008-11-12 01:19:571319
[email protected]b1fed962008-12-18 00:54:081320 // Preserve the size of the original window. The new window has already
1321 // been given an offset by the OS, so we shouldn't copy the old bounds.
1322 BrowserWindow* new_window = browser->window();
1323 new_window->SetBounds(gfx::Rect(new_window->GetNormalBounds().origin(),
1324 window()->GetNormalBounds().size()));
1325
[email protected]36b6dcb2008-11-12 01:19:571326 // We need to show the browser now. Otherwise ContainerWin assumes the
1327 // TabContents is invisible and won't size it.
[email protected]15952e462008-11-14 00:29:051328 browser->window()->Show();
[email protected]36b6dcb2008-11-12 01:19:571329
1330 // The page transition below is only for the purpose of inserting the tab.
[email protected]15952e462008-11-14 00:29:051331 new_contents = browser->AddTabWithNavigationController(
[email protected]ec322ff2008-11-19 22:53:301332 contents->controller()->Clone(),
[email protected]36b6dcb2008-11-12 01:19:571333 PageTransition::LINK);
[email protected]36b6dcb2008-11-12 01:19:571334 }
1335
1336 if (profile_->HasSessionService()) {
1337 SessionService* session_service = profile_->GetSessionService();
1338 if (session_service)
1339 session_service->TabRestored(new_contents->controller());
1340 }
1341}
1342
[email protected]36b6dcb2008-11-12 01:19:571343void Browser::CloseFrameAfterDragSession() {
1344 // This is scheduled to run after we return to the message loop because
1345 // otherwise the frame will think the drag session is still active and ignore
1346 // the request.
1347 MessageLoop::current()->PostTask(FROM_HERE,
1348 method_factory_.NewRunnableMethod(&Browser::CloseFrame));
initial.commit09911bf2008-07-26 23:55:291349}
1350
[email protected]2d46c842008-11-14 19:24:311351///////////////////////////////////////////////////////////////////////////////
[email protected]36b6dcb2008-11-12 01:19:571352// Browser, TabStripModelObserver implementation:
1353
1354void Browser::TabInsertedAt(TabContents* contents,
1355 int index,
1356 bool foreground) {
1357 contents->set_delegate(this);
1358 contents->controller()->SetWindowID(session_id());
1359
1360 SyncHistoryWithTabs(tabstrip_model_.GetIndexOfTabContents(contents));
1361
1362 // When a tab is dropped into a tab strip we need to make sure that the
1363 // associated Find window is moved along with it. We therefore change the
1364 // parent of the Find window (if the parent is already correctly set this
1365 // does nothing).
1366 // TODO(brettw) this could probably be improved, see
1367 // WebContentsView::ReparentFindWindow for more.
[email protected]64ff7942008-12-17 18:11:231368 WebContents* web_contents = contents->AsWebContents();
1369 if (web_contents)
1370 web_contents->view()->ReparentFindWindow(this);
[email protected]36b6dcb2008-11-12 01:19:571371
[email protected]159f7762008-12-19 14:58:271372 // Make sure the loading state is updated correctly, otherwise the throbber
1373 // won't start if the page is loading.
1374 LoadingStateChanged(contents);
1375
[email protected]36b6dcb2008-11-12 01:19:571376 // If the tab crashes in the beforeunload or unload handler, it won't be
1377 // able to ack. But we know we can close it.
1378 NotificationService::current()->
1379 AddObserver(this, NOTIFY_WEB_CONTENTS_DISCONNECTED,
1380 Source<TabContents>(contents));
1381}
1382
1383void Browser::TabClosingAt(TabContents* contents, int index) {
1384 NavigationController* controller = contents->controller();
1385 DCHECK(controller);
1386 NotificationService::current()->
1387 Notify(NOTIFY_TAB_CLOSING,
1388 Source<NavigationController>(controller),
1389 NotificationService::NoDetails());
1390
1391 // Sever the TabContents' connection back to us.
1392 contents->set_delegate(NULL);
1393}
1394
1395void Browser::TabDetachedAt(TabContents* contents, int index) {
1396 contents->set_delegate(NULL);
1397 if (!tabstrip_model_.closing_all())
1398 SyncHistoryWithTabs(0);
1399
1400 RemoveScheduledUpdatesFor(contents);
1401
1402 NotificationService::current()->
[email protected]adf650f2008-12-09 16:10:061403 RemoveObserver(this, NOTIFY_WEB_CONTENTS_DISCONNECTED,
[email protected]36b6dcb2008-11-12 01:19:571404 Source<TabContents>(contents));
1405}
1406
1407void Browser::TabSelectedAt(TabContents* old_contents,
1408 TabContents* new_contents,
1409 int index,
1410 bool user_gesture) {
1411 DCHECK(old_contents != new_contents);
1412
1413 // If we have any update pending, do it now.
1414 if (!chrome_updater_factory_.empty() && old_contents)
1415 ProcessPendingUIUpdates();
1416
1417 LocationBarView* location_bar = GetLocationBarView();
1418 if (old_contents) {
1419 // Save what the user's currently typing, so it can be restored when we
1420 // switch back to this tab.
1421 if (location_bar)
1422 location_bar->location_entry()->SaveStateToTab(old_contents);
1423 }
1424
1425 // Propagate the profile to the location bar.
1426 UpdateToolbar(true);
1427
[email protected]64ff7942008-12-17 18:11:231428 // Update stop/go state.
1429 UpdateStopGoState(new_contents->is_loading());
[email protected]36b6dcb2008-11-12 01:19:571430
[email protected]84214982008-12-10 18:49:101431 // Update commands to reflect current state.
1432 UpdateCommandsForTabState();
[email protected]36b6dcb2008-11-12 01:19:571433
1434 // Reset the status bubble.
[email protected]be3877f2009-01-14 15:51:101435 StatusBubble* status_bubble = GetStatusBubble();
1436 if (status_bubble) {
1437 status_bubble->Hide();
[email protected]36b6dcb2008-11-12 01:19:571438
[email protected]be3877f2009-01-14 15:51:101439 // Show the loading state (if any).
1440 status_bubble->SetStatus(GetSelectedTabContents()->GetStatusText());
1441 }
[email protected]36b6dcb2008-11-12 01:19:571442
1443 // Update sessions. Don't force creation of sessions. If sessions doesn't
1444 // exist, the change will be picked up by sessions when created.
1445 if (profile_->HasSessionService()) {
1446 SessionService* session_service = profile_->GetSessionService();
1447 if (session_service && !tabstrip_model_.closing_all()) {
[email protected]2d46c842008-11-14 19:24:311448 session_service->SetSelectedTabInWindow(
1449 session_id(), tabstrip_model_.selected_index());
[email protected]36b6dcb2008-11-12 01:19:571450 }
1451 }
1452}
1453
1454void Browser::TabMoved(TabContents* contents,
1455 int from_index,
1456 int to_index) {
1457 DCHECK(from_index >= 0 && to_index >= 0);
1458 // Notify the history service.
1459 SyncHistoryWithTabs(std::min(from_index, to_index));
1460}
1461
1462void Browser::TabStripEmpty() {
1463 // Close the frame after we return to the message loop (not immediately,
1464 // otherwise it will destroy this object before the stack has a chance to
1465 // cleanly unwind.)
1466 // Note: This will be called several times if TabStripEmpty is called several
1467 // times. This is because it does not close the window if tabs are
1468 // still present.
1469 // NOTE: If you change to be immediate (no invokeLater) then you'll need to
1470 // update BrowserList::CloseAllBrowsers.
1471 MessageLoop::current()->PostTask(FROM_HERE,
1472 method_factory_.NewRunnableMethod(&Browser::CloseFrame));
1473}
1474
1475///////////////////////////////////////////////////////////////////////////////
1476// Browser, TabContentsDelegate implementation:
initial.commit09911bf2008-07-26 23:55:291477
1478void Browser::OpenURLFromTab(TabContents* source,
[email protected]c0588052008-10-27 23:01:501479 const GURL& url, const GURL& referrer,
initial.commit09911bf2008-07-26 23:55:291480 WindowOpenDisposition disposition,
[email protected]e38f40152008-09-12 23:08:301481 PageTransition::Type transition) {
initial.commit09911bf2008-07-26 23:55:291482 // No code for these yet
1483 DCHECK((disposition != NEW_POPUP) && (disposition != SAVE_TO_DISK));
1484
1485 TabContents* current_tab = source ? source : GetSelectedTabContents();
1486 bool source_tab_was_frontmost = (current_tab == GetSelectedTabContents());
1487 TabContents* new_contents = NULL;
1488
1489 // If the URL is part of the same web site, then load it in the same
1490 // SiteInstance (and thus the same process). This is an optimization to
1491 // reduce process overhead; it is not necessary for compatibility. (That is,
1492 // the new tab will not have script connections to the previous tab, so it
1493 // does not need to be part of the same SiteInstance or BrowsingInstance.)
1494 // Default to loading in a new SiteInstance and BrowsingInstance.
1495 // TODO(creis): should this apply to applications?
1496 SiteInstance* instance = NULL;
1497 // Don't use this logic when "--process-per-tab" is specified.
1498 if (!CommandLine().HasSwitch(switches::kProcessPerTab)) {
1499 if (current_tab) {
1500 const WebContents* const web_contents = current_tab->AsWebContents();
1501 if (web_contents) {
1502 const GURL& current_url = web_contents->GetURL();
1503 if (SiteInstance::IsSameWebSite(current_url, url))
[email protected]e9ba4472008-09-14 15:42:431504 instance = web_contents->GetSiteInstance();
initial.commit09911bf2008-07-26 23:55:291505 }
1506 }
1507 }
1508
1509 // If this is an application we can only have one tab so a new tab always
1510 // goes into a tabbed browser window.
[email protected]299dabd2008-11-19 02:27:161511 if (disposition != NEW_WINDOW && type_ == TYPE_APP) {
initial.commit09911bf2008-07-26 23:55:291512 // If the disposition is OFF_THE_RECORD we don't want to create a new
1513 // browser that will itself create another OTR browser. This will result in
1514 // a browser leak (and crash below because no tab is created or selected).
1515 if (disposition == OFF_THE_RECORD) {
1516 OpenURLOffTheRecord(profile_, url);
1517 return;
1518 }
1519
1520 Browser* b = GetOrCreateTabbedBrowser();
1521 DCHECK(b);
1522
1523 // If we have just created a new browser window, make sure we select the
1524 // tab.
1525 if (b->tab_count() == 0 && disposition == NEW_BACKGROUND_TAB)
1526 disposition = NEW_FOREGROUND_TAB;
1527
[email protected]c0588052008-10-27 23:01:501528 b->OpenURL(url, referrer, disposition, transition);
[email protected]15952e462008-11-14 00:29:051529 b->window()->Show();
initial.commit09911bf2008-07-26 23:55:291530 return;
1531 }
1532
1533 if (profile_->IsOffTheRecord() && disposition == OFF_THE_RECORD)
1534 disposition = NEW_FOREGROUND_TAB;
1535
1536 if (disposition == NEW_WINDOW) {
[email protected]15952e462008-11-14 00:29:051537 Browser* browser = Browser::Create(profile_);
1538 new_contents = browser->AddTabWithURL(url, referrer, transition, true,
1539 instance);
1540 browser->window()->Show();
initial.commit09911bf2008-07-26 23:55:291541 } else if ((disposition == CURRENT_TAB) && current_tab) {
1542 if (transition == PageTransition::TYPED ||
1543 transition == PageTransition::AUTO_BOOKMARK ||
1544 transition == PageTransition::GENERATED ||
1545 transition == PageTransition::START_PAGE) {
[email protected]968e56ae2008-08-04 18:39:281546 // Don't forget the openers if this tab is a New Tab page opened at the
1547 // end of the TabStrip (e.g. by pressing Ctrl+T). Give the user one
1548 // navigation of one of these transition types before resetting the
1549 // opener relationships (this allows for the use case of opening a new
1550 // tab to do a quick look-up of something while viewing a tab earlier in
1551 // the strip). We can make this heuristic more permissive if need be.
1552 // TODO(beng): (http://b/1306495) write unit tests for this once this
1553 // object is unit-testable.
1554 int current_tab_index =
1555 tabstrip_model_.GetIndexOfTabContents(current_tab);
[email protected]adf650f2008-12-09 16:10:061556 bool forget_openers =
[email protected]968e56ae2008-08-04 18:39:281557 !(current_tab->type() == TAB_CONTENTS_NEW_TAB_UI &&
1558 current_tab_index == (tab_count() - 1) &&
1559 current_tab->controller()->GetEntryCount() == 1);
1560 if (forget_openers) {
1561 // If the user navigates the current tab to another page in any way
1562 // other than by clicking a link, we want to pro-actively forget all
1563 // TabStrip opener relationships since we assume they're beginning a
1564 // different task by reusing the current tab.
1565 tabstrip_model_.ForgetAllOpeners();
1566 // In this specific case we also want to reset the group relationship,
1567 // since it is now technically invalid.
1568 tabstrip_model_.ForgetGroup(current_tab);
1569 }
initial.commit09911bf2008-07-26 23:55:291570 }
[email protected]c0588052008-10-27 23:01:501571 current_tab->controller()->LoadURL(url, referrer, transition);
[email protected]2d46c842008-11-14 19:24:311572 // The TabContents might have changed as part of the navigation (ex: new
1573 // tab page can become WebContents).
initial.commit09911bf2008-07-26 23:55:291574 new_contents = current_tab->controller()->active_contents();
[email protected]be3877f2009-01-14 15:51:101575 if (GetStatusBubble())
1576 GetStatusBubble()->Hide();
initial.commit09911bf2008-07-26 23:55:291577
1578 // Synchronously update the location bar. This allows us to immediately
1579 // have the URL bar update when the user types something, rather than
1580 // going through the normal system of ScheduleUIUpdate which has a delay.
[email protected]36b6dcb2008-11-12 01:19:571581 UpdateToolbar(false);
initial.commit09911bf2008-07-26 23:55:291582 } else if (disposition == OFF_THE_RECORD) {
1583 OpenURLOffTheRecord(profile_, url);
1584 return;
1585 } else if (disposition != SUPPRESS_OPEN) {
[email protected]15952e462008-11-14 00:29:051586 new_contents = AddTabWithURL(url, referrer, transition,
1587 disposition != NEW_BACKGROUND_TAB, instance);
initial.commit09911bf2008-07-26 23:55:291588 }
1589
1590 if (disposition != NEW_BACKGROUND_TAB && source_tab_was_frontmost) {
[email protected]2baf83d2008-07-30 05:58:171591 // Give the focus to the newly navigated tab, if the source tab was
1592 // front-most.
initial.commit09911bf2008-07-26 23:55:291593 new_contents->Focus();
1594 }
1595}
1596
1597void Browser::NavigationStateChanged(const TabContents* source,
1598 unsigned changed_flags) {
initial.commit09911bf2008-07-26 23:55:291599 // Only update the UI when something visible has changed.
[email protected]e83f1682008-09-07 23:57:401600 if (changed_flags)
initial.commit09911bf2008-07-26 23:55:291601 ScheduleUIUpdate(source, changed_flags);
1602
[email protected]84214982008-12-10 18:49:101603 // We don't schedule updates to commands since they will only change once per
1604 // navigation, so we don't have to worry about flickering.
[email protected]e83f1682008-09-07 23:57:401605 if (changed_flags & TabContents::INVALIDATE_URL)
[email protected]84214982008-12-10 18:49:101606 UpdateCommandsForTabState();
initial.commit09911bf2008-07-26 23:55:291607}
1608
1609void Browser::ReplaceContents(TabContents* source, TabContents* new_contents) {
1610 source->set_delegate(NULL);
1611 new_contents->set_delegate(this);
1612
1613 RemoveScheduledUpdatesFor(source);
1614
1615 int index = tabstrip_model_.GetIndexOfTabContents(source);
1616 tabstrip_model_.ReplaceTabContentsAt(index, new_contents);
[email protected]8f673f3a2008-08-05 22:34:281617
1618 if (is_attempting_to_close_browser_) {
1619 // Need to do this asynchronously as it will close the tab, which is
1620 // currently on the call stack above us.
1621 MessageLoop::current()->PostTask(FROM_HERE,
[email protected]8a2ce5a2008-08-11 23:43:081622 method_factory_.NewRunnableMethod(&Browser::ClearUnloadState,
[email protected]8f673f3a2008-08-05 22:34:281623 Source<TabContents>(source).ptr()));
1624 }
1625 // Need to remove ourselves as an observer for disconnection on the replaced
1626 // TabContents, since we only care to fire onbeforeunload handlers on active
1627 // Tabs. Make sure an observer is added for the replacement TabContents.
1628 NotificationService::current()->
[email protected]adf650f2008-12-09 16:10:061629 RemoveObserver(this, NOTIFY_WEB_CONTENTS_DISCONNECTED,
[email protected]8f673f3a2008-08-05 22:34:281630 Source<TabContents>(source));
1631 NotificationService::current()->
1632 AddObserver(this, NOTIFY_WEB_CONTENTS_DISCONNECTED,
1633 Source<TabContents>(new_contents));
initial.commit09911bf2008-07-26 23:55:291634}
1635
1636void Browser::AddNewContents(TabContents* source,
1637 TabContents* new_contents,
1638 WindowOpenDisposition disposition,
1639 const gfx::Rect& initial_pos,
1640 bool user_gesture) {
1641 DCHECK(disposition != SAVE_TO_DISK); // No code for this yet
1642
1643 // If this is an application we can only have one tab so we need to process
1644 // this in tabbed browser window.
1645 if (tabstrip_model_.count() > 0 &&
1646 disposition != NEW_WINDOW && disposition != NEW_POPUP &&
[email protected]299dabd2008-11-19 02:27:161647 type_ != TYPE_NORMAL) {
initial.commit09911bf2008-07-26 23:55:291648 Browser* b = GetOrCreateTabbedBrowser();
1649 DCHECK(b);
1650 PageTransition::Type transition = PageTransition::LINK;
1651 // If we were called from an "installed webapp" we want to emulate the code
1652 // that is run from browser_init.cc for links from external applications.
1653 // This means we need to open the tab with the START PAGE transition.
1654 // AddNewContents doesn't support this but the TabStripModel's
1655 // AddTabContents method does.
[email protected]299dabd2008-11-19 02:27:161656 if (type_ == TYPE_APP)
initial.commit09911bf2008-07-26 23:55:291657 transition = PageTransition::START_PAGE;
1658 b->tabstrip_model()->AddTabContents(new_contents, -1, transition, true);
[email protected]15952e462008-11-14 00:29:051659 b->window()->Show();
initial.commit09911bf2008-07-26 23:55:291660 return;
1661 }
1662
1663 if (disposition == NEW_POPUP) {
1664 BuildPopupWindow(source, new_contents, initial_pos);
1665 } else if (disposition == NEW_WINDOW) {
[email protected]15952e462008-11-14 00:29:051666 Browser* browser = Browser::Create(profile_);
1667 browser->AddNewContents(source, new_contents, NEW_FOREGROUND_TAB,
1668 initial_pos, user_gesture);
1669 browser->window()->Show();
initial.commit09911bf2008-07-26 23:55:291670 } else if (disposition == CURRENT_TAB) {
1671 ReplaceContents(source, new_contents);
1672 } else if (disposition != SUPPRESS_OPEN) {
1673 tabstrip_model_.AddTabContents(new_contents, -1, PageTransition::LINK,
1674 disposition == NEW_FOREGROUND_TAB);
1675 }
1676}
1677
initial.commit09911bf2008-07-26 23:55:291678void Browser::ActivateContents(TabContents* contents) {
1679 tabstrip_model_.SelectTabContentsAt(
1680 tabstrip_model_.GetIndexOfTabContents(contents), false);
[email protected]f3e99e32008-07-30 04:48:391681 window_->Activate();
initial.commit09911bf2008-07-26 23:55:291682}
1683
initial.commit09911bf2008-07-26 23:55:291684void Browser::LoadingStateChanged(TabContents* source) {
[email protected]afb73882008-11-14 22:40:441685 window_->UpdateLoadingAnimations(tabstrip_model_.TabsAreLoading());
[email protected]f3e99e32008-07-30 04:48:391686 window_->UpdateTitleBar();
initial.commit09911bf2008-07-26 23:55:291687
initial.commit09911bf2008-07-26 23:55:291688 if (source == GetSelectedTabContents()) {
[email protected]64ff7942008-12-17 18:11:231689 UpdateStopGoState(source->is_loading());
[email protected]be3877f2009-01-14 15:51:101690 if (GetStatusBubble())
1691 GetStatusBubble()->SetStatus(GetSelectedTabContents()->GetStatusText());
initial.commit09911bf2008-07-26 23:55:291692 }
1693}
1694
1695void Browser::CloseContents(TabContents* source) {
[email protected]04b4a6c2008-08-02 00:44:471696 if (is_attempting_to_close_browser_) {
1697 // If we're trying to close the browser, just clear the state related to
[email protected]adf650f2008-12-09 16:10:061698 // waiting for unload to fire. Don't actually try to close the tab as it
[email protected]04b4a6c2008-08-02 00:44:471699 // will go down the slow shutdown path instead of the fast path of killing
1700 // all the renderer processes.
[email protected]8a2ce5a2008-08-11 23:43:081701 ClearUnloadState(source);
[email protected]04b4a6c2008-08-02 00:44:471702 return;
1703 }
1704
initial.commit09911bf2008-07-26 23:55:291705 int index = tabstrip_model_.GetIndexOfTabContents(source);
1706 if (index == TabStripModel::kNoTab) {
1707 NOTREACHED() << "CloseContents called for tab not in our strip";
1708 return;
1709 }
1710 tabstrip_model_.CloseTabContentsAt(index);
1711}
1712
[email protected]15e8abe2008-08-20 22:40:401713void Browser::MoveContents(TabContents* source, const gfx::Rect& pos) {
[email protected]299dabd2008-11-19 02:27:161714 if (type() != TYPE_POPUP) {
initial.commit09911bf2008-07-26 23:55:291715 NOTREACHED() << "moving invalid browser type";
1716 return;
1717 }
[email protected]2d46c842008-11-14 19:24:311718 window_->SetBounds(pos);
initial.commit09911bf2008-07-26 23:55:291719}
1720
1721bool Browser::IsPopup(TabContents* source) {
1722 // A non-tabbed BROWSER is an unconstrained popup.
[email protected]299dabd2008-11-19 02:27:161723 return (type() == TYPE_POPUP);
initial.commit09911bf2008-07-26 23:55:291724}
1725
[email protected]36b6dcb2008-11-12 01:19:571726void Browser::ToolbarSizeChanged(TabContents* source, bool is_animating) {
1727 if (source == GetSelectedTabContents() || source == NULL) {
1728 // This will refresh the shelf if needed.
1729 window_->SelectedTabToolbarSizeChanged(is_animating);
1730 }
1731}
1732
1733void Browser::URLStarredChanged(TabContents* source, bool starred) {
1734 if (source == GetSelectedTabContents())
1735 SetStarredButtonToggled(starred);
1736}
1737
1738void Browser::ContentsMouseEvent(TabContents* source, UINT message) {
[email protected]be3877f2009-01-14 15:51:101739 if (!GetStatusBubble())
1740 return;
1741
[email protected]36b6dcb2008-11-12 01:19:571742 if (source == GetSelectedTabContents()) {
1743 if (message == WM_MOUSEMOVE) {
1744 GetStatusBubble()->MouseMoved();
1745 } else if (message == WM_MOUSELEAVE) {
1746 GetStatusBubble()->SetURL(GURL(), std::wstring());
1747 }
1748 }
1749}
1750
1751void Browser::UpdateTargetURL(TabContents* source, const GURL& url) {
[email protected]be3877f2009-01-14 15:51:101752 if (!GetStatusBubble())
1753 return;
1754
[email protected]36b6dcb2008-11-12 01:19:571755 if (source == GetSelectedTabContents()) {
1756 PrefService* prefs = profile_->GetPrefs();
1757 GetStatusBubble()->SetURL(url, prefs->GetString(prefs::kAcceptLanguages));
1758 }
1759}
1760
1761void Browser::ContentsZoomChange(bool zoom_in) {
1762 controller_.ExecuteCommand(zoom_in ? IDC_ZOOM_PLUS : IDC_ZOOM_MINUS);
1763}
1764
1765bool Browser::IsApplication() const {
[email protected]299dabd2008-11-19 02:27:161766 return type_ == TYPE_APP;
[email protected]36b6dcb2008-11-12 01:19:571767}
1768
1769void Browser::ConvertContentsToApplication(TabContents* contents) {
[email protected]64ff7942008-12-17 18:11:231770 WebContents* web_contents = contents->AsWebContents();
1771 if (!web_contents || !web_contents->web_app()) {
[email protected]36b6dcb2008-11-12 01:19:571772 NOTREACHED();
1773 return;
1774 }
1775
1776 int index = tabstrip_model_.GetIndexOfTabContents(contents);
1777 if (index < 0)
1778 return;
1779
[email protected]64ff7942008-12-17 18:11:231780 WebApp* app = web_contents->web_app();
1781 const std::wstring& app_name = app->name().empty() ?
1782 ComputeApplicationNameFromURL(app->url()) : app->name();
[email protected]36b6dcb2008-11-12 01:19:571783 RegisterAppPrefs(app_name);
1784
1785 tabstrip_model_.DetachTabContentsAt(index);
[email protected]15952e462008-11-14 00:29:051786 Browser* browser = Browser::CreateForApp(app_name, profile_);
1787 browser->tabstrip_model()->AppendTabContents(contents, true);
1788 browser->window()->Show();
[email protected]36b6dcb2008-11-12 01:19:571789}
1790
1791void Browser::ContentsStateChanged(TabContents* source) {
1792 int index = tabstrip_model_.GetIndexOfTabContents(source);
1793 if (index != TabStripModel::kNoTab)
1794 tabstrip_model_.UpdateTabContentsStateAt(index);
1795}
1796
1797bool Browser::ShouldDisplayURLField() {
1798 return !IsApplication();
1799}
1800
1801void Browser::BeforeUnloadFired(TabContents* tab,
1802 bool proceed,
1803 bool* proceed_to_fire_unload) {
1804 if (!is_attempting_to_close_browser_) {
1805 *proceed_to_fire_unload = proceed;
1806 return;
1807 }
1808
1809 if (!proceed) {
1810 CancelWindowClose();
1811 *proceed_to_fire_unload = false;
1812 return;
1813 }
1814
[email protected]06b42f032008-12-03 18:43:051815 if (RemoveFromSet(&tabs_needing_before_unload_fired_, tab)) {
[email protected]2d46c842008-11-14 19:24:311816 // Now that beforeunload has fired, put the tab on the queue to fire
1817 // unload.
[email protected]06b42f032008-12-03 18:43:051818 tabs_needing_unload_fired_.insert(tab);
[email protected]36b6dcb2008-11-12 01:19:571819 ProcessPendingTabs();
[email protected]adf650f2008-12-09 16:10:061820 // We want to handle firing the unload event ourselves since we want to
[email protected]36b6dcb2008-11-12 01:19:571821 // fire all the beforeunload events before attempting to fire the unload
1822 // events should the user cancel closing the browser.
1823 *proceed_to_fire_unload = false;
1824 return;
1825 }
1826
1827 *proceed_to_fire_unload = true;
1828}
1829
initial.commit09911bf2008-07-26 23:55:291830void Browser::ShowHtmlDialog(HtmlDialogContentsDelegate* delegate,
[email protected]2d46c842008-11-14 19:24:311831 void* parent_window) {
1832 window_->ShowHTMLDialog(delegate, parent_window);
initial.commit09911bf2008-07-26 23:55:291833}
1834
[email protected]36b6dcb2008-11-12 01:19:571835///////////////////////////////////////////////////////////////////////////////
1836// Browser, SelectFileDialog::Listener implementation:
1837
1838void Browser::FileSelected(const std::wstring& path, void* params) {
1839 GURL file_url = net::FilePathToFileURL(path);
1840 if (!file_url.is_empty())
1841 OpenURL(file_url, GURL(), CURRENT_TAB, PageTransition::TYPED);
1842}
1843
1844///////////////////////////////////////////////////////////////////////////////
1845// Browser, NotificationObserver implementation:
1846
initial.commit09911bf2008-07-26 23:55:291847void Browser::Observe(NotificationType type,
1848 const NotificationSource& source,
1849 const NotificationDetails& details) {
[email protected]e83f1682008-09-07 23:57:401850 switch (type) {
[email protected]e83f1682008-09-07 23:57:401851 case NOTIFY_WEB_CONTENTS_DISCONNECTED:
1852 if (is_attempting_to_close_browser_) {
1853 // Need to do this asynchronously as it will close the tab, which is
1854 // currently on the call stack above us.
1855 MessageLoop::current()->PostTask(FROM_HERE,
1856 method_factory_.NewRunnableMethod(&Browser::ClearUnloadState,
1857 Source<TabContents>(source).ptr()));
1858 }
1859 break;
1860
1861 case NOTIFY_SSL_STATE_CHANGED:
1862 // When the current tab's SSL state changes, we need to update the URL
[email protected]90e8d062008-09-08 02:26:321863 // bar to reflect the new state. Note that it's possible for the selected
1864 // tab contents to be NULL. This is because we listen for all sources
1865 // (NavigationControllers) for convenience, so the notification could
1866 // actually be for a different window while we're doing asynchronous
1867 // closing of this one.
1868 if (GetSelectedTabContents() &&
1869 GetSelectedTabContents()->controller() ==
[email protected]e83f1682008-09-07 23:57:401870 Source<NavigationController>(source).ptr())
[email protected]36b6dcb2008-11-12 01:19:571871 UpdateToolbar(false);
[email protected]e83f1682008-09-07 23:57:401872 break;
1873
1874 default:
1875 NOTREACHED() << "Got a notification we didn't register for.";
initial.commit09911bf2008-07-26 23:55:291876 }
1877}
1878
[email protected]36b6dcb2008-11-12 01:19:571879///////////////////////////////////////////////////////////////////////////////
1880// Browser, Command and state updating (private):
1881
1882void Browser::InitCommandState() {
1883 // All browser commands whose state isn't set automagically some other way
1884 // (like Back & Forward with initial page load) must have their state
1885 // initialized here, otherwise they will be forever disabled.
1886
[email protected]84214982008-12-10 18:49:101887 // Navigation commands
[email protected]36b6dcb2008-11-12 01:19:571888 controller_.UpdateCommandEnabled(IDC_RELOAD, true);
[email protected]84214982008-12-10 18:49:101889
1890 // Window management commands
1891 controller_.UpdateCommandEnabled(IDC_NEW_WINDOW, true);
1892 controller_.UpdateCommandEnabled(IDC_NEW_INCOGNITO_WINDOW, true);
[email protected]84214982008-12-10 18:49:101893 // TODO(pkasting): Perhaps the code that populates this submenu should do
1894 // this?
1895 controller_.UpdateCommandEnabled(IDC_NEW_WINDOW_PROFILE_0, true);
1896 controller_.UpdateCommandEnabled(IDC_NEW_WINDOW_PROFILE_1, true);
1897 controller_.UpdateCommandEnabled(IDC_NEW_WINDOW_PROFILE_2, true);
1898 controller_.UpdateCommandEnabled(IDC_NEW_WINDOW_PROFILE_3, true);
1899 controller_.UpdateCommandEnabled(IDC_NEW_WINDOW_PROFILE_4, true);
1900 controller_.UpdateCommandEnabled(IDC_NEW_WINDOW_PROFILE_5, true);
1901 controller_.UpdateCommandEnabled(IDC_NEW_WINDOW_PROFILE_6, true);
1902 controller_.UpdateCommandEnabled(IDC_NEW_WINDOW_PROFILE_7, true);
1903 controller_.UpdateCommandEnabled(IDC_NEW_WINDOW_PROFILE_8, true);
1904 controller_.UpdateCommandEnabled(IDC_CLOSE_WINDOW, true);
[email protected]f1d306e62008-12-08 20:50:051905 controller_.UpdateCommandEnabled(IDC_NEW_TAB, true);
1906 controller_.UpdateCommandEnabled(IDC_CLOSE_TAB, true);
[email protected]f1d306e62008-12-08 20:50:051907 controller_.UpdateCommandEnabled(IDC_DUPLICATE_TAB, true);
[email protected]84214982008-12-10 18:49:101908 controller_.UpdateCommandEnabled(IDC_EXIT, true);
1909
1910 // Page-related commands
1911 controller_.UpdateCommandEnabled(IDC_CLOSE_POPUPS, true);
[email protected]36b6dcb2008-11-12 01:19:571912 controller_.UpdateCommandEnabled(IDC_ENCODING_AUTO_DETECT, true);
1913 controller_.UpdateCommandEnabled(IDC_ENCODING_UTF8, true);
1914 controller_.UpdateCommandEnabled(IDC_ENCODING_UTF16LE, true);
1915 controller_.UpdateCommandEnabled(IDC_ENCODING_ISO88591, true);
1916 controller_.UpdateCommandEnabled(IDC_ENCODING_WINDOWS1252, true);
[email protected]1c5bf632008-12-11 20:30:491917 controller_.UpdateCommandEnabled(IDC_ENCODING_GBK, true);
[email protected]36b6dcb2008-11-12 01:19:571918 controller_.UpdateCommandEnabled(IDC_ENCODING_GB18030, true);
1919 controller_.UpdateCommandEnabled(IDC_ENCODING_BIG5HKSCS, true);
1920 controller_.UpdateCommandEnabled(IDC_ENCODING_BIG5, true);
1921 controller_.UpdateCommandEnabled(IDC_ENCODING_THAI, true);
1922 controller_.UpdateCommandEnabled(IDC_ENCODING_KOREAN, true);
1923 controller_.UpdateCommandEnabled(IDC_ENCODING_SHIFTJIS, true);
1924 controller_.UpdateCommandEnabled(IDC_ENCODING_ISO2022JP, true);
1925 controller_.UpdateCommandEnabled(IDC_ENCODING_EUCJP, true);
1926 controller_.UpdateCommandEnabled(IDC_ENCODING_ISO885915, true);
1927 controller_.UpdateCommandEnabled(IDC_ENCODING_MACINTOSH, true);
1928 controller_.UpdateCommandEnabled(IDC_ENCODING_ISO88592, true);
1929 controller_.UpdateCommandEnabled(IDC_ENCODING_WINDOWS1250, true);
1930 controller_.UpdateCommandEnabled(IDC_ENCODING_ISO88595, true);
1931 controller_.UpdateCommandEnabled(IDC_ENCODING_WINDOWS1251, true);
1932 controller_.UpdateCommandEnabled(IDC_ENCODING_KOI8R, true);
1933 controller_.UpdateCommandEnabled(IDC_ENCODING_KOI8U, true);
1934 controller_.UpdateCommandEnabled(IDC_ENCODING_ISO88597, true);
1935 controller_.UpdateCommandEnabled(IDC_ENCODING_WINDOWS1253, true);
1936 controller_.UpdateCommandEnabled(IDC_ENCODING_ISO88594, true);
1937 controller_.UpdateCommandEnabled(IDC_ENCODING_ISO885913, true);
1938 controller_.UpdateCommandEnabled(IDC_ENCODING_WINDOWS1257, true);
1939 controller_.UpdateCommandEnabled(IDC_ENCODING_ISO88593, true);
1940 controller_.UpdateCommandEnabled(IDC_ENCODING_ISO885910, true);
1941 controller_.UpdateCommandEnabled(IDC_ENCODING_ISO885914, true);
1942 controller_.UpdateCommandEnabled(IDC_ENCODING_ISO885916, true);
[email protected]36b6dcb2008-11-12 01:19:571943 controller_.UpdateCommandEnabled(IDC_ENCODING_WINDOWS1254, true);
1944 controller_.UpdateCommandEnabled(IDC_ENCODING_ISO88596, true);
1945 controller_.UpdateCommandEnabled(IDC_ENCODING_WINDOWS1256, true);
1946 controller_.UpdateCommandEnabled(IDC_ENCODING_ISO88598, true);
1947 controller_.UpdateCommandEnabled(IDC_ENCODING_WINDOWS1255, true);
1948 controller_.UpdateCommandEnabled(IDC_ENCODING_WINDOWS1258, true);
[email protected]84214982008-12-10 18:49:101949
1950 // Clipboard commands
1951 controller_.UpdateCommandEnabled(IDC_CUT, true);
1952 controller_.UpdateCommandEnabled(IDC_COPY, true);
1953 controller_.UpdateCommandEnabled(IDC_COPY_URL, true);
1954 controller_.UpdateCommandEnabled(IDC_PASTE, true);
1955
[email protected]84214982008-12-10 18:49:101956 // Show various bits of UI
1957 controller_.UpdateCommandEnabled(IDC_OPEN_FILE, true);
1958 controller_.UpdateCommandEnabled(IDC_CREATE_SHORTCUTS, false);
[email protected]84214982008-12-10 18:49:101959 controller_.UpdateCommandEnabled(IDC_TASK_MANAGER, true);
1960 controller_.UpdateCommandEnabled(IDC_SELECT_PROFILE, true);
[email protected]84214982008-12-10 18:49:101961 controller_.UpdateCommandEnabled(IDC_SHOW_HISTORY, true);
1962 controller_.UpdateCommandEnabled(IDC_SHOW_BOOKMARK_MANAGER, true);
1963 controller_.UpdateCommandEnabled(IDC_SHOW_DOWNLOADS, true);
[email protected]f1d306e62008-12-08 20:50:051964 controller_.UpdateCommandEnabled(IDC_HELP_PAGE, true);
[email protected]64ff7942008-12-17 18:11:231965
1966 // Initialize other commands based on the window type.
1967 {
1968 bool normal_window = type() == TYPE_NORMAL;
1969
1970 // Navigation commands
1971 controller_.UpdateCommandEnabled(IDC_HOME, normal_window);
1972 controller_.UpdateCommandEnabled(IDC_OPEN_CURRENT_URL, normal_window);
1973
1974 // Window management commands
1975 controller_.UpdateCommandEnabled(IDC_PROFILE_MENU, normal_window);
1976 controller_.UpdateCommandEnabled(IDC_SELECT_NEXT_TAB, normal_window);
1977 controller_.UpdateCommandEnabled(IDC_SELECT_PREVIOUS_TAB, normal_window);
1978 controller_.UpdateCommandEnabled(IDC_SELECT_TAB_0, normal_window);
1979 controller_.UpdateCommandEnabled(IDC_SELECT_TAB_1, normal_window);
1980 controller_.UpdateCommandEnabled(IDC_SELECT_TAB_2, normal_window);
1981 controller_.UpdateCommandEnabled(IDC_SELECT_TAB_3, normal_window);
1982 controller_.UpdateCommandEnabled(IDC_SELECT_TAB_4, normal_window);
1983 controller_.UpdateCommandEnabled(IDC_SELECT_TAB_5, normal_window);
1984 controller_.UpdateCommandEnabled(IDC_SELECT_TAB_6, normal_window);
1985 controller_.UpdateCommandEnabled(IDC_SELECT_TAB_7, normal_window);
1986 controller_.UpdateCommandEnabled(IDC_SELECT_LAST_TAB, normal_window);
1987 controller_.UpdateCommandEnabled(IDC_RESTORE_TAB,
1988 normal_window && !profile_->IsOffTheRecord());
1989 controller_.UpdateCommandEnabled(IDC_SHOW_AS_TAB, (type() == TYPE_POPUP));
1990
1991 // Focus various bits of UI
1992 controller_.UpdateCommandEnabled(IDC_FOCUS_TOOLBAR, normal_window);
1993 controller_.UpdateCommandEnabled(IDC_FOCUS_LOCATION, normal_window);
1994 controller_.UpdateCommandEnabled(IDC_FOCUS_SEARCH, normal_window);
1995
1996 // Show various bits of UI
1997 controller_.UpdateCommandEnabled(IDC_DEVELOPER_MENU, normal_window);
1998 controller_.UpdateCommandEnabled(IDC_DEBUGGER,
1999 // The debugger doesn't work in single process mode.
2000 normal_window && !RenderProcessHost::run_renderer_in_process());
2001 controller_.UpdateCommandEnabled(IDC_NEW_PROFILE, normal_window);
2002 controller_.UpdateCommandEnabled(IDC_REPORT_BUG, normal_window);
2003 controller_.UpdateCommandEnabled(IDC_SHOW_BOOKMARK_BAR, normal_window);
2004 controller_.UpdateCommandEnabled(IDC_CLEAR_BROWSING_DATA, normal_window);
2005 controller_.UpdateCommandEnabled(IDC_IMPORT_SETTINGS, normal_window);
2006 controller_.UpdateCommandEnabled(IDC_OPTIONS, normal_window);
2007 controller_.UpdateCommandEnabled(IDC_EDIT_SEARCH_ENGINES, normal_window);
2008 controller_.UpdateCommandEnabled(IDC_VIEW_PASSWORDS, normal_window);
2009 controller_.UpdateCommandEnabled(IDC_ABOUT, normal_window);
2010 }
[email protected]36b6dcb2008-11-12 01:19:572011}
2012
[email protected]84214982008-12-10 18:49:102013void Browser::UpdateCommandsForTabState() {
[email protected]c7c42332008-11-15 01:10:542014 TabContents* current_tab = GetSelectedTabContents();
[email protected]64ff7942008-12-17 18:11:232015 if (!current_tab) // May be NULL during tab restore.
[email protected]d8375fd2008-11-25 22:45:392016 return;
[email protected]d8375fd2008-11-25 22:45:392017
[email protected]84214982008-12-10 18:49:102018 // Navigation commands
initial.commit09911bf2008-07-26 23:55:292019 NavigationController* nc = current_tab->controller();
2020 controller_.UpdateCommandEnabled(IDC_BACK, nc->CanGoBack());
2021 controller_.UpdateCommandEnabled(IDC_FORWARD, nc->CanGoForward());
2022
[email protected]84214982008-12-10 18:49:102023 // Window management commands
2024 controller_.UpdateCommandEnabled(IDC_DUPLICATE_TAB,
2025 CanDuplicateContentsAt(selected_index()));
2026
[email protected]64ff7942008-12-17 18:11:232027 // Initialize commands available only for web content.
2028 {
2029 WebContents* web_contents = current_tab->AsWebContents();
2030 bool is_web_contents = web_contents != NULL;
[email protected]84214982008-12-10 18:49:102031
[email protected]84214982008-12-10 18:49:102032 // Page-related commands
[email protected]5d3611d2008-12-11 00:41:262033 // Only allow bookmarking for tabbed browsers.
[email protected]64ff7942008-12-17 18:11:232034 controller_.UpdateCommandEnabled(IDC_STAR,
2035 is_web_contents && (type() == TYPE_NORMAL));
2036 SetStarredButtonToggled(is_web_contents && web_contents->is_starred());
initial.commit09911bf2008-07-26 23:55:292037 // View-source should not be enabled if already in view-source mode.
[email protected]f1d306e62008-12-08 20:50:052038 controller_.UpdateCommandEnabled(IDC_VIEW_SOURCE,
[email protected]64ff7942008-12-17 18:11:232039 is_web_contents && (current_tab->type() != TAB_CONTENTS_VIEW_SOURCE) &&
initial.commit09911bf2008-07-26 23:55:292040 current_tab->controller()->GetActiveEntry());
[email protected]64ff7942008-12-17 18:11:232041 controller_.UpdateCommandEnabled(IDC_PRINT, is_web_contents);
[email protected]f1d306e62008-12-08 20:50:052042 controller_.UpdateCommandEnabled(IDC_SAVE_PAGE,
[email protected]64ff7942008-12-17 18:11:232043 is_web_contents && SavePackage::IsSavableURL(current_tab->GetURL()));
[email protected]84214982008-12-10 18:49:102044 controller_.UpdateCommandEnabled(IDC_ENCODING_MENU,
[email protected]64ff7942008-12-17 18:11:232045 is_web_contents &&
[email protected]84214982008-12-10 18:49:102046 SavePackage::IsSavableContents(web_contents->contents_mime_type()) &&
2047 SavePackage::IsSavableURL(current_tab->GetURL()));
2048
2049 // Find-in-page
[email protected]64ff7942008-12-17 18:11:232050 controller_.UpdateCommandEnabled(IDC_FIND, is_web_contents);
2051 controller_.UpdateCommandEnabled(IDC_FIND_NEXT, is_web_contents);
2052 controller_.UpdateCommandEnabled(IDC_FIND_PREVIOUS, is_web_contents);
initial.commit09911bf2008-07-26 23:55:292053
[email protected]84214982008-12-10 18:49:102054 // Zoom
[email protected]64ff7942008-12-17 18:11:232055 controller_.UpdateCommandEnabled(IDC_ZOOM_MENU, is_web_contents);
2056 controller_.UpdateCommandEnabled(IDC_ZOOM_PLUS, is_web_contents);
2057 controller_.UpdateCommandEnabled(IDC_ZOOM_NORMAL, is_web_contents);
2058 controller_.UpdateCommandEnabled(IDC_ZOOM_MINUS, is_web_contents);
[email protected]84214982008-12-10 18:49:102059
2060 // Show various bits of UI
[email protected]64ff7942008-12-17 18:11:232061 controller_.UpdateCommandEnabled(IDC_JS_CONSOLE, is_web_contents);
2062 controller_.UpdateCommandEnabled(IDC_CREATE_SHORTCUTS,
2063 is_web_contents && !current_tab->GetFavIcon().isNull());
[email protected]f2530062008-12-03 23:52:032064 }
initial.commit09911bf2008-07-26 23:55:292065}
2066
[email protected]64ff7942008-12-17 18:11:232067void Browser::UpdateStopGoState(bool is_loading) {
[email protected]be3877f2009-01-14 15:51:102068 GoButton* go_button = GetGoButton();
2069 if (!go_button)
2070 return;
2071
2072 go_button->ChangeMode(is_loading ?
[email protected]64ff7942008-12-17 18:11:232073 GoButton::MODE_STOP : GoButton::MODE_GO);
2074 controller_.UpdateCommandEnabled(IDC_GO, !is_loading);
2075 controller_.UpdateCommandEnabled(IDC_STOP, is_loading);
2076}
2077
[email protected]36b6dcb2008-11-12 01:19:572078void Browser::SetStarredButtonToggled(bool starred) {
[email protected]be3877f2009-01-14 15:51:102079 ToolbarStarToggle* star_button = window_->GetStarButton();
2080 if (!star_button)
2081 return;
2082
2083 star_button->SetToggled(starred);
initial.commit09911bf2008-07-26 23:55:292084}
2085
[email protected]36b6dcb2008-11-12 01:19:572086///////////////////////////////////////////////////////////////////////////////
2087// Browser, UI update coalescing and handling (private):
2088
2089void Browser::UpdateToolbar(bool should_restore_state) {
2090 window_->UpdateToolbar(GetSelectedTabContents(), should_restore_state);
initial.commit09911bf2008-07-26 23:55:292091}
2092
[email protected]36b6dcb2008-11-12 01:19:572093void Browser::ScheduleUIUpdate(const TabContents* source,
2094 unsigned changed_flags) {
2095 // Synchronously update the URL.
2096 if (changed_flags & TabContents::INVALIDATE_URL &&
2097 source == GetSelectedTabContents()) {
2098 // Only update the URL for the current tab. Note that we do not update
2099 // the navigation commands since those would have already been updated
2100 // synchronously by NavigationStateChanged.
2101 UpdateToolbar(false);
2102
2103 if (changed_flags == TabContents::INVALIDATE_URL)
2104 return; // Just had an update URL and nothing else.
2105 }
2106
2107 // Save the dirty bits.
2108 scheduled_updates_.push_back(UIUpdate(source, changed_flags));
2109
2110 if (chrome_updater_factory_.empty()) {
2111 // No task currently scheduled, start another.
2112 MessageLoop::current()->PostDelayedTask(FROM_HERE,
2113 chrome_updater_factory_.NewRunnableMethod(
2114 &Browser::ProcessPendingUIUpdates),
2115 kUIUpdateCoalescingTimeMS);
2116 }
2117}
2118
2119void Browser::ProcessPendingUIUpdates() {
2120#ifndef NDEBUG
2121 // Validate that all tabs we have pending updates for exist. This is scary
2122 // because the pending list must be kept in sync with any detached or
2123 // deleted tabs. This code does not dereference any TabContents pointers.
2124 for (size_t i = 0; i < scheduled_updates_.size(); i++) {
2125 bool found = false;
2126 for (int tab = 0; tab < tab_count(); tab++) {
2127 if (GetTabContentsAt(tab)->controller() ==
2128 scheduled_updates_[i].source->controller()) {
2129 found = true;
2130 break;
2131 }
2132 }
2133 DCHECK(found);
2134 }
2135#endif
2136
2137 chrome_updater_factory_.RevokeAll();
2138
[email protected]2d46c842008-11-14 19:24:312139 // We could have many updates for the same thing in the queue. This map
2140 // tracks the bits of the stuff we've already updated for each TabContents so
2141 // we don't update again.
[email protected]36b6dcb2008-11-12 01:19:572142 typedef std::map<const TabContents*, unsigned> UpdateTracker;
2143 UpdateTracker updated_stuff;
2144
2145 for (size_t i = 0; i < scheduled_updates_.size(); i++) {
2146 // Do not dereference |contents|, it may be out-of-date!
2147 const TabContents* contents = scheduled_updates_[i].source;
2148 unsigned flags = scheduled_updates_[i].changed_flags;
2149
2150 // Remove any bits we have already updated, and save the new bits.
2151 UpdateTracker::iterator updated = updated_stuff.find(contents);
2152 if (updated != updated_stuff.end()) {
2153 // Turn off bits already set.
2154 flags &= ~updated->second;
2155 if (!flags)
2156 continue;
2157
2158 updated->second |= flags;
2159 } else {
2160 updated_stuff[contents] = flags;
2161 }
2162
2163 // Updates to the title or favicon require a tab repaint. However, the
2164 // inverse is not true since updates to the title also update the window
2165 // title.
2166 bool invalidate_tab = false;
2167 if (flags & TabContents::INVALIDATE_TITLE ||
2168 flags & TabContents::INVALIDATE_FAVICON) {
2169 invalidate_tab = true;
2170
2171 // Anything that repaints the tab means the favicon is updated.
2172 updated_stuff[contents] |= TabContents::INVALIDATE_FAVICON;
2173 }
2174
2175 // Updating the URL happens synchronously in ScheduleUIUpdate.
2176
[email protected]be3877f2009-01-14 15:51:102177 if (flags & TabContents::INVALIDATE_LOAD && GetStatusBubble())
[email protected]36b6dcb2008-11-12 01:19:572178 GetStatusBubble()->SetStatus(GetSelectedTabContents()->GetStatusText());
2179
2180 if (invalidate_tab) { // INVALIDATE_TITLE or INVALIDATE_FAVICON.
2181 tabstrip_model_.UpdateTabContentsStateAt(
2182 tabstrip_model_.GetIndexOfController(contents->controller()));
2183 window_->UpdateTitleBar();
2184
2185 if (contents == GetSelectedTabContents()) {
2186 TabContents* current_tab = GetSelectedTabContents();
[email protected]f1d306e62008-12-08 20:50:052187 controller_.UpdateCommandEnabled(IDC_CREATE_SHORTCUTS,
[email protected]36b6dcb2008-11-12 01:19:572188 current_tab->type() == TAB_CONTENTS_WEB &&
2189 !current_tab->GetFavIcon().isNull());
2190 }
2191 }
2192
2193 // We don't need to process INVALIDATE_STATE, since that's not visible.
2194 }
2195
2196 scheduled_updates_.clear();
2197}
2198
2199void Browser::RemoveScheduledUpdatesFor(TabContents* contents) {
2200 if (!contents)
2201 return;
2202
2203 // Remove any pending UI updates for the detached tab.
2204 UpdateVector::iterator cur_update = scheduled_updates_.begin();
2205 while (cur_update != scheduled_updates_.end()) {
2206 if (cur_update->source == contents) {
2207 cur_update = scheduled_updates_.erase(cur_update);
2208 } else {
2209 ++cur_update;
initial.commit09911bf2008-07-26 23:55:292210 }
2211 }
2212}
2213
[email protected]36b6dcb2008-11-12 01:19:572214///////////////////////////////////////////////////////////////////////////////
2215// Browser, Getters for UI (private):
initial.commit09911bf2008-07-26 23:55:292216
[email protected]36b6dcb2008-11-12 01:19:572217LocationBarView* Browser::GetLocationBarView() const {
2218 return window_->GetLocationBarView();
initial.commit09911bf2008-07-26 23:55:292219}
2220
2221GoButton* Browser::GetGoButton() {
[email protected]195442e2008-07-31 22:41:282222 return window_->GetGoButton();
initial.commit09911bf2008-07-26 23:55:292223}
2224
[email protected]36b6dcb2008-11-12 01:19:572225StatusBubble* Browser::GetStatusBubble() {
2226 return window_->GetStatusBubble();
initial.commit09911bf2008-07-26 23:55:292227}
2228
[email protected]36b6dcb2008-11-12 01:19:572229///////////////////////////////////////////////////////////////////////////////
2230// Browser, Session restore functions (private):
initial.commit09911bf2008-07-26 23:55:292231
2232void Browser::SyncHistoryWithTabs(int index) {
2233 if (!profile()->HasSessionService())
2234 return;
2235 SessionService* session_service = profile()->GetSessionService();
2236 if (session_service) {
2237 for (int i = index; i < tab_count(); ++i) {
2238 TabContents* contents = GetTabContentsAt(i);
2239 if (contents) {
2240 session_service->SetTabIndexInWindow(
2241 session_id(), contents->controller()->session_id(), i);
2242 }
2243 }
2244 }
2245}
2246
[email protected]36b6dcb2008-11-12 01:19:572247NavigationController* Browser::BuildRestoredNavigationController(
2248 const std::vector<TabNavigation>& navigations,
2249 int selected_navigation) {
2250 if (!navigations.empty()) {
2251 DCHECK(selected_navigation >= 0 &&
2252 selected_navigation < static_cast<int>(navigations.size()));
[email protected]36b6dcb2008-11-12 01:19:572253 // Create a NavigationController. This constructor creates the appropriate
2254 // set of TabContents.
[email protected]ec322ff2008-11-19 22:53:302255 return new NavigationController(profile_, navigations, selected_navigation);
[email protected]36b6dcb2008-11-12 01:19:572256 } else {
2257 // No navigations. Create a tab with about:blank.
2258 TabContents* contents =
2259 CreateTabContentsForURL(GURL("about:blank"), GURL(), profile_,
2260 PageTransition::START_PAGE, false, NULL);
2261 return new NavigationController(contents, profile_);
initial.commit09911bf2008-07-26 23:55:292262 }
2263}
2264
[email protected]36b6dcb2008-11-12 01:19:572265///////////////////////////////////////////////////////////////////////////////
2266// Browser, OnBeforeUnload handling (private):
initial.commit09911bf2008-07-26 23:55:292267
[email protected]04b4a6c2008-08-02 00:44:472268void Browser::ProcessPendingTabs() {
2269 DCHECK(is_attempting_to_close_browser_);
initial.commit09911bf2008-07-26 23:55:292270
[email protected]04b4a6c2008-08-02 00:44:472271 if (HasCompletedUnloadProcessing()) {
2272 // We've finished all the unload events and can proceed to close the
2273 // browser.
2274 OnWindowClosing();
initial.commit09911bf2008-07-26 23:55:292275 return;
2276 }
2277
[email protected]04b4a6c2008-08-02 00:44:472278 // Process beforeunload tabs first. When that queue is empty, process
2279 // unload tabs.
[email protected]04b4a6c2008-08-02 00:44:472280 if (!tabs_needing_before_unload_fired_.empty()) {
[email protected]06b42f032008-12-03 18:43:052281 TabContents* tab = *(tabs_needing_before_unload_fired_.begin());
[email protected]1f5af4442008-09-25 22:11:062282 tab->AsWebContents()->render_view_host()->FirePageBeforeUnload();
[email protected]04b4a6c2008-08-02 00:44:472283 } else if (!tabs_needing_unload_fired_.empty()) {
initial.commit09911bf2008-07-26 23:55:292284 // We've finished firing all beforeunload events and can proceed with unload
2285 // events.
2286 // TODO(ojan): We should add a call to browser_shutdown::OnShutdownStarting
2287 // somewhere around here so that we have accurate measurements of shutdown
2288 // time.
[email protected]04b4a6c2008-08-02 00:44:472289 // TODO(ojan): We can probably fire all the unload events in parallel and
2290 // get a perf benefit from that in the cases where the tab hangs in it's
2291 // unload handler or takes a long time to page in.
[email protected]06b42f032008-12-03 18:43:052292 TabContents* tab = *(tabs_needing_unload_fired_.begin());
[email protected]1f5af4442008-09-25 22:11:062293 tab->AsWebContents()->render_view_host()->FirePageUnload();
initial.commit09911bf2008-07-26 23:55:292294 } else {
[email protected]04b4a6c2008-08-02 00:44:472295 NOTREACHED();
initial.commit09911bf2008-07-26 23:55:292296 }
2297}
2298
[email protected]04b4a6c2008-08-02 00:44:472299bool Browser::HasCompletedUnloadProcessing() {
2300 return is_attempting_to_close_browser_ &&
2301 tabs_needing_before_unload_fired_.empty() &&
2302 tabs_needing_unload_fired_.empty();
2303}
2304
2305void Browser::CancelWindowClose() {
2306 DCHECK(is_attempting_to_close_browser_);
2307 // Only cancelling beforeunload should be able to cancel the window's close.
2308 // So there had better be a tab that we think needs beforeunload fired.
2309 DCHECK(!tabs_needing_before_unload_fired_.empty());
2310
[email protected]8f673f3a2008-08-05 22:34:282311 tabs_needing_before_unload_fired_.clear();
2312 tabs_needing_unload_fired_.clear();
[email protected]04b4a6c2008-08-02 00:44:472313
2314 is_attempting_to_close_browser_ = false;
2315}
2316
[email protected]06b42f032008-12-03 18:43:052317bool Browser::RemoveFromSet(UnloadListenerSet* set, TabContents* tab) {
[email protected]04b4a6c2008-08-02 00:44:472318 DCHECK(is_attempting_to_close_browser_);
2319
[email protected]06b42f032008-12-03 18:43:052320 UnloadListenerSet::iterator iter = std::find(set->begin(), set->end(), tab);
2321 if (iter != set->end()) {
2322 set->erase(iter);
2323 return true;
[email protected]04b4a6c2008-08-02 00:44:472324 }
2325 return false;
2326}
initial.commit09911bf2008-07-26 23:55:292327
[email protected]36b6dcb2008-11-12 01:19:572328void Browser::ClearUnloadState(TabContents* tab) {
2329 DCHECK(is_attempting_to_close_browser_);
[email protected]06b42f032008-12-03 18:43:052330 RemoveFromSet(&tabs_needing_before_unload_fired_, tab);
2331 RemoveFromSet(&tabs_needing_unload_fired_, tab);
[email protected]36b6dcb2008-11-12 01:19:572332 ProcessPendingTabs();
initial.commit09911bf2008-07-26 23:55:292333}
2334
[email protected]36b6dcb2008-11-12 01:19:572335///////////////////////////////////////////////////////////////////////////////
2336// Browser, Assorted utility functions (private):
initial.commit09911bf2008-07-26 23:55:292337
initial.commit09911bf2008-07-26 23:55:292338Browser* Browser::GetOrCreateTabbedBrowser() {
2339 Browser* browser = BrowserList::FindBrowserWithType(
[email protected]299dabd2008-11-19 02:27:162340 profile_, TYPE_NORMAL);
[email protected]15952e462008-11-14 00:29:052341 if (!browser)
2342 browser = Browser::Create(profile_);
initial.commit09911bf2008-07-26 23:55:292343 return browser;
2344}
2345
initial.commit09911bf2008-07-26 23:55:292346void Browser::BuildPopupWindow(TabContents* source,
2347 TabContents* new_contents,
2348 const gfx::Rect& initial_pos) {
[email protected]64ff7942008-12-17 18:11:232349 Browser* browser =
2350 new Browser((type_ == TYPE_APP) ? TYPE_APP : TYPE_POPUP, profile_);
[email protected]15952e462008-11-14 00:29:052351 browser->set_override_bounds(initial_pos);
2352 browser->CreateBrowserWindow();
[email protected]2f69fb52008-12-12 18:50:392353 // We need to Show before AddNewContents, otherwise AddNewContents will focus
2354 // it (via BrowserView::TabSelectedAt calling RestoreFocus), triggering any
2355 // onblur="" handlers.
2356 browser->window()->Show();
[email protected]15952e462008-11-14 00:29:052357 // TODO(beng): See if this can be made to use
2358 // TabStripModel::AppendTabContents.
2359 browser->AddNewContents(source, new_contents, NEW_FOREGROUND_TAB,
2360 gfx::Rect(), true);
initial.commit09911bf2008-07-26 23:55:292361}
2362
[email protected]36b6dcb2008-11-12 01:19:572363GURL Browser::GetHomePage() {
[email protected]15952e462008-11-14 00:29:052364 if (profile_->GetPrefs()->GetBoolean(prefs::kHomePageIsNewTabPage))
[email protected]36b6dcb2008-11-12 01:19:572365 return NewTabUIURL();
[email protected]15952e462008-11-14 00:29:052366 GURL home_page = GURL(URLFixerUpper::FixupURL(
2367 profile_->GetPrefs()->GetString(prefs::kHomePage),
2368 std::wstring()));
2369 if (!home_page.is_valid())
2370 return NewTabUIURL();
2371 return home_page;
[email protected]36b6dcb2008-11-12 01:19:572372}
initial.commit09911bf2008-07-26 23:55:292373
[email protected]fbd77592008-11-12 20:50:272374void Browser::AdvanceFindSelection(bool forward_direction) {
2375 GetSelectedTabContents()->AsWebContents()->view()->FindInPage(
2376 *this, true, forward_direction);
2377}
2378
[email protected]36b6dcb2008-11-12 01:19:572379void Browser::CloseFrame() {
2380 window_->Close();
initial.commit09911bf2008-07-26 23:55:292381}
2382
2383// static
2384std::wstring Browser::ComputeApplicationNameFromURL(const GURL& url) {
2385 std::string t;
2386 t.append(url.host());
2387 t.append("_");
2388 t.append(url.path());
2389 return UTF8ToWide(t);
2390}
2391
2392// static
initial.commit09911bf2008-07-26 23:55:292393void Browser::RegisterAppPrefs(const std::wstring& app_name) {
2394 // A set of apps that we've already started.
2395 static std::set<std::wstring>* g_app_names = NULL;
2396
2397 if (!g_app_names)
2398 g_app_names = new std::set<std::wstring>;
2399
2400 // Only register once for each app name.
2401 if (g_app_names->find(app_name) != g_app_names->end())
2402 return;
2403 g_app_names->insert(app_name);
2404
2405 // We need to register the window position pref.
2406 std::wstring window_pref(prefs::kBrowserWindowPlacement);
2407 window_pref.append(L"_");
2408 window_pref.append(app_name);
2409 PrefService* prefs = g_browser_process->local_state();
2410 DCHECK(prefs);
2411
2412 prefs->RegisterDictionaryPref(window_pref.c_str());
2413}