blob: b3b539a4bd97e5c52554095dc713d47d8f1a63af [file] [log] [blame]
[email protected]4801ecc2009-04-05 04:52:581// Copyright (c) 2006-2009 The Chromium Authors. All rights reserved.
license.botbf09a502008-08-24 00:55:552// 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
[email protected]c61db1d2009-02-06 03:39:185#include "chrome/browser/browser.h"
6
[email protected]a92b8642009-05-05 23:38:567#include "app/l10n_util.h"
[email protected]8a53ee042009-01-21 16:41:338#include "base/command_line.h"
9#include "base/idle_timer.h"
10#include "base/logging.h"
11#include "base/string_util.h"
[email protected]b689fce72009-03-17 22:45:3412#include "base/thread.h"
[email protected]88d74942009-01-21 22:04:4413#include "chrome/app/chrome_dll_resource.h"
[email protected]a9afddb2009-02-12 17:49:4214#include "chrome/browser/bookmarks/bookmark_model.h"
[email protected]8a53ee042009-01-21 16:41:3315#include "chrome/browser/browser_list.h"
[email protected]c61db1d2009-02-06 03:39:1816#include "chrome/browser/browser_shutdown.h"
[email protected]c98fe6f2009-02-25 20:33:2317#include "chrome/browser/browser_window.h"
[email protected]40d59ce52009-03-06 23:20:1418#include "chrome/browser/character_encoding.h"
[email protected]0800c662009-05-08 19:41:4919#include "chrome/browser/debugger/debugger_host.h"
[email protected]40ecc902009-03-16 13:42:4720#include "chrome/browser/debugger/devtools_manager.h"
[email protected]69444cc2009-04-09 20:40:0621#include "chrome/browser/download/download_manager.h"
[email protected]4801ecc2009-04-05 04:52:5822#include "chrome/browser/find_bar.h"
23#include "chrome/browser/find_bar_controller.h"
[email protected]7745b822009-01-27 20:15:3524#include "chrome/browser/location_bar.h"
[email protected]d938aed92009-01-22 19:49:3325#include "chrome/browser/metrics/user_metrics.h"
[email protected]a239c3f2009-02-17 22:13:1926#include "chrome/browser/net/url_fixer_upper.h"
[email protected]0e3e3e32009-05-14 01:00:5327#include "chrome/browser/options_window.h"
[email protected]f7011fcb2009-01-28 21:54:3228#include "chrome/browser/profile.h"
[email protected]85e921fb82009-02-11 23:19:4429#include "chrome/browser/sessions/session_service.h"
[email protected]c61db1d2009-02-06 03:39:1830#include "chrome/browser/sessions/session_types.h"
[email protected]bd580a252009-02-12 01:16:3031#include "chrome/browser/sessions/tab_restore_service.h"
[email protected]abf6c7a2009-03-03 16:24:1032#include "chrome/browser/status_bubble.h"
[email protected]a165a052009-02-18 21:43:0033#include "chrome/browser/tab_contents/interstitial_page.h"
[email protected]c61db1d2009-02-06 03:39:1834#include "chrome/browser/tab_contents/navigation_controller.h"
35#include "chrome/browser/tab_contents/navigation_entry.h"
36#include "chrome/browser/tab_contents/site_instance.h"
[email protected]57c6a652009-05-04 07:58:3437#include "chrome/browser/tab_contents/tab_contents.h"
[email protected]81af9392009-04-21 02:37:4538#include "chrome/browser/tab_contents/tab_contents_view.h"
[email protected]4d34e2e2009-05-26 22:55:2839#include "chrome/browser/window_sizer.h"
[email protected]d938aed92009-01-22 19:49:3340#include "chrome/common/chrome_constants.h"
41#include "chrome/common/chrome_switches.h"
[email protected]5b1a0e22009-05-26 19:00:5842#include "chrome/common/extensions/extension.h"
[email protected]bfd04a62009-02-01 18:16:5643#include "chrome/common/notification_service.h"
[email protected]d938aed92009-01-22 19:49:3344#include "chrome/common/page_transition_types.h"
[email protected]8a53ee042009-01-21 16:41:3345#include "chrome/common/pref_names.h"
46#include "chrome/common/pref_service.h"
[email protected]b689fce72009-03-17 22:45:3447#include "chrome/common/url_constants.h"
[email protected]026e34a2009-02-06 00:06:1248#ifdef CHROME_PERSONALIZATION
49#include "chrome/personalization/personalization.h"
50#endif
[email protected]a3e18c42009-03-04 23:36:0551#include "grit/chromium_strings.h"
52#include "grit/generated_resources.h"
53#include "grit/locale_settings.h"
[email protected]8a53ee042009-01-21 16:41:3354#include "net/base/cookie_monster.h"
55#include "net/base/cookie_policy.h"
[email protected]2bfd94d2009-04-29 20:32:0356#include "net/base/mime_util.h"
[email protected]8a53ee042009-01-21 16:41:3357#include "net/base/net_util.h"
58#include "net/base/registry_controlled_domain.h"
59#include "net/url_request/url_request_context.h"
[email protected]d938aed92009-01-22 19:49:3360#include "webkit/glue/window_open_disposition.h"
[email protected]8a53ee042009-01-21 16:41:3361
62#if defined(OS_WIN)
initial.commit09911bf2008-07-26 23:55:2963#include <windows.h>
64#include <shellapi.h>
65
[email protected]4a0765a2009-05-08 23:12:2566#include "app/win_util.h"
[email protected]36b6dcb2008-11-12 01:19:5767#include "chrome/browser/automation/ui_controls.h"
initial.commit09911bf2008-07-26 23:55:2968#include "chrome/browser/browser_process.h"
initial.commit09911bf2008-07-26 23:55:2969#include "chrome/browser/browser_url_handler.h"
70#include "chrome/browser/cert_store.h"
[email protected]1eb89e82008-08-15 12:27:0371#include "chrome/browser/debugger/debugger_window.h"
[email protected]37936ee2008-09-14 01:09:5072#include "chrome/browser/download/save_package.h"
[email protected]3b073b22009-01-16 03:29:0373#include "chrome/browser/ssl/ssl_error_info.h"
[email protected]36b6dcb2008-11-12 01:19:5774#include "chrome/browser/task_manager.h"
[email protected]f2530062008-12-03 23:52:0375#include "chrome/browser/user_data_manager.h"
initial.commit09911bf2008-07-26 23:55:2976#include "chrome/browser/view_ids.h"
initial.commit09911bf2008-07-26 23:55:2977#include "chrome/browser/views/location_bar_view.h"
[email protected]6dffde322009-02-18 03:47:4878#include "chrome/common/child_process_host.h"
[email protected]8a53ee042009-01-21 16:41:3379#endif // OS_WIN
[email protected]e1acf6f2008-10-27 20:43:3380
[email protected]7d3feb912009-05-15 20:37:4281#if defined(TOOLKIT_VIEWS)
82#include "chrome/browser/dock_info.h"
83#endif
84
[email protected]8a53ee042009-01-21 16:41:3385using base::TimeDelta;
initial.commit09911bf2008-07-26 23:55:2986
87// How long we wait before updating the browser chrome while loading a page.
88static const int kUIUpdateCoalescingTimeMS = 200;
89
90// Idle time before helping prune memory consumption.
91static const int kBrowserReleaseMemoryInterval = 30; // In seconds.
92
[email protected]36b6dcb2008-11-12 01:19:5793///////////////////////////////////////////////////////////////////////////////
initial.commit09911bf2008-07-26 23:55:2994
[email protected]a436d922009-02-13 23:16:4295// A task to reduce the working set of the child processes that live on the IO
96// thread (i.e. plugins, workers).
97class ReduceChildProcessesWorkingSetTask : public Task {
initial.commit09911bf2008-07-26 23:55:2998 public:
99 virtual void Run() {
[email protected]8a53ee042009-01-21 16:41:33100#if defined(OS_WIN)
[email protected]6dffde322009-02-18 03:47:48101 for (ChildProcessHost::Iterator iter; !iter.Done(); ++iter)
102 iter->ReduceWorkingSet();
[email protected]8a53ee042009-01-21 16:41:33103#endif
initial.commit09911bf2008-07-26 23:55:29104 }
105};
106
107// A browser task to run when the user is not using the browser.
108// In our case, we're trying to be nice to the operating system and release
109// memory not in use.
[email protected]aeab57ea2008-08-28 20:50:12110class BrowserIdleTimer : public base::IdleTimer {
initial.commit09911bf2008-07-26 23:55:29111 public:
[email protected]aeab57ea2008-08-28 20:50:12112 BrowserIdleTimer()
113 : base::IdleTimer(TimeDelta::FromSeconds(kBrowserReleaseMemoryInterval),
114 false) {
initial.commit09911bf2008-07-26 23:55:29115 }
116
117 virtual void OnIdle() {
[email protected]8a53ee042009-01-21 16:41:33118#if defined(OS_WIN)
initial.commit09911bf2008-07-26 23:55:29119 // We're idle. Release browser and renderer unused pages.
120
121 // Handle the Browser.
[email protected]176aa482008-11-14 03:25:15122 base::Process process(GetCurrentProcess());
initial.commit09911bf2008-07-26 23:55:29123 process.ReduceWorkingSet();
124
125 // Handle the Renderer(s).
126 RenderProcessHost::iterator renderer_iter;
127 for (renderer_iter = RenderProcessHost::begin(); renderer_iter !=
[email protected]176aa482008-11-14 03:25:15128 RenderProcessHost::end(); renderer_iter++) {
129 base::Process process = renderer_iter->second->process();
initial.commit09911bf2008-07-26 23:55:29130 process.ReduceWorkingSet();
131 }
132
[email protected]a436d922009-02-13 23:16:42133 // Handle the child processe. We need to iterate through them on the IO
134 // thread because that thread manages the child process collection.
initial.commit09911bf2008-07-26 23:55:29135 g_browser_process->io_thread()->message_loop()->PostTask(FROM_HERE,
[email protected]a436d922009-02-13 23:16:42136 new ReduceChildProcessesWorkingSetTask());
[email protected]8a53ee042009-01-21 16:41:33137#endif
initial.commit09911bf2008-07-26 23:55:29138 }
139};
140
[email protected]36b6dcb2008-11-12 01:19:57141///////////////////////////////////////////////////////////////////////////////
initial.commit09911bf2008-07-26 23:55:29142
143struct Browser::UIUpdate {
144 UIUpdate(const TabContents* src, unsigned flags)
145 : source(src),
146 changed_flags(flags) {
147 }
148
149 // The source of the update.
150 const TabContents* source;
151
152 // What changed in the UI.
153 unsigned changed_flags;
154};
155
[email protected]505323e22009-01-24 02:47:58156namespace {
157
158// Returns true if the specified TabContents has unload listeners registered.
159bool TabHasUnloadListener(TabContents* contents) {
[email protected]57c6a652009-05-04 07:58:34160 return contents->notify_disconnection() &&
161 !contents->showing_interstitial_page() &&
162 !contents->render_view_host()->SuddenTerminationAllowed();
[email protected]505323e22009-01-24 02:47:58163}
164
165} // namespace
166
[email protected]36b6dcb2008-11-12 01:19:57167///////////////////////////////////////////////////////////////////////////////
168// Browser, Constructors, Creation, Showing:
initial.commit09911bf2008-07-26 23:55:29169
[email protected]299dabd2008-11-19 02:27:16170Browser::Browser(Type type, Profile* profile)
[email protected]15952e462008-11-14 00:29:05171 : type_(type),
172 profile_(profile),
[email protected]f3e99e32008-07-30 04:48:39173 window_(NULL),
initial.commit09911bf2008-07-26 23:55:29174 tabstrip_model_(this, profile),
[email protected]1fc025202009-01-20 23:03:14175 command_updater_(this),
initial.commit09911bf2008-07-26 23:55:29176 toolbar_model_(this),
[email protected]15952e462008-11-14 00:29:05177 chrome_updater_factory_(this),
178 is_attempting_to_close_browser_(false),
[email protected]69444cc2009-04-09 20:40:06179 cancel_download_confirmation_state_(NOT_PROMPTED),
[email protected]2e716622009-03-09 21:11:01180 maximized_state_(MAXIMIZED_STATE_DEFAULT),
[email protected]15952e462008-11-14 00:29:05181 method_factory_(this),
[email protected]ebdcf9742009-01-23 05:25:28182 idle_task_(new BrowserIdleTimer) {
initial.commit09911bf2008-07-26 23:55:29183 tabstrip_model_.AddObserver(this);
184
[email protected]0cb94102009-05-22 19:51:21185 registrar_.Add(this, NotificationType::SSL_VISIBLE_STATE_CHANGED,
186 NotificationService::AllSources());
187 registrar_.Add(this, NotificationType::EXTENSION_UNLOADED,
188 NotificationService::AllSources());
initial.commit09911bf2008-07-26 23:55:29189
initial.commit09911bf2008-07-26 23:55:29190 InitCommandState();
191 BrowserList::AddBrowser(this);
192
193 encoding_auto_detect_.Init(prefs::kWebKitUsesUniversalDetector,
194 profile_->GetPrefs(), NULL);
195
196 // Trim browser memory on idle for low & medium memory models.
197 if (g_browser_process->memory_model() < BrowserProcess::HIGH_MEMORY_MODEL)
198 idle_task_->Start();
initial.commit09911bf2008-07-26 23:55:29199}
200
201Browser::~Browser() {
202 // The tab strip should be empty at this point.
[email protected]a31a86f2009-02-06 00:58:09203#if !defined(OS_LINUX)
204 // TODO(erg): Temporarily disabling this DCHECK while we build the linux
205 // views system. We don't have a tabstrip model up yet.
initial.commit09911bf2008-07-26 23:55:29206 DCHECK(tabstrip_model_.empty());
[email protected]a31a86f2009-02-06 00:58:09207#endif
initial.commit09911bf2008-07-26 23:55:29208 tabstrip_model_.RemoveObserver(this);
209
210 BrowserList::RemoveBrowser(this);
211
212 if (!BrowserList::HasBrowserWithProfile(profile_)) {
213 // We're the last browser window with this profile. We need to nuke the
214 // TabRestoreService, which will start the shutdown of the
215 // NavigationControllers and allow for proper shutdown. If we don't do this
216 // chrome won't shutdown cleanly, and may end up crashing when some
217 // thread tries to use the IO thread (or another thread) that is no longer
218 // valid.
219 profile_->ResetTabRestoreService();
220 }
221
222 SessionService* session_service = profile_->GetSessionService();
223 if (session_service)
224 session_service->WindowClosed(session_id_);
225
[email protected]d8375fd2008-11-25 22:45:39226 TabRestoreService* tab_restore_service = profile()->GetTabRestoreService();
227 if (tab_restore_service)
228 tab_restore_service->BrowserClosed(this);
229
initial.commit09911bf2008-07-26 23:55:29230 if (profile_->IsOffTheRecord() &&
231 !BrowserList::IsOffTheRecordSessionActive()) {
[email protected]860f55492009-03-27 19:50:59232 // An off-the-record profile is no longer needed, this indirectly
233 // frees its cache and cookies.
234 profile_->GetOriginalProfile()->DestroyOffTheRecordProfile();
initial.commit09911bf2008-07-26 23:55:29235 }
236
237 // There may be pending file dialogs, we need to tell them that we've gone
238 // away so they don't try and call back to us.
239 if (select_file_dialog_.get())
240 select_file_dialog_->ListenerDestroyed();
241}
242
[email protected]15952e462008-11-14 00:29:05243// static
244Browser* Browser::Create(Profile* profile) {
[email protected]299dabd2008-11-19 02:27:16245 Browser* browser = new Browser(TYPE_NORMAL, profile);
[email protected]15952e462008-11-14 00:29:05246 browser->CreateBrowserWindow();
247 return browser;
248}
[email protected]6104acf2008-11-11 22:27:34249
[email protected]15952e462008-11-14 00:29:05250// static
251Browser* Browser::CreateForPopup(Profile* profile) {
[email protected]299dabd2008-11-19 02:27:16252 Browser* browser = new Browser(TYPE_POPUP, profile);
[email protected]15952e462008-11-14 00:29:05253 browser->CreateBrowserWindow();
254 return browser;
255}
256
257// static
258Browser* Browser::CreateForApp(const std::wstring& app_name,
[email protected]d5fbc002009-02-27 22:12:58259 Profile* profile, bool is_popup) {
260 Browser* browser = new Browser(is_popup? TYPE_APP_POPUP : TYPE_APP, profile);
[email protected]15952e462008-11-14 00:29:05261 browser->app_name_ = app_name;
262 browser->CreateBrowserWindow();
263 return browser;
264}
265
266void Browser::CreateBrowserWindow() {
267 DCHECK(!window_);
268 window_ = BrowserWindow::CreateBrowserWindow(this);
269
270 // Show the First Run information bubble if we've been told to.
271 PrefService* local_state = g_browser_process->local_state();
[email protected]be3877f2009-01-14 15:51:10272 if (!local_state)
273 return;
[email protected]15952e462008-11-14 00:29:05274 if (local_state->IsPrefRegistered(prefs::kShouldShowFirstRunBubble) &&
275 local_state->GetBoolean(prefs::kShouldShowFirstRunBubble)) {
[email protected]b1390d02009-05-19 23:50:37276 bool show_OEM_bubble = (local_state->
277 IsPrefRegistered(prefs::kShouldUseOEMFirstRunBubble) &&
278 local_state->GetBoolean(prefs::kShouldUseOEMFirstRunBubble));
[email protected]15952e462008-11-14 00:29:05279 // Reset the preference so we don't show the bubble for subsequent windows.
280 local_state->ClearPref(prefs::kShouldShowFirstRunBubble);
[email protected]b1390d02009-05-19 23:50:37281 window_->GetLocationBar()->ShowFirstRunBubble(show_OEM_bubble);
initial.commit09911bf2008-07-26 23:55:29282 }
[email protected]4801ecc2009-04-05 04:52:58283
[email protected]4801ecc2009-04-05 04:52:58284 FindBar* find_bar = BrowserWindow::CreateFindBar(this);
285 find_bar_controller_.reset(new FindBarController(find_bar));
286 find_bar->SetFindBarController(find_bar_controller_.get());
initial.commit09911bf2008-07-26 23:55:29287}
288
[email protected]36b6dcb2008-11-12 01:19:57289///////////////////////////////////////////////////////////////////////////////
290// Browser, Creation Helpers:
291
292// static
[email protected]15952e462008-11-14 00:29:05293void Browser::OpenEmptyWindow(Profile* profile) {
294 Browser* browser = Browser::Create(profile);
[email protected]36b6dcb2008-11-12 01:19:57295 browser->AddBlankTab(true);
[email protected]15952e462008-11-14 00:29:05296 browser->window()->Show();
initial.commit09911bf2008-07-26 23:55:29297}
298
[email protected]36b6dcb2008-11-12 01:19:57299// static
300void Browser::OpenURLOffTheRecord(Profile* profile, const GURL& url) {
301 Profile* off_the_record_profile = profile->GetOffTheRecordProfile();
302 Browser* browser = BrowserList::FindBrowserWithType(
[email protected]15952e462008-11-14 00:29:05303 off_the_record_profile,
[email protected]299dabd2008-11-19 02:27:16304 TYPE_NORMAL);
[email protected]15952e462008-11-14 00:29:05305 if (!browser)
306 browser = Browser::Create(off_the_record_profile);
[email protected]36b6dcb2008-11-12 01:19:57307 // TODO(eroman): should we have referrer here?
[email protected]5a4940be2009-05-06 06:44:39308 browser->AddTabWithURL(url, GURL(), PageTransition::LINK, true, -1, false,
309 NULL);
[email protected]15952e462008-11-14 00:29:05310 browser->window()->Show();
[email protected]2baf83d2008-07-30 05:58:17311}
312
[email protected]36b6dcb2008-11-12 01:19:57313// static
[email protected]0303f31c2009-02-02 06:42:05314void Browser::OpenApplicationWindow(Profile* profile, const GURL& url) {
315 std::wstring app_name = ComputeApplicationNameFromURL(url);
[email protected]36b6dcb2008-11-12 01:19:57316 RegisterAppPrefs(app_name);
[email protected]15952e462008-11-14 00:29:05317
[email protected]d5fbc002009-02-27 22:12:58318 Browser* browser = Browser::CreateForApp(app_name, profile, false);
[email protected]22735af62009-04-07 21:09:58319 browser->AddTabWithURL(url, GURL(), PageTransition::START_PAGE, true, -1,
[email protected]5a4940be2009-05-06 06:44:39320 false, NULL);
[email protected]15952e462008-11-14 00:29:05321 browser->window()->Show();
[email protected]68f009f2009-02-26 19:43:35322 // TODO(jcampan): http://crbug.com/8123 we should not need to set the initial
323 // focus explicitly.
[email protected]57c6a652009-05-04 07:58:34324 browser->GetSelectedTabContents()->view()->SetInitialFocus();
[email protected]d6a3c772009-01-27 19:41:20325}
initial.commit09911bf2008-07-26 23:55:29326
[email protected]36b6dcb2008-11-12 01:19:57327///////////////////////////////////////////////////////////////////////////////
[email protected]36b6dcb2008-11-12 01:19:57328// Browser, State Storage and Retrieval for UI:
329
[email protected]bc9a5152008-11-15 00:32:04330std::wstring Browser::GetWindowPlacementKey() const {
[email protected]36b6dcb2008-11-12 01:19:57331 std::wstring name(prefs::kBrowserWindowPlacement);
332 if (!app_name_.empty()) {
333 name.append(L"_");
334 name.append(app_name_);
335 }
[email protected]bc9a5152008-11-15 00:32:04336 return name;
337}
[email protected]36b6dcb2008-11-12 01:19:57338
[email protected]bc9a5152008-11-15 00:32:04339bool Browser::ShouldSaveWindowPlacement() const {
340 // We don't save window position for popups.
[email protected]d5fbc002009-02-27 22:12:58341 return (type() & TYPE_POPUP) == 0;
[email protected]bc9a5152008-11-15 00:32:04342}
[email protected]36b6dcb2008-11-12 01:19:57343
[email protected]bc9a5152008-11-15 00:32:04344void Browser::SaveWindowPlacement(const gfx::Rect& bounds, bool maximized) {
345 // Save to the session storage service, used when reloading a past session.
346 // Note that we don't want to be the ones who cause lazy initialization of
347 // the session service. This function gets called during initial window
348 // showing, and we don't want to bring in the session service this early.
[email protected]36b6dcb2008-11-12 01:19:57349 if (profile()->HasSessionService()) {
350 SessionService* session_service = profile()->GetSessionService();
351 if (session_service)
352 session_service->SetWindowBounds(session_id_, bounds, maximized);
353 }
354}
355
[email protected]15952e462008-11-14 00:29:05356gfx::Rect Browser::GetSavedWindowBounds() const {
[email protected]bb975362009-01-21 01:00:22357 const CommandLine& parsed_command_line = *CommandLine::ForCurrentProcess();
[email protected]15952e462008-11-14 00:29:05358 bool record_mode = parsed_command_line.HasSwitch(switches::kRecordMode);
359 bool playback_mode = parsed_command_line.HasSwitch(switches::kPlaybackMode);
360 if (record_mode || playback_mode) {
361 // In playback/record mode we always fix the size of the browser and
362 // move it to (0,0). The reason for this is two reasons: First we want
363 // resize/moves in the playback to still work, and Second we want
364 // playbacks to work (as much as possible) on machines w/ different
365 // screen sizes.
366 return gfx::Rect(0, 0, 800, 600);
367 }
368
369 gfx::Rect restored_bounds = override_bounds_;
370 bool maximized;
[email protected]6dfed102009-04-28 03:09:53371 WindowSizer::GetBrowserWindowBounds(app_name_, restored_bounds, NULL,
[email protected]15952e462008-11-14 00:29:05372 &restored_bounds, &maximized);
373 return restored_bounds;
374}
375
376// TODO(beng): obtain maximized state some other way so we don't need to go
377// through all this hassle.
378bool Browser::GetSavedMaximizedState() const {
[email protected]bb975362009-01-21 01:00:22379 if (CommandLine::ForCurrentProcess()->HasSwitch(switches::kStartMaximized))
[email protected]15952e462008-11-14 00:29:05380 return true;
381
[email protected]2e716622009-03-09 21:11:01382 if (maximized_state_ == MAXIMIZED_STATE_MAXIMIZED)
383 return true;
384 if (maximized_state_ == MAXIMIZED_STATE_UNMAXIMIZED)
385 return false;
386
387 // An explicit maximized state was not set. Query the window sizer.
[email protected]15952e462008-11-14 00:29:05388 gfx::Rect restored_bounds;
[email protected]2e716622009-03-09 21:11:01389 bool maximized = false;
[email protected]6dfed102009-04-28 03:09:53390 WindowSizer::GetBrowserWindowBounds(app_name_, restored_bounds, NULL,
[email protected]15952e462008-11-14 00:29:05391 &restored_bounds, &maximized);
392 return maximized;
[email protected]36b6dcb2008-11-12 01:19:57393}
394
395SkBitmap Browser::GetCurrentPageIcon() const {
[email protected]ce5348a82008-12-18 18:36:23396 TabContents* contents = GetSelectedTabContents();
397 // |contents| can be NULL since GetCurrentPageIcon() is called by the window
398 // during the window's creation (before tabs have been added).
399 return contents ? contents->GetFavIcon() : SkBitmap();
[email protected]36b6dcb2008-11-12 01:19:57400}
401
402std::wstring Browser::GetCurrentPageTitle() const {
403 TabContents* contents = tabstrip_model_.GetSelectedTabContents();
404 std::wstring title;
[email protected]c7c42332008-11-15 01:10:54405
406 // |contents| can be NULL because GetCurrentPageTitle is called by the window
407 // during the window's creation (before tabs have been added).
[email protected]36b6dcb2008-11-12 01:19:57408 if (contents) {
[email protected]4c4d8d22009-03-04 05:29:27409 title = UTF16ToWideHack(contents->GetTitle());
[email protected]36b6dcb2008-11-12 01:19:57410 FormatTitleForDisplay(&title);
411 }
412 if (title.empty())
413 title = l10n_util::GetString(IDS_TAB_UNTITLED_TITLE);
414
[email protected]57e68dba2009-05-15 21:30:50415#if defined(OS_WIN) || defined(OS_LINUX)
[email protected]edb5e6a2009-04-08 23:46:17416 int string_id = IDS_BROWSER_WINDOW_TITLE_FORMAT;
417 // Don't append the app name to window titles when we're not displaying a
418 // distributor logo for the frame.
419 if (!ShouldShowDistributorLogo())
420 string_id = IDS_BROWSER_WINDOW_TITLE_FORMAT_NO_LOGO;
421 return l10n_util::GetStringF(string_id, title);
[email protected]57e68dba2009-05-15 21:30:50422#elif defined(OS_MACOSX)
423 // On Mac, we don't want to suffix the page title with the application name.
424 return title;
425#endif
[email protected]36b6dcb2008-11-12 01:19:57426}
427
428// static
429void Browser::FormatTitleForDisplay(std::wstring* title) {
430 size_t current_index = 0;
431 size_t match_index;
432 while ((match_index = title->find(L'\n', current_index)) !=
433 std::wstring::npos) {
434 title->replace(match_index, 1, L"");
435 current_index = match_index;
436 }
437}
438
[email protected]edb5e6a2009-04-08 23:46:17439bool Browser::ShouldShowDistributorLogo() const {
440 // Don't show the distributor logo on app frames and app popups.
441 return !(type_ & TYPE_APP);
442}
[email protected]c61db1d2009-02-06 03:39:18443
[email protected]36b6dcb2008-11-12 01:19:57444///////////////////////////////////////////////////////////////////////////////
445// Browser, OnBeforeUnload handling:
446
447bool Browser::ShouldCloseWindow() {
[email protected]69444cc2009-04-09 20:40:06448 if (!CanCloseWithInProgressDownloads())
449 return false;
450
451 if (HasCompletedUnloadProcessing())
[email protected]36b6dcb2008-11-12 01:19:57452 return true;
[email protected]69444cc2009-04-09 20:40:06453
[email protected]36b6dcb2008-11-12 01:19:57454 is_attempting_to_close_browser_ = true;
455
456 for (int i = 0; i < tab_count(); ++i) {
[email protected]505323e22009-01-24 02:47:58457 TabContents* contents = GetTabContentsAt(i);
458 if (TabHasUnloadListener(contents))
459 tabs_needing_before_unload_fired_.insert(contents);
[email protected]36b6dcb2008-11-12 01:19:57460 }
461
462 if (tabs_needing_before_unload_fired_.empty())
463 return true;
464
465 ProcessPendingTabs();
466 return false;
467}
468
469void Browser::OnWindowClosing() {
470 if (!ShouldCloseWindow())
471 return;
472
[email protected]a239c3f2009-02-17 22:13:19473#if defined(OS_WIN) || defined(OS_LINUX)
474 // We don't want to do this on Mac since closing all windows isn't a sign
475 // that the app is shutting down.
[email protected]36b6dcb2008-11-12 01:19:57476 if (BrowserList::size() == 1)
477 browser_shutdown::OnShutdownStarting(browser_shutdown::WINDOW_CLOSE);
[email protected]a239c3f2009-02-17 22:13:19478#endif
[email protected]36b6dcb2008-11-12 01:19:57479
480 // Don't use HasSessionService here, we want to force creation of the
481 // session service so that user can restore what was open.
482 SessionService* session_service = profile()->GetSessionService();
483 if (session_service)
484 session_service->WindowClosing(session_id());
485
[email protected]d8375fd2008-11-25 22:45:39486 TabRestoreService* tab_restore_service = profile()->GetTabRestoreService();
487 if (tab_restore_service)
488 tab_restore_service->BrowserClosing(this);
489
[email protected]36b6dcb2008-11-12 01:19:57490 CloseAllTabs();
491}
492
[email protected]69444cc2009-04-09 20:40:06493////////////////////////////////////////////////////////////////////////////////
494// In-progress download termination handling:
495
496void Browser::InProgressDownloadResponse(bool cancel_downloads) {
497 if (cancel_downloads) {
498 cancel_download_confirmation_state_ = RESPONSE_RECEIVED;
499 CloseWindow();
500 return;
501 }
502
503 // Sets the confirmation state to NOT_PROMPTED so that if the user tries to
504 // close again we'll show the warning again.
505 cancel_download_confirmation_state_ = NOT_PROMPTED;
506
507 // Show the download page so the user can figure-out what downloads are still
508 // in-progress.
509 ShowDownloadsTab();
510}
511
512
513////////////////////////////////////////////////////////////////////////////////
[email protected]36b6dcb2008-11-12 01:19:57514// Browser, Tab adding/showing functions:
515
516TabContents* Browser::AddTabWithURL(
517 const GURL& url, const GURL& referrer, PageTransition::Type transition,
[email protected]5a4940be2009-05-06 06:44:39518 bool foreground, int index, bool force_index,
519 SiteInstance* instance) {
[email protected]22735af62009-04-07 21:09:58520 TabContents* contents = NULL;
521 if (type_ == TYPE_NORMAL || tabstrip_model()->empty()) {
522 GURL url_to_load = url;
523 if (url_to_load.is_empty())
524 url_to_load = GetHomePage();
525 contents = CreateTabContentsForURL(url_to_load, referrer, profile_,
526 transition, false, instance);
[email protected]5a4940be2009-05-06 06:44:39527 tabstrip_model_.AddTabContents(contents, index, force_index,
528 transition, foreground);
[email protected]22735af62009-04-07 21:09:58529 // By default, content believes it is not hidden. When adding contents
530 // in the background, tell it that it's hidden.
531 if (!foreground)
532 contents->WasHidden();
533 } else {
534 // We're in an app window or a popup window. Find an existing browser to
535 // open this URL in, creating one if none exists.
536 Browser* b = GetOrCreateTabbedBrowser();
537 contents = b->AddTabWithURL(url, referrer, transition, foreground, index,
[email protected]5a4940be2009-05-06 06:44:39538 force_index, instance);
[email protected]22735af62009-04-07 21:09:58539 b->window()->Show();
[email protected]36b6dcb2008-11-12 01:19:57540 }
[email protected]36b6dcb2008-11-12 01:19:57541 return contents;
542}
543
[email protected]ce3fa3c2009-04-20 19:55:57544// TODO(brettw) this should be just AddTab and it should take a TabContents.
[email protected]36b6dcb2008-11-12 01:19:57545TabContents* Browser::AddTabWithNavigationController(
546 NavigationController* ctrl, PageTransition::Type type) {
[email protected]7f0005a2009-04-15 03:25:11547 TabContents* tc = ctrl->tab_contents();
[email protected]5a4940be2009-05-06 06:44:39548 tabstrip_model_.AddTabContents(tc, -1, false, type, true);
[email protected]36b6dcb2008-11-12 01:19:57549 return tc;
550}
551
[email protected]e0c7c262009-04-23 23:09:43552void Browser::AddTabContents(TabContents* new_contents,
553 WindowOpenDisposition disposition,
554 const gfx::Rect& initial_pos,
555 bool user_gesture) {
556 AddNewContents(NULL, new_contents, disposition, initial_pos, user_gesture);
557}
558
559void Browser::CloseTabContents(TabContents* contents) {
560 CloseContents(contents);
561}
562
563void Browser::BrowserShowHtmlDialog(HtmlDialogUIDelegate* delegate,
[email protected]322f3ff2009-05-22 16:19:54564 gfx::NativeWindow parent_window) {
[email protected]e0c7c262009-04-23 23:09:43565 ShowHtmlDialog(delegate, parent_window);
566}
567
568void Browser::BrowserRenderWidgetShowing() {
569 RenderWidgetShowing();
570}
571
572void Browser::ToolbarSizeChanged(bool is_animating) {
573 ToolbarSizeChanged(NULL, is_animating);
574}
575
[email protected]ce3fa3c2009-04-20 19:55:57576TabContents* Browser::AddRestoredTab(
[email protected]36b6dcb2008-11-12 01:19:57577 const std::vector<TabNavigation>& navigations,
578 int tab_index,
579 int selected_navigation,
580 bool select) {
[email protected]57c6a652009-05-04 07:58:34581 TabContents* new_tab = new TabContents(profile(), NULL,
[email protected]ce3fa3c2009-04-20 19:55:57582 MSG_ROUTING_NONE, NULL);
583 new_tab->controller().RestoreFromState(navigations, selected_navigation);
[email protected]36b6dcb2008-11-12 01:19:57584
[email protected]ce3fa3c2009-04-20 19:55:57585 tabstrip_model_.InsertTabContentsAt(tab_index, new_tab, select, false);
[email protected]77bc6732009-04-20 22:01:03586 if (select)
587 window_->Activate();
[email protected]36b6dcb2008-11-12 01:19:57588 if (profile_->HasSessionService()) {
589 SessionService* session_service = profile_->GetSessionService();
590 if (session_service)
[email protected]ce3fa3c2009-04-20 19:55:57591 session_service->TabRestored(&new_tab->controller());
[email protected]36b6dcb2008-11-12 01:19:57592 }
[email protected]ce3fa3c2009-04-20 19:55:57593 return new_tab;
[email protected]36b6dcb2008-11-12 01:19:57594}
595
596void Browser::ReplaceRestoredTab(
597 const std::vector<TabNavigation>& navigations,
598 int selected_navigation) {
[email protected]57c6a652009-05-04 07:58:34599 TabContents* replacement = new TabContents(profile(), NULL,
[email protected]ce3fa3c2009-04-20 19:55:57600 MSG_ROUTING_NONE, NULL);
601 replacement->controller().RestoreFromState(navigations, selected_navigation);
[email protected]36b6dcb2008-11-12 01:19:57602
603 tabstrip_model_.ReplaceNavigationControllerAt(
604 tabstrip_model_.selected_index(),
[email protected]ce3fa3c2009-04-20 19:55:57605 &replacement->controller());
[email protected]36b6dcb2008-11-12 01:19:57606}
607
[email protected]a8eff102009-04-14 15:23:43608bool Browser::CanRestoreTab() {
609 TabRestoreService* service = profile_->GetTabRestoreService();
610 return service && !service->entries().empty();
611}
612
[email protected]7a5f33d2009-03-03 04:35:36613void Browser::ShowSingleDOMUITab(const GURL& url) {
[email protected]b689fce72009-03-17 22:45:34614 // See if we already have a tab with the given URL and select it if so.
615 for (int i = 0; i < tabstrip_model_.count(); i++) {
616 TabContents* tc = tabstrip_model_.GetTabContentsAt(i);
617 if (tc->GetURL() == url) {
[email protected]36b6dcb2008-11-12 01:19:57618 tabstrip_model_.SelectTabContentsAt(i, false);
619 return;
620 }
621 }
[email protected]b689fce72009-03-17 22:45:34622
623 // Otherwise, just create a new tab.
[email protected]5a4940be2009-05-06 06:44:39624 AddTabWithURL(url, GURL(), PageTransition::AUTO_BOOKMARK, true, -1,
625 false, NULL);
[email protected]36b6dcb2008-11-12 01:19:57626}
[email protected]d938aed92009-01-22 19:49:33627
[email protected]36b6dcb2008-11-12 01:19:57628///////////////////////////////////////////////////////////////////////////////
629// Browser, Assorted browser commands:
630
[email protected]485fba42009-03-24 23:27:29631void Browser::GoBack(WindowOpenDisposition disposition) {
[email protected]fbd77592008-11-12 20:50:27632 UserMetrics::RecordAction(L"Back", profile_);
633
[email protected]36b6dcb2008-11-12 01:19:57634 // If we are showing an interstitial, just hide it.
635 TabContents* current_tab = GetSelectedTabContents();
[email protected]57c6a652009-05-04 07:58:34636 if (current_tab->interstitial_page()) {
[email protected]a3a1d142008-12-19 00:42:30637 // The GoBack() case is a special case when an interstitial is shown because
638 // the "previous" page is still available, just hidden by the interstitial.
639 // We treat the back as a "Don't proceed", this hides the interstitial and
640 // reveals the previous page.
[email protected]57c6a652009-05-04 07:58:34641 current_tab->interstitial_page()->DontProceed();
[email protected]c7c42332008-11-15 01:10:54642 return;
[email protected]36b6dcb2008-11-12 01:19:57643 }
[email protected]485fba42009-03-24 23:27:29644
[email protected]ce3fa3c2009-04-20 19:55:57645 if (current_tab->controller().CanGoBack()) {
646 NavigationController* controller = NULL;
647 if (disposition == NEW_FOREGROUND_TAB ||
648 disposition == NEW_BACKGROUND_TAB) {
[email protected]90ba8dd2009-04-25 19:43:52649 TabContents* cloned = GetSelectedTabContents()->Clone();
[email protected]5a4940be2009-05-06 06:44:39650 tabstrip_model_.AddTabContents(cloned, -1, false,
[email protected]90ba8dd2009-04-25 19:43:52651 PageTransition::LINK,
652 disposition == NEW_FOREGROUND_TAB);
653 controller = &cloned->controller();
[email protected]485fba42009-03-24 23:27:29654 } else {
655 // Default disposition is CURRENT_TAB.
[email protected]ce3fa3c2009-04-20 19:55:57656 controller = &current_tab->controller();
[email protected]485fba42009-03-24 23:27:29657 }
658 controller->GoBack();
659 }
[email protected]36b6dcb2008-11-12 01:19:57660}
661
[email protected]485fba42009-03-24 23:27:29662void Browser::GoForward(WindowOpenDisposition disp) {
[email protected]ce3fa3c2009-04-20 19:55:57663 // TODO(brettw) this is mostly duplicated from GoBack, these should have a
664 // common backend or something.
[email protected]fbd77592008-11-12 20:50:27665 UserMetrics::RecordAction(L"Forward", profile_);
[email protected]ce3fa3c2009-04-20 19:55:57666 if (GetSelectedTabContents()->controller().CanGoForward()) {
[email protected]485fba42009-03-24 23:27:29667 NavigationController* controller = 0;
668 if (disp == NEW_FOREGROUND_TAB || disp == NEW_BACKGROUND_TAB) {
[email protected]90ba8dd2009-04-25 19:43:52669 TabContents* cloned = GetSelectedTabContents()->Clone();
[email protected]5a4940be2009-05-06 06:44:39670 tabstrip_model_.AddTabContents(cloned, -1, false,
[email protected]90ba8dd2009-04-25 19:43:52671 PageTransition::LINK,
672 disp == NEW_FOREGROUND_TAB);
673 controller = &cloned->controller();
[email protected]485fba42009-03-24 23:27:29674 } else {
675 // Default disposition is CURRENT_TAB.
[email protected]ce3fa3c2009-04-20 19:55:57676 controller = &GetSelectedTabContents()->controller();
[email protected]485fba42009-03-24 23:27:29677 }
678 controller->GoForward();
679 }
[email protected]36b6dcb2008-11-12 01:19:57680}
681
682void Browser::Reload() {
[email protected]fbd77592008-11-12 20:50:27683 UserMetrics::RecordAction(L"Reload", profile_);
684
[email protected]36b6dcb2008-11-12 01:19:57685 // If we are showing an interstitial, treat this as an OpenURL.
686 TabContents* current_tab = GetSelectedTabContents();
687 if (current_tab) {
[email protected]57c6a652009-05-04 07:58:34688 if (current_tab->showing_interstitial_page()) {
[email protected]ce3fa3c2009-04-20 19:55:57689 NavigationEntry* entry = current_tab->controller().GetActiveEntry();
[email protected]36b6dcb2008-11-12 01:19:57690 DCHECK(entry); // Should exist if interstitial is showing.
691 OpenURL(entry->url(), GURL(), CURRENT_TAB, PageTransition::RELOAD);
692 return;
693 }
[email protected]36b6dcb2008-11-12 01:19:57694
[email protected]0a4a3c12009-05-04 17:10:29695 // Forcibly reset the location bar, since otherwise it won't discard any
696 // ongoing user edits, since it doesn't realize this is a user-initiated
697 // action.
698 window_->GetLocationBar()->Revert();
699
[email protected]20142ba2009-05-04 16:58:47700 // As this is caused by a user action, give the focus to the page.
[email protected]36b6dcb2008-11-12 01:19:57701 current_tab->Focus();
[email protected]ce3fa3c2009-04-20 19:55:57702 current_tab->controller().Reload(true);
[email protected]36b6dcb2008-11-12 01:19:57703 }
704}
705
[email protected]485fba42009-03-24 23:27:29706void Browser::Home(WindowOpenDisposition disposition) {
[email protected]fbd77592008-11-12 20:50:27707 UserMetrics::RecordAction(L"Home", profile_);
[email protected]485fba42009-03-24 23:27:29708 OpenURL(GetHomePage(), GURL(), disposition, PageTransition::AUTO_BOOKMARK);
[email protected]36b6dcb2008-11-12 01:19:57709}
710
[email protected]fbd77592008-11-12 20:50:27711void Browser::OpenCurrentURL() {
712 UserMetrics::RecordAction(L"LoadURL", profile_);
[email protected]7745b822009-01-27 20:15:35713 LocationBar* location_bar = window_->GetLocationBar();
[email protected]b087019502009-02-09 21:59:21714 OpenURL(GURL(WideToUTF8(location_bar->GetInputString())), GURL(),
[email protected]8fe497b2009-04-09 21:06:59715 location_bar->GetWindowOpenDisposition(),
716 location_bar->GetPageTransition());
[email protected]fbd77592008-11-12 20:50:27717}
718
[email protected]485fba42009-03-24 23:27:29719void Browser::Go(WindowOpenDisposition disposition) {
[email protected]84214982008-12-10 18:49:10720 UserMetrics::RecordAction(L"Go", profile_);
[email protected]485fba42009-03-24 23:27:29721 window_->GetLocationBar()->AcceptInputWithDisposition(disposition);
[email protected]84214982008-12-10 18:49:10722}
723
724void Browser::Stop() {
725 UserMetrics::RecordAction(L"Stop", profile_);
[email protected]0daf94732008-12-17 01:08:33726 GetSelectedTabContents()->Stop();
[email protected]84214982008-12-10 18:49:10727}
728
729void Browser::NewWindow() {
730 UserMetrics::RecordAction(L"NewWindow", profile_);
731 Browser::OpenEmptyWindow(profile_->GetOriginalProfile());
732}
733
734void Browser::NewIncognitoWindow() {
735 UserMetrics::RecordAction(L"NewIncognitoWindow", profile_);
736 Browser::OpenEmptyWindow(profile_->GetOffTheRecordProfile());
737}
738
739void Browser::NewProfileWindowByIndex(int index) {
[email protected]d938aed92009-01-22 19:49:33740#if defined(OS_WIN)
[email protected]ac926362009-02-26 01:33:18741 const CommandLine& command_line = *CommandLine::ForCurrentProcess();
742 if (!command_line.HasSwitch(switches::kEnableUserDataDirProfiles))
743 return;
[email protected]84214982008-12-10 18:49:10744 UserMetrics::RecordAction(L"NewProfileWindowByIndex", profile_);
745 UserDataManager::Get()->LaunchChromeForProfile(index);
[email protected]d938aed92009-01-22 19:49:33746#endif
[email protected]84214982008-12-10 18:49:10747}
748
749void Browser::CloseWindow() {
750 UserMetrics::RecordAction(L"CloseWindow", profile_);
751 window_->Close();
752}
753
[email protected]fbd77592008-11-12 20:50:27754void Browser::NewTab() {
755 UserMetrics::RecordAction(L"NewTab", profile_);
[email protected]299dabd2008-11-19 02:27:16756 if (type() == TYPE_NORMAL) {
[email protected]fbd77592008-11-12 20:50:27757 AddBlankTab(true);
758 } else {
759 Browser* b = GetOrCreateTabbedBrowser();
[email protected]fbd77592008-11-12 20:50:27760 b->AddBlankTab(true);
[email protected]15952e462008-11-14 00:29:05761 b->window()->Show();
[email protected]e54f30d2009-01-14 21:17:11762 // The call to AddBlankTab above did not set the focus to the tab as its
763 // window was not active, so we have to do it explicitly.
764 // See http://crbug.com/6380.
[email protected]57c6a652009-05-04 07:58:34765 b->GetSelectedTabContents()->view()->RestoreFocus();
[email protected]fbd77592008-11-12 20:50:27766 }
767}
768
769void Browser::CloseTab() {
770 UserMetrics::RecordAction(L"CloseTab_Accelerator", profile_);
771 tabstrip_model_.CloseTabContentsAt(tabstrip_model_.selected_index());
772}
773
[email protected]fbd77592008-11-12 20:50:27774void Browser::SelectNextTab() {
775 UserMetrics::RecordAction(L"SelectNextTab", profile_);
776 tabstrip_model_.SelectNextTab();
777}
778
779void Browser::SelectPreviousTab() {
780 UserMetrics::RecordAction(L"SelectPrevTab", profile_);
781 tabstrip_model_.SelectPreviousTab();
782}
783
784void Browser::SelectNumberedTab(int index) {
785 if (index < tab_count()) {
786 UserMetrics::RecordAction(L"SelectNumberedTab", profile_);
787 tabstrip_model_.SelectTabContentsAt(index, true);
788 }
789}
790
791void Browser::SelectLastTab() {
792 UserMetrics::RecordAction(L"SelectLastTab", profile_);
793 tabstrip_model_.SelectLastTab();
794}
795
796void Browser::DuplicateTab() {
797 UserMetrics::RecordAction(L"Duplicate", profile_);
798 DuplicateContentsAt(selected_index());
799}
800
801void Browser::RestoreTab() {
802 UserMetrics::RecordAction(L"RestoreTab", profile_);
803 TabRestoreService* service = profile_->GetTabRestoreService();
804 if (!service)
805 return;
806
[email protected]d8375fd2008-11-25 22:45:39807 service->RestoreMostRecentEntry(this);
[email protected]fbd77592008-11-12 20:50:27808}
809
810void Browser::ConvertPopupToTabbedBrowser() {
811 UserMetrics::RecordAction(L"ShowAsTab", profile_);
[email protected]fbd77592008-11-12 20:50:27812 int tab_strip_index = tabstrip_model_.selected_index();
813 TabContents* contents = tabstrip_model_.DetachTabContentsAt(tab_strip_index);
[email protected]15952e462008-11-14 00:29:05814 Browser* browser = Browser::Create(profile_);
815 browser->tabstrip_model()->AppendTabContents(contents, true);
816 browser->window()->Show();
[email protected]fbd77592008-11-12 20:50:27817}
818
[email protected]9282cea2009-02-18 18:49:00819void Browser::ToggleFullscreenMode() {
820 UserMetrics::RecordAction(L"ToggleFullscreen", profile_);
821 window_->SetFullscreen(!window_->IsFullscreen());
822 UpdateCommandsForFullscreenMode(window_->IsFullscreen());
823}
824
[email protected]fbd77592008-11-12 20:50:27825void Browser::Exit() {
826 UserMetrics::RecordAction(L"Exit", profile_);
827 BrowserList::CloseAllBrowsers(true);
828}
829
[email protected]36b6dcb2008-11-12 01:19:57830void Browser::BookmarkCurrentPage() {
[email protected]fbd77592008-11-12 20:50:27831 UserMetrics::RecordAction(L"Star", profile_);
832
[email protected]b7ca4e62009-01-23 20:37:29833 TabContents* contents = GetSelectedTabContents();
834 BookmarkModel* model = contents->profile()->GetBookmarkModel();
[email protected]36b6dcb2008-11-12 01:19:57835 if (!model || !model->IsLoaded())
836 return; // Ignore requests until bookmarks are loaded.
837
[email protected]ce3fa3c2009-04-20 19:55:57838 NavigationEntry* entry = contents->controller().GetActiveEntry();
[email protected]36b6dcb2008-11-12 01:19:57839 if (!entry)
840 return; // Can't star if there is no URL.
841 const GURL& url = entry->display_url();
842 if (url.is_empty() || !url.is_valid())
843 return;
844
[email protected]c50d0d42009-03-03 17:37:44845 bool was_bookmarked = model->IsBookmarked(url);
[email protected]4c4d8d22009-03-04 05:29:27846 model->SetURLStarred(url, UTF16ToWideHack(entry->title()), true);
[email protected]5f2731c52009-02-28 00:41:27847 if (window_->IsActive()) {
848 // Only show the bubble if the window is active, otherwise we may get into
849 // weird situations were the bubble is deleted as soon as it is shown.
[email protected]c50d0d42009-03-03 17:37:44850 window_->ShowBookmarkBubble(url, was_bookmarked);
[email protected]5f2731c52009-02-28 00:41:27851 }
[email protected]36b6dcb2008-11-12 01:19:57852}
853
[email protected]40bdb6d92009-02-25 00:22:27854void Browser::SavePage() {
855 UserMetrics::RecordAction(L"SavePage", profile_);
[email protected]57c6a652009-05-04 07:58:34856 GetSelectedTabContents()->OnSavePage();
[email protected]40bdb6d92009-02-25 00:22:27857}
858
[email protected]fbd77592008-11-12 20:50:27859void Browser::ViewSource() {
860 UserMetrics::RecordAction(L"ViewSource", profile_);
[email protected]36b6dcb2008-11-12 01:19:57861
[email protected]36b6dcb2008-11-12 01:19:57862 TabContents* current_tab = GetSelectedTabContents();
[email protected]ce3fa3c2009-04-20 19:55:57863 NavigationEntry* entry = current_tab->controller().GetLastCommittedEntry();
[email protected]fbd77592008-11-12 20:50:27864 if (entry) {
865 GURL url("view-source:" + entry->url().spec());
[email protected]749eea042009-01-05 22:35:54866 OpenURL(url, GURL(), NEW_FOREGROUND_TAB, PageTransition::LINK);
[email protected]36b6dcb2008-11-12 01:19:57867 }
868}
initial.commit09911bf2008-07-26 23:55:29869
[email protected]4801ecc2009-04-05 04:52:58870void Browser::ShowFindBar() {
871 find_bar_controller_->Show();
872}
873
[email protected]a3e18c42009-03-04 23:36:05874bool Browser::SupportsWindowFeature(WindowFeature feature) const {
875 unsigned int features = FEATURE_INFOBAR | FEATURE_DOWNLOADSHELF;
[email protected]653c9ea2009-05-06 16:58:56876 if (type() == TYPE_NORMAL) {
877 features |= FEATURE_BOOKMARKBAR;
878 features |= FEATURE_EXTENSIONSHELF;
879 }
[email protected]a3e18c42009-03-04 23:36:05880 if (!window_ || !window_->IsFullscreen()) {
881 if (type() == TYPE_NORMAL)
882 features |= FEATURE_TABSTRIP | FEATURE_TOOLBAR;
883 else
884 features |= FEATURE_TITLEBAR;
885 if ((type() & Browser::TYPE_APP) == 0)
886 features |= FEATURE_LOCATIONBAR;
887 }
888 return !!(features & feature);
889}
890
[email protected]c61db1d2009-02-06 03:39:18891#if defined(OS_WIN)
892
[email protected]fbd77592008-11-12 20:50:27893void Browser::ClosePopups() {
894 UserMetrics::RecordAction(L"CloseAllSuppressedPopups", profile_);
895 GetSelectedTabContents()->CloseAllSuppressedPopups();
896}
initial.commit09911bf2008-07-26 23:55:29897
[email protected]fbd77592008-11-12 20:50:27898void Browser::Print() {
899 UserMetrics::RecordAction(L"PrintPreview", profile_);
[email protected]57c6a652009-05-04 07:58:34900 GetSelectedTabContents()->PrintPreview();
[email protected]fbd77592008-11-12 20:50:27901}
[email protected]40d59ce52009-03-06 23:20:14902#endif // #if defined(OS_WIN)
[email protected]fbd77592008-11-12 20:50:27903
[email protected]fbd77592008-11-12 20:50:27904void Browser::ToggleEncodingAutoDetect() {
905 UserMetrics::RecordAction(L"AutoDetectChange", profile_);
906 encoding_auto_detect_.SetValue(!encoding_auto_detect_.GetValue());
907 // Reload the page so we can try to auto-detect the charset.
908 Reload();
909}
910
911void Browser::OverrideEncoding(int encoding_id) {
912 UserMetrics::RecordAction(L"OverrideEncoding", profile_);
913 const std::wstring selected_encoding =
914 CharacterEncoding::GetCanonicalEncodingNameByCommandId(encoding_id);
[email protected]57c6a652009-05-04 07:58:34915 TabContents* contents = GetSelectedTabContents();
916 if (!selected_encoding.empty() && contents)
917 contents->override_encoding(selected_encoding);
[email protected]fbd77592008-11-12 20:50:27918 // Update the list of recently selected encodings.
919 std::wstring new_selected_encoding_list;
920 if (CharacterEncoding::UpdateRecentlySelectdEncoding(
921 profile_->GetPrefs()->GetString(prefs::kRecentlySelectedEncoding),
922 encoding_id,
923 &new_selected_encoding_list)) {
924 profile_->GetPrefs()->SetString(prefs::kRecentlySelectedEncoding,
925 new_selected_encoding_list);
926 }
[email protected]36b6dcb2008-11-12 01:19:57927}
928
[email protected]40d59ce52009-03-06 23:20:14929#if defined(OS_WIN)
[email protected]84214982008-12-10 18:49:10930// TODO(devint): http://b/issue?id=1117225 Cut, Copy, and Paste are always
931// enabled in the page menu regardless of whether the command will do
932// anything. When someone selects the menu item, we just act as if they hit
933// the keyboard shortcut for the command by sending the associated key press
934// to windows. The real fix to this bug is to disable the commands when they
935// won't do anything. We'll need something like an overall clipboard command
936// manager to do that.
937
938void Browser::Cut() {
939 UserMetrics::RecordAction(L"Cut", profile_);
940 ui_controls::SendKeyPress(L'X', true, false, false);
[email protected]36b6dcb2008-11-12 01:19:57941}
942
[email protected]84214982008-12-10 18:49:10943void Browser::Copy() {
944 UserMetrics::RecordAction(L"Copy", profile_);
945 ui_controls::SendKeyPress(L'C', true, false, false);
[email protected]36b6dcb2008-11-12 01:19:57946}
947
[email protected]84214982008-12-10 18:49:10948void Browser::CopyCurrentPageURL() {
949 UserMetrics::RecordAction(L"CopyURLToClipBoard", profile_);
950 std::string url = GetSelectedTabContents()->GetURL().spec();
951
952 if (!::OpenClipboard(NULL)) {
953 NOTREACHED();
954 return;
955 }
956
957 if (::EmptyClipboard()) {
958 HGLOBAL text = ::GlobalAlloc(GMEM_MOVEABLE, url.size() + 1);
959 LPSTR ptr = static_cast<LPSTR>(::GlobalLock(text));
960 memcpy(ptr, url.c_str(), url.size());
961 ptr[url.size()] = '\0';
962 ::GlobalUnlock(text);
963
964 ::SetClipboardData(CF_TEXT, text);
965 }
966
967 if (!::CloseClipboard()) {
968 NOTREACHED();
969 }
[email protected]36b6dcb2008-11-12 01:19:57970}
971
[email protected]84214982008-12-10 18:49:10972void Browser::Paste() {
973 UserMetrics::RecordAction(L"Paste", profile_);
974 ui_controls::SendKeyPress(L'V', true, false, false);
975}
[email protected]31b1bc3a2009-03-10 19:26:19976#endif // #if defined(OS_WIN)
[email protected]84214982008-12-10 18:49:10977
978void Browser::Find() {
979 UserMetrics::RecordAction(L"Find", profile_);
[email protected]4f3dc372009-02-24 00:10:29980 FindInPage(false, false);
[email protected]84214982008-12-10 18:49:10981}
982
983void Browser::FindNext() {
984 UserMetrics::RecordAction(L"FindNext", profile_);
[email protected]4f3dc372009-02-24 00:10:29985 FindInPage(true, true);
[email protected]84214982008-12-10 18:49:10986}
987
988void Browser::FindPrevious() {
989 UserMetrics::RecordAction(L"FindPrevious", profile_);
[email protected]4f3dc372009-02-24 00:10:29990 FindInPage(true, false);
[email protected]84214982008-12-10 18:49:10991}
992
993void Browser::ZoomIn() {
994 UserMetrics::RecordAction(L"ZoomPlus", profile_);
[email protected]57c6a652009-05-04 07:58:34995 GetSelectedTabContents()->render_view_host()->Zoom(PageZoom::LARGER);
[email protected]84214982008-12-10 18:49:10996}
997
998void Browser::ZoomReset() {
999 UserMetrics::RecordAction(L"ZoomNormal", profile_);
[email protected]57c6a652009-05-04 07:58:341000 GetSelectedTabContents()->render_view_host()->Zoom(PageZoom::STANDARD);
[email protected]84214982008-12-10 18:49:101001}
1002
1003void Browser::ZoomOut() {
1004 UserMetrics::RecordAction(L"ZoomMinus", profile_);
[email protected]57c6a652009-05-04 07:58:341005 GetSelectedTabContents()->render_view_host()->Zoom(PageZoom::SMALLER);
[email protected]84214982008-12-10 18:49:101006}
1007
[email protected]40d59ce52009-03-06 23:20:141008#if defined(OS_WIN)
[email protected]84214982008-12-10 18:49:101009void Browser::FocusToolbar() {
1010 UserMetrics::RecordAction(L"FocusToolbar", profile_);
1011 window_->FocusToolbar();
1012}
[email protected]d56bcd22009-03-16 19:51:561013#endif
[email protected]84214982008-12-10 18:49:101014
1015void Browser::FocusLocationBar() {
1016 UserMetrics::RecordAction(L"FocusLocation", profile_);
[email protected]d56bcd22009-03-16 19:51:561017 window_->SetFocusToLocationBar();
[email protected]84214982008-12-10 18:49:101018}
1019
1020void Browser::FocusSearch() {
1021 // TODO(beng): replace this with FocusLocationBar
1022 UserMetrics::RecordAction(L"FocusSearch", profile_);
[email protected]7745b822009-01-27 20:15:351023 window_->GetLocationBar()->FocusSearch();
[email protected]84214982008-12-10 18:49:101024}
1025
1026void Browser::OpenFile() {
1027 UserMetrics::RecordAction(L"OpenFile", profile_);
1028 if (!select_file_dialog_.get())
1029 select_file_dialog_ = SelectFileDialog::Create(this);
1030
1031 // TODO(beng): figure out how to juggle this.
[email protected]d56bcd22009-03-16 19:51:561032 gfx::NativeWindow parent_window = window_->GetNativeHandle();
[email protected]84214982008-12-10 18:49:101033 select_file_dialog_->SelectFile(SelectFileDialog::SELECT_OPEN_FILE,
[email protected]561abe62009-04-06 18:08:341034 string16(), FilePath(),
[email protected]b949f1112009-04-12 20:03:081035 NULL, 0, FILE_PATH_LITERAL(""),
[email protected]d56bcd22009-03-16 19:51:561036 parent_window, NULL);
[email protected]84214982008-12-10 18:49:101037}
1038
[email protected]d56bcd22009-03-16 19:51:561039#if defined(OS_WIN)
[email protected]84214982008-12-10 18:49:101040void Browser::OpenCreateShortcutsDialog() {
1041 UserMetrics::RecordAction(L"CreateShortcut", profile_);
[email protected]57c6a652009-05-04 07:58:341042 GetSelectedTabContents()->CreateShortcut();
[email protected]36b6dcb2008-11-12 01:19:571043}
1044
[email protected]fbd77592008-11-12 20:50:271045void Browser::OpenDebuggerWindow() {
1046#ifndef CHROME_DEBUGGER_DISABLED
1047 UserMetrics::RecordAction(L"Debugger", profile_);
[email protected]20142ba2009-05-04 16:58:471048 // Only one debugger instance can exist at a time right now.
1049 // TODO(erikkay): need an alert, dialog, something
1050 // or better yet, fix the one instance limitation
[email protected]0800c662009-05-08 19:41:491051 DebuggerHost* host = DebuggerWindow::GetAnyExistingDebugger();
1052 if (host) {
1053 host->ShowWindow();
1054 return;
1055 }
1056 debugger_window_ = new DebuggerWindow();
[email protected]20142ba2009-05-04 16:58:471057 debugger_window_->Show(GetSelectedTabContents());
[email protected]fbd77592008-11-12 20:50:271058#endif
1059}
[email protected]36b6dcb2008-11-12 01:19:571060
[email protected]fbd77592008-11-12 20:50:271061void Browser::OpenJavaScriptConsole() {
1062 UserMetrics::RecordAction(L"ShowJSConsole", profile_);
[email protected]684b4ba22009-05-07 06:27:411063 GetSelectedTabContents()->render_view_host()->
1064 ShowJavaScriptConsole();
[email protected]fbd77592008-11-12 20:50:271065}
1066
[email protected]84214982008-12-10 18:49:101067void Browser::OpenTaskManager() {
1068 UserMetrics::RecordAction(L"TaskManager", profile_);
1069 TaskManager::Open();
1070}
1071
1072void Browser::OpenSelectProfileDialog() {
[email protected]12a6f0362009-03-09 19:37:361073 const CommandLine& command_line = *CommandLine::ForCurrentProcess();
1074 if (!command_line.HasSwitch(switches::kEnableUserDataDirProfiles))
1075 return;
[email protected]84214982008-12-10 18:49:101076 UserMetrics::RecordAction(L"SelectProfile", profile_);
[email protected]505323e22009-01-24 02:47:581077 window_->ShowSelectProfileDialog();
[email protected]84214982008-12-10 18:49:101078}
1079
1080void Browser::OpenNewProfileDialog() {
[email protected]ac926362009-02-26 01:33:181081 const CommandLine& command_line = *CommandLine::ForCurrentProcess();
1082 if (!command_line.HasSwitch(switches::kEnableUserDataDirProfiles))
1083 return;
[email protected]84214982008-12-10 18:49:101084 UserMetrics::RecordAction(L"CreateProfile", profile_);
[email protected]505323e22009-01-24 02:47:581085 window_->ShowNewProfileDialog();
[email protected]84214982008-12-10 18:49:101086}
1087
1088void Browser::OpenBugReportDialog() {
1089 UserMetrics::RecordAction(L"ReportBug", profile_);
1090 window_->ShowReportBugDialog();
1091}
[email protected]44b2c8852009-03-18 00:57:491092#endif // #if defined(OS_WIN)
[email protected]84214982008-12-10 18:49:101093
[email protected]44b2c8852009-03-18 00:57:491094
[email protected]84214982008-12-10 18:49:101095void Browser::ToggleBookmarkBar() {
1096 UserMetrics::RecordAction(L"ShowBookmarksBar", profile_);
1097 window_->ToggleBookmarkBar();
1098}
1099
[email protected]44b2c8852009-03-18 00:57:491100#if defined(OS_WIN)
[email protected]84214982008-12-10 18:49:101101void Browser::OpenBookmarkManager() {
1102 UserMetrics::RecordAction(L"ShowBookmarkManager", profile_);
1103 window_->ShowBookmarkManager();
1104}
[email protected]8bf80e922009-03-09 20:56:361105#endif // #if defined(OS_WIN)
1106
1107void Browser::ShowHistoryTab() {
1108 UserMetrics::RecordAction(L"ShowHistory", profile_);
[email protected]b689fce72009-03-17 22:45:341109 ShowSingleDOMUITab(GURL(chrome::kChromeUIHistoryURL));
[email protected]8bf80e922009-03-09 20:56:361110}
[email protected]84214982008-12-10 18:49:101111
1112void Browser::ShowDownloadsTab() {
1113 UserMetrics::RecordAction(L"ShowDownloads", profile_);
[email protected]b689fce72009-03-17 22:45:341114 ShowSingleDOMUITab(GURL(chrome::kChromeUIDownloadsURL));
[email protected]84214982008-12-10 18:49:101115}
1116
1117void Browser::OpenClearBrowsingDataDialog() {
1118 UserMetrics::RecordAction(L"ClearBrowsingData_ShowDlg", profile_);
1119 window_->ShowClearBrowsingDataDialog();
1120}
1121
[email protected]84214982008-12-10 18:49:101122void Browser::OpenOptionsDialog() {
1123 UserMetrics::RecordAction(L"ShowOptions", profile_);
1124 ShowOptionsWindow(OPTIONS_PAGE_DEFAULT, OPTIONS_GROUP_NONE, profile_);
1125}
1126
[email protected]0e3e3e32009-05-14 01:00:531127#if defined(OS_WIN)
[email protected]84214982008-12-10 18:49:101128void Browser::OpenKeywordEditor() {
1129 UserMetrics::RecordAction(L"EditSearchEngines", profile_);
1130 window_->ShowSearchEnginesDialog();
[email protected]fbd77592008-11-12 20:50:271131}
1132
1133void Browser::OpenPasswordManager() {
[email protected]2d46c842008-11-14 19:24:311134 window_->ShowPasswordManager();
[email protected]fbd77592008-11-12 20:50:271135}
[email protected]4dbac172009-04-24 20:23:491136#endif
[email protected]fbd77592008-11-12 20:50:271137
[email protected]1bdf29e2009-05-11 23:45:251138#if defined(OS_WIN) || defined(OS_LINUX)
1139void Browser::OpenImportSettingsDialog() {
1140 UserMetrics::RecordAction(L"Import_ShowDlg", profile_);
1141 window_->ShowImportDialog();
1142}
1143#endif
1144
[email protected]fbd77592008-11-12 20:50:271145void Browser::OpenAboutChromeDialog() {
1146 UserMetrics::RecordAction(L"AboutChrome", profile_);
[email protected]2d46c842008-11-14 19:24:311147 window_->ShowAboutChromeDialog();
[email protected]fbd77592008-11-12 20:50:271148}
1149
[email protected]fbd77592008-11-12 20:50:271150void Browser::OpenHelpTab() {
[email protected]40d59ce52009-03-06 23:20:141151 GURL help_url(WideToASCII(l10n_util::GetString(IDS_HELP_CONTENT_URL)));
[email protected]22735af62009-04-07 21:09:581152 AddTabWithURL(help_url, GURL(), PageTransition::AUTO_BOOKMARK, true, -1,
[email protected]5a4940be2009-05-06 06:44:391153 false, NULL);
[email protected]fbd77592008-11-12 20:50:271154}
1155
[email protected]36b6dcb2008-11-12 01:19:571156///////////////////////////////////////////////////////////////////////////////
1157
1158// static
1159void Browser::RegisterPrefs(PrefService* prefs) {
1160 prefs->RegisterDictionaryPref(prefs::kBrowserWindowPlacement);
1161 prefs->RegisterIntegerPref(prefs::kOptionsWindowLastTabIndex, 0);
1162}
1163
1164// static
1165void Browser::RegisterUserPrefs(PrefService* prefs) {
1166 prefs->RegisterStringPref(prefs::kHomePage, L"chrome-internal:");
1167 prefs->RegisterBooleanPref(prefs::kHomePageIsNewTabPage, true);
1168 prefs->RegisterIntegerPref(prefs::kCookieBehavior,
1169 net::CookiePolicy::ALLOW_ALL_COOKIES);
1170 prefs->RegisterBooleanPref(prefs::kShowHomeButton, false);
1171 prefs->RegisterStringPref(prefs::kRecentlySelectedEncoding, L"");
[email protected]36b6dcb2008-11-12 01:19:571172 prefs->RegisterBooleanPref(prefs::kDeleteBrowsingHistory, true);
1173 prefs->RegisterBooleanPref(prefs::kDeleteDownloadHistory, true);
1174 prefs->RegisterBooleanPref(prefs::kDeleteCache, true);
1175 prefs->RegisterBooleanPref(prefs::kDeleteCookies, true);
1176 prefs->RegisterBooleanPref(prefs::kDeletePasswords, false);
1177 prefs->RegisterBooleanPref(prefs::kDeleteFormData, true);
1178 prefs->RegisterIntegerPref(prefs::kDeleteTimePeriod, 0);
[email protected]48b47ffa2009-05-02 07:18:301179 prefs->RegisterBooleanPref(prefs::kCheckDefaultBrowser, true);
[email protected]36b6dcb2008-11-12 01:19:571180}
1181
1182// static
1183Browser* Browser::GetBrowserForController(
1184 const NavigationController* controller, int* index_result) {
1185 BrowserList::const_iterator it;
1186 for (it = BrowserList::begin(); it != BrowserList::end(); ++it) {
[email protected]902cdf772009-05-06 15:08:121187 int index = (*it)->tabstrip_model_.GetIndexOfController(controller);
[email protected]36b6dcb2008-11-12 01:19:571188 if (index != TabStripModel::kNoTab) {
1189 if (index_result)
1190 *index_result = index;
1191 return *it;
1192 }
1193 }
1194
1195 return NULL;
1196}
1197
[email protected]485fba42009-03-24 23:27:291198void Browser::ExecuteCommandWithDisposition(
1199 int id, WindowOpenDisposition disposition) {
[email protected]1fc025202009-01-20 23:03:141200 // No commands are enabled if there is not yet any selected tab.
1201 // TODO(pkasting): It seems like we should not need this, because either
1202 // most/all commands should not have been enabled yet anyway or the ones that
1203 // are enabled should be global, or safe themselves against having no selected
1204 // tab. However, Ben says he tried removing this before and got lots of
1205 // crashes, e.g. from Windows sending WM_COMMANDs at random times during
1206 // window construction. This probably could use closer examination someday.
1207 if (!GetSelectedTabContents())
1208 return;
1209
1210 DCHECK(command_updater_.IsCommandEnabled(id)) << "Invalid/disabled command";
[email protected]36b6dcb2008-11-12 01:19:571211
[email protected]fbd77592008-11-12 20:50:271212 // The order of commands in this switch statement must match the function
1213 // declaration order in browser.h!
[email protected]36b6dcb2008-11-12 01:19:571214 switch (id) {
[email protected]84214982008-12-10 18:49:101215 // Navigation commands
[email protected]485fba42009-03-24 23:27:291216 case IDC_BACK: GoBack(disposition); break;
1217 case IDC_FORWARD: GoForward(disposition); break;
[email protected]cb525c82008-12-08 23:04:541218 case IDC_RELOAD: Reload(); break;
[email protected]485fba42009-03-24 23:27:291219 case IDC_HOME: Home(disposition); break;
[email protected]cb525c82008-12-08 23:04:541220 case IDC_OPEN_CURRENT_URL: OpenCurrentURL(); break;
[email protected]485fba42009-03-24 23:27:291221 case IDC_GO: Go(disposition); break;
[email protected]84214982008-12-10 18:49:101222 case IDC_STOP: Stop(); break;
[email protected]36b6dcb2008-11-12 01:19:571223
[email protected]84214982008-12-10 18:49:101224 // Window management commands
[email protected]cb525c82008-12-08 23:04:541225 case IDC_NEW_WINDOW: NewWindow(); break;
1226 case IDC_NEW_INCOGNITO_WINDOW: NewIncognitoWindow(); break;
[email protected]84214982008-12-10 18:49:101227 case IDC_NEW_WINDOW_PROFILE_0:
1228 case IDC_NEW_WINDOW_PROFILE_1:
1229 case IDC_NEW_WINDOW_PROFILE_2:
1230 case IDC_NEW_WINDOW_PROFILE_3:
1231 case IDC_NEW_WINDOW_PROFILE_4:
1232 case IDC_NEW_WINDOW_PROFILE_5:
1233 case IDC_NEW_WINDOW_PROFILE_6:
1234 case IDC_NEW_WINDOW_PROFILE_7:
[email protected]f21c613a2009-02-12 14:46:171235 case IDC_NEW_WINDOW_PROFILE_8:
[email protected]84214982008-12-10 18:49:101236 NewProfileWindowByIndex(id - IDC_NEW_WINDOW_PROFILE_0); break;
[email protected]a3c07002009-05-20 20:35:521237#if defined(OS_WIN) || defined(OS_LINUX)
[email protected]cb525c82008-12-08 23:04:541238 case IDC_CLOSE_WINDOW: CloseWindow(); break;
[email protected]f7454892009-01-29 19:24:211239#endif
[email protected]84214982008-12-10 18:49:101240 case IDC_NEW_TAB: NewTab(); break;
1241 case IDC_CLOSE_TAB: CloseTab(); break;
[email protected]cb525c82008-12-08 23:04:541242 case IDC_SELECT_NEXT_TAB: SelectNextTab(); break;
1243 case IDC_SELECT_PREVIOUS_TAB: SelectPreviousTab(); break;
[email protected]36b6dcb2008-11-12 01:19:571244 case IDC_SELECT_TAB_0:
1245 case IDC_SELECT_TAB_1:
1246 case IDC_SELECT_TAB_2:
1247 case IDC_SELECT_TAB_3:
1248 case IDC_SELECT_TAB_4:
1249 case IDC_SELECT_TAB_5:
1250 case IDC_SELECT_TAB_6:
[email protected]cb525c82008-12-08 23:04:541251 case IDC_SELECT_TAB_7: SelectNumberedTab(id - IDC_SELECT_TAB_0);
1252 break;
1253 case IDC_SELECT_LAST_TAB: SelectLastTab(); break;
1254 case IDC_DUPLICATE_TAB: DuplicateTab(); break;
1255 case IDC_RESTORE_TAB: RestoreTab(); break;
1256 case IDC_SHOW_AS_TAB: ConvertPopupToTabbedBrowser(); break;
[email protected]9282cea2009-02-18 18:49:001257 case IDC_FULLSCREEN: ToggleFullscreenMode(); break;
[email protected]cb525c82008-12-08 23:04:541258 case IDC_EXIT: Exit(); break;
[email protected]36b6dcb2008-11-12 01:19:571259
[email protected]84214982008-12-10 18:49:101260 // Page-related commands
[email protected]40bdb6d92009-02-25 00:22:271261 case IDC_SAVE_PAGE: SavePage(); break;
[email protected]cb525c82008-12-08 23:04:541262 case IDC_STAR: BookmarkCurrentPage(); break;
1263 case IDC_VIEW_SOURCE: ViewSource(); break;
[email protected]c61db1d2009-02-06 03:39:181264#if defined(OS_WIN)
[email protected]cb525c82008-12-08 23:04:541265 case IDC_CLOSE_POPUPS: ClosePopups(); break;
1266 case IDC_PRINT: Print(); break;
[email protected]40d59ce52009-03-06 23:20:141267#endif
[email protected]cb525c82008-12-08 23:04:541268 case IDC_ENCODING_AUTO_DETECT: ToggleEncodingAutoDetect(); break;
[email protected]36b6dcb2008-11-12 01:19:571269 case IDC_ENCODING_UTF8:
1270 case IDC_ENCODING_UTF16LE:
1271 case IDC_ENCODING_ISO88591:
1272 case IDC_ENCODING_WINDOWS1252:
[email protected]1c5bf632008-12-11 20:30:491273 case IDC_ENCODING_GBK:
[email protected]36b6dcb2008-11-12 01:19:571274 case IDC_ENCODING_GB18030:
1275 case IDC_ENCODING_BIG5HKSCS:
1276 case IDC_ENCODING_BIG5:
1277 case IDC_ENCODING_KOREAN:
1278 case IDC_ENCODING_SHIFTJIS:
1279 case IDC_ENCODING_ISO2022JP:
1280 case IDC_ENCODING_EUCJP:
1281 case IDC_ENCODING_THAI:
1282 case IDC_ENCODING_ISO885915:
1283 case IDC_ENCODING_MACINTOSH:
1284 case IDC_ENCODING_ISO88592:
1285 case IDC_ENCODING_WINDOWS1250:
1286 case IDC_ENCODING_ISO88595:
1287 case IDC_ENCODING_WINDOWS1251:
1288 case IDC_ENCODING_KOI8R:
1289 case IDC_ENCODING_KOI8U:
1290 case IDC_ENCODING_ISO88597:
1291 case IDC_ENCODING_WINDOWS1253:
1292 case IDC_ENCODING_ISO88594:
1293 case IDC_ENCODING_ISO885913:
1294 case IDC_ENCODING_WINDOWS1257:
1295 case IDC_ENCODING_ISO88593:
1296 case IDC_ENCODING_ISO885910:
1297 case IDC_ENCODING_ISO885914:
1298 case IDC_ENCODING_ISO885916:
[email protected]36b6dcb2008-11-12 01:19:571299 case IDC_ENCODING_WINDOWS1254:
1300 case IDC_ENCODING_ISO88596:
1301 case IDC_ENCODING_WINDOWS1256:
1302 case IDC_ENCODING_ISO88598:
[email protected]e13271f2009-03-07 00:26:001303 case IDC_ENCODING_ISO88598I:
[email protected]36b6dcb2008-11-12 01:19:571304 case IDC_ENCODING_WINDOWS1255:
[email protected]cb525c82008-12-08 23:04:541305 case IDC_ENCODING_WINDOWS1258: OverrideEncoding(id); break;
[email protected]36b6dcb2008-11-12 01:19:571306
[email protected]40d59ce52009-03-06 23:20:141307#if defined(OS_WIN)
[email protected]84214982008-12-10 18:49:101308 // Clipboard commands
1309 case IDC_CUT: Cut(); break;
1310 case IDC_COPY: Copy(); break;
1311 case IDC_COPY_URL: CopyCurrentPageURL(); break;
1312 case IDC_PASTE: Paste(); break;
[email protected]31b1bc3a2009-03-10 19:26:191313#endif
[email protected]84214982008-12-10 18:49:101314
1315 // Find-in-page
1316 case IDC_FIND: Find(); break;
1317 case IDC_FIND_NEXT: FindNext(); break;
1318 case IDC_FIND_PREVIOUS: FindPrevious(); break;
1319
1320 // Zoom
1321 case IDC_ZOOM_PLUS: ZoomIn(); break;
1322 case IDC_ZOOM_NORMAL: ZoomReset(); break;
1323 case IDC_ZOOM_MINUS: ZoomOut(); break;
1324
1325 // Focus various bits of UI
[email protected]d56bcd22009-03-16 19:51:561326#if defined(OS_WIN)
[email protected]84214982008-12-10 18:49:101327 case IDC_FOCUS_TOOLBAR: FocusToolbar(); break;
[email protected]d56bcd22009-03-16 19:51:561328#endif
[email protected]84214982008-12-10 18:49:101329 case IDC_FOCUS_LOCATION: FocusLocationBar(); break;
1330 case IDC_FOCUS_SEARCH: FocusSearch(); break;
1331
1332 // Show various bits of UI
1333 case IDC_OPEN_FILE: OpenFile(); break;
[email protected]d56bcd22009-03-16 19:51:561334#if defined(OS_WIN)
[email protected]84214982008-12-10 18:49:101335 case IDC_CREATE_SHORTCUTS: OpenCreateShortcutsDialog(); break;
[email protected]cb525c82008-12-08 23:04:541336 case IDC_DEBUGGER: OpenDebuggerWindow(); break;
1337 case IDC_JS_CONSOLE: OpenJavaScriptConsole(); break;
[email protected]cb525c82008-12-08 23:04:541338 case IDC_TASK_MANAGER: OpenTaskManager(); break;
[email protected]cb525c82008-12-08 23:04:541339 case IDC_SELECT_PROFILE: OpenSelectProfileDialog(); break;
1340 case IDC_NEW_PROFILE: OpenNewProfileDialog(); break;
[email protected]84214982008-12-10 18:49:101341 case IDC_REPORT_BUG: OpenBugReportDialog(); break;
[email protected]44b2c8852009-03-18 00:57:491342#endif
1343
[email protected]84214982008-12-10 18:49:101344 case IDC_SHOW_BOOKMARK_BAR: ToggleBookmarkBar(); break;
[email protected]44b2c8852009-03-18 00:57:491345
1346#if defined(OS_WIN)
[email protected]84214982008-12-10 18:49:101347 case IDC_SHOW_BOOKMARK_MANAGER: OpenBookmarkManager(); break;
[email protected]8bf80e922009-03-09 20:56:361348#endif
1349 case IDC_SHOW_HISTORY: ShowHistoryTab(); break;
[email protected]84214982008-12-10 18:49:101350 case IDC_SHOW_DOWNLOADS: ShowDownloadsTab(); break;
[email protected]8bf80e922009-03-09 20:56:361351#if defined(OS_WIN)
[email protected]026e34a2009-02-06 00:06:121352#ifdef CHROME_PERSONALIZATION
1353 case IDC_P13N_INFO:
1354 Personalization::HandleMenuItemClick(profile()); break;
1355#endif
[email protected]0e3e3e32009-05-14 01:00:531356#endif
[email protected]84214982008-12-10 18:49:101357 case IDC_OPTIONS: OpenOptionsDialog(); break;
[email protected]0e3e3e32009-05-14 01:00:531358#if defined(OS_WIN)
[email protected]84214982008-12-10 18:49:101359 case IDC_EDIT_SEARCH_ENGINES: OpenKeywordEditor(); break;
1360 case IDC_VIEW_PASSWORDS: OpenPasswordManager(); break;
[email protected]88d74942009-01-21 22:04:441361#endif
[email protected]1bdf29e2009-05-11 23:45:251362#if defined(OS_WIN) || defined(OS_LINUX)
[email protected]25364e12009-05-22 01:37:191363 case IDC_CLEAR_BROWSING_DATA: OpenClearBrowsingDataDialog(); break;
[email protected]1bdf29e2009-05-11 23:45:251364 case IDC_IMPORT_SETTINGS: OpenImportSettingsDialog(); break;
1365#endif
[email protected]4dbac172009-04-24 20:23:491366 case IDC_ABOUT: OpenAboutChromeDialog(); break;
[email protected]40d59ce52009-03-06 23:20:141367 case IDC_HELP_PAGE: OpenHelpTab(); break;
[email protected]d938aed92009-01-22 19:49:331368
[email protected]36b6dcb2008-11-12 01:19:571369 default:
[email protected]84214982008-12-10 18:49:101370 LOG(WARNING) << "Received Unimplemented Command: " << id;
[email protected]fbd77592008-11-12 20:50:271371 break;
[email protected]36b6dcb2008-11-12 01:19:571372 }
1373}
1374
1375///////////////////////////////////////////////////////////////////////////////
[email protected]485fba42009-03-24 23:27:291376// Browser, CommandUpdater::CommandUpdaterDelegate implementation:
1377
1378void Browser::ExecuteCommand(int id) {
1379 ExecuteCommandWithDisposition(id, CURRENT_TAB);
1380}
1381
1382///////////////////////////////////////////////////////////////////////////////
[email protected]36b6dcb2008-11-12 01:19:571383// Browser, TabStripModelDelegate implementation:
1384
[email protected]22735af62009-04-07 21:09:581385TabContents* Browser::AddBlankTab(bool foreground) {
1386 return AddBlankTabAt(-1, foreground);
1387}
1388
1389TabContents* Browser::AddBlankTabAt(int index, bool foreground) {
1390 return AddTabWithURL(GURL(chrome::kChromeUINewTabURL), GURL(),
[email protected]5a4940be2009-05-06 06:44:391391 PageTransition::TYPED, foreground, index, false, NULL);
[email protected]15952e462008-11-14 00:29:051392}
1393
[email protected]3d1104f2009-03-26 15:30:281394Browser* Browser::CreateNewStripWithContents(TabContents* detached_contents,
1395 const gfx::Rect& window_bounds,
1396 const DockInfo& dock_info) {
[email protected]299dabd2008-11-19 02:27:161397 DCHECK(type_ == TYPE_NORMAL);
[email protected]adf650f2008-12-09 16:10:061398
[email protected]5e495462008-11-20 23:07:411399 gfx::Rect new_window_bounds = window_bounds;
1400 bool maximize = false;
1401 if (dock_info.GetNewWindowBounds(&new_window_bounds, &maximize))
1402 dock_info.AdjustOtherWindowBounds();
1403
[email protected]36b6dcb2008-11-12 01:19:571404 // Create an empty new browser window the same size as the old one.
[email protected]299dabd2008-11-19 02:27:161405 Browser* browser = new Browser(TYPE_NORMAL, profile_);
[email protected]5e495462008-11-20 23:07:411406 browser->set_override_bounds(new_window_bounds);
[email protected]2e716622009-03-09 21:11:011407 browser->set_maximized_state(
1408 maximize ? MAXIMIZED_STATE_MAXIMIZED : MAXIMIZED_STATE_UNMAXIMIZED);
[email protected]15952e462008-11-14 00:29:051409 browser->CreateBrowserWindow();
1410 browser->tabstrip_model()->AppendTabContents(detached_contents, true);
[email protected]159f7762008-12-19 14:58:271411 // Make sure the loading state is updated correctly, otherwise the throbber
1412 // won't start if the page is loading.
1413 browser->LoadingStateChanged(detached_contents);
[email protected]3d1104f2009-03-26 15:30:281414 return browser;
[email protected]36b6dcb2008-11-12 01:19:571415}
1416
1417int Browser::GetDragActions() const {
[email protected]d54f6a002009-03-18 17:17:251418 return TAB_TEAROFF_ACTION | (tab_count() > 1 ? TAB_MOVE_ACTION : 0);
[email protected]36b6dcb2008-11-12 01:19:571419}
1420
1421TabContents* Browser::CreateTabContentsForURL(
1422 const GURL& url, const GURL& referrer, Profile* profile,
1423 PageTransition::Type transition, bool defer_load,
1424 SiteInstance* instance) const {
[email protected]57c6a652009-05-04 07:58:341425 TabContents* contents = new TabContents(profile, instance,
[email protected]9423d9412009-04-14 22:13:551426 MSG_ROUTING_NONE, NULL);
[email protected]36b6dcb2008-11-12 01:19:571427
1428 if (!defer_load) {
1429 // Load the initial URL before adding the new tab contents to the tab strip
1430 // so that the tab contents has navigation state.
[email protected]ce3fa3c2009-04-20 19:55:571431 contents->controller().LoadURL(url, referrer, transition);
[email protected]36b6dcb2008-11-12 01:19:571432 }
1433
1434 return contents;
1435}
1436
1437bool Browser::CanDuplicateContentsAt(int index) {
[email protected]ce3fa3c2009-04-20 19:55:571438 NavigationController& nc = GetTabContentsAt(index)->controller();
1439 return nc.tab_contents() && nc.GetLastCommittedEntry();
[email protected]36b6dcb2008-11-12 01:19:571440}
1441
1442void Browser::DuplicateContentsAt(int index) {
1443 TabContents* contents = GetTabContentsAt(index);
1444 TabContents* new_contents = NULL;
1445 DCHECK(contents);
1446
[email protected]299dabd2008-11-19 02:27:161447 if (type_ == TYPE_NORMAL) {
[email protected]36b6dcb2008-11-12 01:19:571448 // If this is a tabbed browser, just create a duplicate tab inside the same
1449 // window next to the tab being duplicated.
[email protected]ce3fa3c2009-04-20 19:55:571450 new_contents = contents->Clone();
[email protected]36b6dcb2008-11-12 01:19:571451 // If you duplicate a tab that is not selected, we need to make sure to
1452 // select the tab being duplicated so that DetermineInsertionIndex returns
1453 // the right index (if tab 5 is selected and we right-click tab 1 we want
1454 // the new tab to appear in index position 2, not 6).
1455 if (tabstrip_model_.selected_index() != index)
1456 tabstrip_model_.SelectTabContentsAt(index, true);
[email protected]5a4940be2009-05-06 06:44:391457 tabstrip_model_.AddTabContents(new_contents, index + 1, false,
[email protected]36b6dcb2008-11-12 01:19:571458 PageTransition::LINK, true);
1459 } else {
[email protected]15952e462008-11-14 00:29:051460 Browser* browser = NULL;
[email protected]d5fbc002009-02-27 22:12:581461 if (type_ & TYPE_APP) {
1462 browser = Browser::CreateForApp(app_name_, profile_, type_ & TYPE_POPUP);
[email protected]299dabd2008-11-19 02:27:161463 } else if (type_ == TYPE_POPUP) {
[email protected]15952e462008-11-14 00:29:051464 browser = Browser::CreateForPopup(profile_);
1465 }
[email protected]36b6dcb2008-11-12 01:19:571466
[email protected]b1fed962008-12-18 00:54:081467 // Preserve the size of the original window. The new window has already
1468 // been given an offset by the OS, so we shouldn't copy the old bounds.
1469 BrowserWindow* new_window = browser->window();
1470 new_window->SetBounds(gfx::Rect(new_window->GetNormalBounds().origin(),
1471 window()->GetNormalBounds().size()));
1472
[email protected]36b6dcb2008-11-12 01:19:571473 // We need to show the browser now. Otherwise ContainerWin assumes the
1474 // TabContents is invisible and won't size it.
[email protected]15952e462008-11-14 00:29:051475 browser->window()->Show();
[email protected]36b6dcb2008-11-12 01:19:571476
1477 // The page transition below is only for the purpose of inserting the tab.
[email protected]15952e462008-11-14 00:29:051478 new_contents = browser->AddTabWithNavigationController(
[email protected]ce3fa3c2009-04-20 19:55:571479 &contents->Clone()->controller(),
[email protected]36b6dcb2008-11-12 01:19:571480 PageTransition::LINK);
[email protected]36b6dcb2008-11-12 01:19:571481 }
1482
1483 if (profile_->HasSessionService()) {
1484 SessionService* session_service = profile_->GetSessionService();
1485 if (session_service)
[email protected]ce3fa3c2009-04-20 19:55:571486 session_service->TabRestored(&new_contents->controller());
[email protected]36b6dcb2008-11-12 01:19:571487 }
1488}
1489
[email protected]36b6dcb2008-11-12 01:19:571490void Browser::CloseFrameAfterDragSession() {
[email protected]d6a3c772009-01-27 19:41:201491#if defined(OS_WIN)
[email protected]36b6dcb2008-11-12 01:19:571492 // This is scheduled to run after we return to the message loop because
1493 // otherwise the frame will think the drag session is still active and ignore
1494 // the request.
[email protected]d6a3c772009-01-27 19:41:201495 // TODO(port): figure out what is required here in a cross-platform world
[email protected]36b6dcb2008-11-12 01:19:571496 MessageLoop::current()->PostTask(FROM_HERE,
1497 method_factory_.NewRunnableMethod(&Browser::CloseFrame));
[email protected]d6a3c772009-01-27 19:41:201498#endif
initial.commit09911bf2008-07-26 23:55:291499}
1500
[email protected]505323e22009-01-24 02:47:581501void Browser::CreateHistoricalTab(TabContents* contents) {
1502 // We don't create historical tabs for incognito windows or windows without
1503 // profiles.
1504 if (!profile() || profile()->IsOffTheRecord() ||
1505 !profile()->GetTabRestoreService()) {
1506 return;
1507 }
1508
1509 // We only create historical tab entries for normal tabbed browser windows.
1510 if (type() == TYPE_NORMAL) {
1511 profile()->GetTabRestoreService()->CreateHistoricalTab(
[email protected]ce3fa3c2009-04-20 19:55:571512 &contents->controller());
[email protected]505323e22009-01-24 02:47:581513 }
1514}
1515
1516bool Browser::RunUnloadListenerBeforeClosing(TabContents* contents) {
[email protected]57c6a652009-05-04 07:58:341517 // If the TabContents is not connected yet, then there's no unload
1518 // handler we can fire even if the TabContents has an unload listener.
1519 // One case where we hit this is in a tab that has an infinite loop
1520 // before load.
1521 if (TabHasUnloadListener(contents)) {
1522 // If the page has unload listeners, then we tell the renderer to fire
1523 // them. Once they have fired, we'll get a message back saying whether
1524 // to proceed closing the page or not, which sends us back to this method
1525 // with the HasUnloadListener bit cleared.
1526 contents->render_view_host()->FirePageBeforeUnload();
1527 return true;
[email protected]505323e22009-01-24 02:47:581528 }
1529 return false;
1530}
1531
[email protected]940ccb22009-04-30 17:11:101532bool Browser::CanCloseContentsAt(int index) {
1533 if (tabstrip_model_.count() > 1)
1534 return true;
1535 // We are closing the last tab for this browser. Make sure to check for
1536 // in-progress downloads.
1537 // Note that the next call when it returns false will ask the user for
1538 // confirmation before closing the browser if the user decides so.
1539 return CanCloseWithInProgressDownloads();
1540}
[email protected]d6a3c772009-01-27 19:41:201541
[email protected]2d46c842008-11-14 19:24:311542///////////////////////////////////////////////////////////////////////////////
[email protected]36b6dcb2008-11-12 01:19:571543// Browser, TabStripModelObserver implementation:
1544
1545void Browser::TabInsertedAt(TabContents* contents,
1546 int index,
1547 bool foreground) {
1548 contents->set_delegate(this);
[email protected]ce3fa3c2009-04-20 19:55:571549 contents->controller().SetWindowID(session_id());
[email protected]36b6dcb2008-11-12 01:19:571550
1551 SyncHistoryWithTabs(tabstrip_model_.GetIndexOfTabContents(contents));
1552
[email protected]159f7762008-12-19 14:58:271553 // Make sure the loading state is updated correctly, otherwise the throbber
1554 // won't start if the page is loading.
1555 LoadingStateChanged(contents);
1556
[email protected]36b6dcb2008-11-12 01:19:571557 // If the tab crashes in the beforeunload or unload handler, it won't be
1558 // able to ack. But we know we can close it.
[email protected]0cb94102009-05-22 19:51:211559 registrar_.Add(this, NotificationType::TAB_CONTENTS_DISCONNECTED,
1560 Source<TabContents>(contents));
[email protected]36b6dcb2008-11-12 01:19:571561}
1562
1563void Browser::TabClosingAt(TabContents* contents, int index) {
[email protected]bfd04a62009-02-01 18:16:561564 NotificationService::current()->Notify(
1565 NotificationType::TAB_CLOSING,
[email protected]ce3fa3c2009-04-20 19:55:571566 Source<NavigationController>(&contents->controller()),
[email protected]bfd04a62009-02-01 18:16:561567 NotificationService::NoDetails());
[email protected]36b6dcb2008-11-12 01:19:571568
1569 // Sever the TabContents' connection back to us.
1570 contents->set_delegate(NULL);
1571}
1572
1573void Browser::TabDetachedAt(TabContents* contents, int index) {
[email protected]aacfcc72009-05-27 19:39:541574 // Save what the user's currently typing.
1575 window_->GetLocationBar()->SaveStateToContents(contents);
1576
[email protected]36b6dcb2008-11-12 01:19:571577 contents->set_delegate(NULL);
1578 if (!tabstrip_model_.closing_all())
1579 SyncHistoryWithTabs(0);
1580
1581 RemoveScheduledUpdatesFor(contents);
1582
[email protected]4801ecc2009-04-05 04:52:581583 if (find_bar_controller_.get() && index == tabstrip_model_.selected_index())
[email protected]57c6a652009-05-04 07:58:341584 find_bar_controller_->ChangeTabContents(NULL);
[email protected]4801ecc2009-04-05 04:52:581585
[email protected]0cb94102009-05-22 19:51:211586 registrar_.Remove(this, NotificationType::TAB_CONTENTS_DISCONNECTED,
1587 Source<TabContents>(contents));
[email protected]36b6dcb2008-11-12 01:19:571588}
1589
1590void Browser::TabSelectedAt(TabContents* old_contents,
1591 TabContents* new_contents,
1592 int index,
1593 bool user_gesture) {
1594 DCHECK(old_contents != new_contents);
1595
1596 // If we have any update pending, do it now.
1597 if (!chrome_updater_factory_.empty() && old_contents)
1598 ProcessPendingUIUpdates();
1599
[email protected]36b6dcb2008-11-12 01:19:571600 if (old_contents) {
1601 // Save what the user's currently typing, so it can be restored when we
1602 // switch back to this tab.
[email protected]7745b822009-01-27 20:15:351603 window_->GetLocationBar()->SaveStateToContents(old_contents);
[email protected]36b6dcb2008-11-12 01:19:571604 }
1605
1606 // Propagate the profile to the location bar.
1607 UpdateToolbar(true);
1608
[email protected]64ff7942008-12-17 18:11:231609 // Update stop/go state.
[email protected]c3989812009-04-15 18:08:491610 UpdateStopGoState(new_contents->is_loading(), true);
[email protected]36b6dcb2008-11-12 01:19:571611
[email protected]84214982008-12-10 18:49:101612 // Update commands to reflect current state.
1613 UpdateCommandsForTabState();
[email protected]36b6dcb2008-11-12 01:19:571614
1615 // Reset the status bubble.
[email protected]be3877f2009-01-14 15:51:101616 StatusBubble* status_bubble = GetStatusBubble();
1617 if (status_bubble) {
1618 status_bubble->Hide();
[email protected]36b6dcb2008-11-12 01:19:571619
[email protected]be3877f2009-01-14 15:51:101620 // Show the loading state (if any).
1621 status_bubble->SetStatus(GetSelectedTabContents()->GetStatusText());
1622 }
[email protected]36b6dcb2008-11-12 01:19:571623
[email protected]4801ecc2009-04-05 04:52:581624 if (find_bar_controller_.get()) {
[email protected]57c6a652009-05-04 07:58:341625 find_bar_controller_->ChangeTabContents(new_contents);
[email protected]4801ecc2009-04-05 04:52:581626 find_bar_controller_->find_bar()->MoveWindowIfNecessary(gfx::Rect(),
1627 true);
1628 }
1629
[email protected]36b6dcb2008-11-12 01:19:571630 // Update sessions. Don't force creation of sessions. If sessions doesn't
1631 // exist, the change will be picked up by sessions when created.
1632 if (profile_->HasSessionService()) {
1633 SessionService* session_service = profile_->GetSessionService();
1634 if (session_service && !tabstrip_model_.closing_all()) {
[email protected]2d46c842008-11-14 19:24:311635 session_service->SetSelectedTabInWindow(
1636 session_id(), tabstrip_model_.selected_index());
[email protected]36b6dcb2008-11-12 01:19:571637 }
1638 }
1639}
1640
1641void Browser::TabMoved(TabContents* contents,
1642 int from_index,
1643 int to_index) {
1644 DCHECK(from_index >= 0 && to_index >= 0);
1645 // Notify the history service.
1646 SyncHistoryWithTabs(std::min(from_index, to_index));
1647}
1648
1649void Browser::TabStripEmpty() {
1650 // Close the frame after we return to the message loop (not immediately,
1651 // otherwise it will destroy this object before the stack has a chance to
1652 // cleanly unwind.)
1653 // Note: This will be called several times if TabStripEmpty is called several
1654 // times. This is because it does not close the window if tabs are
1655 // still present.
1656 // NOTE: If you change to be immediate (no invokeLater) then you'll need to
1657 // update BrowserList::CloseAllBrowsers.
1658 MessageLoop::current()->PostTask(FROM_HERE,
1659 method_factory_.NewRunnableMethod(&Browser::CloseFrame));
1660}
1661
1662///////////////////////////////////////////////////////////////////////////////
[email protected]e0c7c262009-04-23 23:09:431663// Browser, PageNavigator implementation:
1664void Browser::OpenURL(const GURL& url, const GURL& referrer,
1665 WindowOpenDisposition disposition,
1666 PageTransition::Type transition) {
1667 OpenURLFromTab(NULL, url, referrer, disposition, transition);
1668}
1669
1670///////////////////////////////////////////////////////////////////////////////
[email protected]36b6dcb2008-11-12 01:19:571671// Browser, TabContentsDelegate implementation:
initial.commit09911bf2008-07-26 23:55:291672
1673void Browser::OpenURLFromTab(TabContents* source,
[email protected]c0588052008-10-27 23:01:501674 const GURL& url, const GURL& referrer,
initial.commit09911bf2008-07-26 23:55:291675 WindowOpenDisposition disposition,
[email protected]e38f40152008-09-12 23:08:301676 PageTransition::Type transition) {
[email protected]20df155d2009-02-04 19:13:301677 // TODO(beng): Move all this code into a separate helper that has unit tests.
1678
initial.commit09911bf2008-07-26 23:55:291679 // No code for these yet
1680 DCHECK((disposition != NEW_POPUP) && (disposition != SAVE_TO_DISK));
1681
1682 TabContents* current_tab = source ? source : GetSelectedTabContents();
1683 bool source_tab_was_frontmost = (current_tab == GetSelectedTabContents());
1684 TabContents* new_contents = NULL;
1685
1686 // If the URL is part of the same web site, then load it in the same
1687 // SiteInstance (and thus the same process). This is an optimization to
1688 // reduce process overhead; it is not necessary for compatibility. (That is,
1689 // the new tab will not have script connections to the previous tab, so it
1690 // does not need to be part of the same SiteInstance or BrowsingInstance.)
1691 // Default to loading in a new SiteInstance and BrowsingInstance.
1692 // TODO(creis): should this apply to applications?
1693 SiteInstance* instance = NULL;
1694 // Don't use this logic when "--process-per-tab" is specified.
[email protected]bb975362009-01-21 01:00:221695 if (!CommandLine::ForCurrentProcess()->HasSwitch(switches::kProcessPerTab)) {
initial.commit09911bf2008-07-26 23:55:291696 if (current_tab) {
[email protected]57c6a652009-05-04 07:58:341697 const GURL& current_url = current_tab->GetURL();
1698 if (SiteInstance::IsSameWebSite(current_url, url))
1699 instance = current_tab->GetSiteInstance();
initial.commit09911bf2008-07-26 23:55:291700 }
1701 }
1702
[email protected]1aa8f502009-04-23 05:49:471703 // If this is not a normal window (such as a popup or an application), we can
1704 // only have one tab so a new tab always goes into a tabbed browser window.
1705 if (disposition != NEW_WINDOW && type_ != TYPE_NORMAL) {
initial.commit09911bf2008-07-26 23:55:291706 // If the disposition is OFF_THE_RECORD we don't want to create a new
1707 // browser that will itself create another OTR browser. This will result in
1708 // a browser leak (and crash below because no tab is created or selected).
1709 if (disposition == OFF_THE_RECORD) {
1710 OpenURLOffTheRecord(profile_, url);
1711 return;
1712 }
1713
1714 Browser* b = GetOrCreateTabbedBrowser();
1715 DCHECK(b);
1716
1717 // If we have just created a new browser window, make sure we select the
1718 // tab.
1719 if (b->tab_count() == 0 && disposition == NEW_BACKGROUND_TAB)
1720 disposition = NEW_FOREGROUND_TAB;
1721
[email protected]c0588052008-10-27 23:01:501722 b->OpenURL(url, referrer, disposition, transition);
[email protected]15952e462008-11-14 00:29:051723 b->window()->Show();
initial.commit09911bf2008-07-26 23:55:291724 return;
1725 }
1726
1727 if (profile_->IsOffTheRecord() && disposition == OFF_THE_RECORD)
1728 disposition = NEW_FOREGROUND_TAB;
1729
[email protected]fba16f52009-04-02 22:30:351730 if (disposition == SINGLETON_TAB) {
1731 ShowSingleDOMUITab(url);
1732 return;
1733 } else if (disposition == NEW_WINDOW) {
[email protected]15952e462008-11-14 00:29:051734 Browser* browser = Browser::Create(profile_);
[email protected]22735af62009-04-07 21:09:581735 new_contents = browser->AddTabWithURL(url, referrer, transition, true, -1,
[email protected]5a4940be2009-05-06 06:44:391736 false, instance);
[email protected]15952e462008-11-14 00:29:051737 browser->window()->Show();
initial.commit09911bf2008-07-26 23:55:291738 } else if ((disposition == CURRENT_TAB) && current_tab) {
[email protected]3eac70b2009-02-10 22:25:091739 tabstrip_model_.TabNavigating(current_tab, transition);
1740
[email protected]ce3fa3c2009-04-20 19:55:571741 current_tab->controller().LoadURL(url, referrer, transition);
1742 new_contents = current_tab;
[email protected]be3877f2009-01-14 15:51:101743 if (GetStatusBubble())
1744 GetStatusBubble()->Hide();
initial.commit09911bf2008-07-26 23:55:291745
[email protected]329581b2009-04-28 06:52:351746 // Update the location bar. This is synchronous. We specfically don't update
1747 // the load state since the load hasn't started yet and updating it will put
1748 // it out of sync with the actual state like whether we're displaying a
1749 // favicon, which controls the throbber. If we updated it here, the throbber
1750 // will show the default favicon for a split second when navigating away
1751 // from the new tab page.
1752 ScheduleUIUpdate(current_tab, TabContents::INVALIDATE_URL);
initial.commit09911bf2008-07-26 23:55:291753 } else if (disposition == OFF_THE_RECORD) {
1754 OpenURLOffTheRecord(profile_, url);
1755 return;
1756 } else if (disposition != SUPPRESS_OPEN) {
[email protected]15952e462008-11-14 00:29:051757 new_contents = AddTabWithURL(url, referrer, transition,
[email protected]5a4940be2009-05-06 06:44:391758 disposition != NEW_BACKGROUND_TAB, -1, false,
[email protected]22735af62009-04-07 21:09:581759 instance);
initial.commit09911bf2008-07-26 23:55:291760 }
1761
1762 if (disposition != NEW_BACKGROUND_TAB && source_tab_was_frontmost) {
[email protected]2baf83d2008-07-30 05:58:171763 // Give the focus to the newly navigated tab, if the source tab was
1764 // front-most.
initial.commit09911bf2008-07-26 23:55:291765 new_contents->Focus();
1766 }
1767}
1768
1769void Browser::NavigationStateChanged(const TabContents* source,
1770 unsigned changed_flags) {
initial.commit09911bf2008-07-26 23:55:291771 // Only update the UI when something visible has changed.
[email protected]e83f1682008-09-07 23:57:401772 if (changed_flags)
initial.commit09911bf2008-07-26 23:55:291773 ScheduleUIUpdate(source, changed_flags);
1774
[email protected]84214982008-12-10 18:49:101775 // We don't schedule updates to commands since they will only change once per
1776 // navigation, so we don't have to worry about flickering.
[email protected]e83f1682008-09-07 23:57:401777 if (changed_flags & TabContents::INVALIDATE_URL)
[email protected]84214982008-12-10 18:49:101778 UpdateCommandsForTabState();
initial.commit09911bf2008-07-26 23:55:291779}
1780
initial.commit09911bf2008-07-26 23:55:291781void Browser::AddNewContents(TabContents* source,
1782 TabContents* new_contents,
1783 WindowOpenDisposition disposition,
1784 const gfx::Rect& initial_pos,
1785 bool user_gesture) {
1786 DCHECK(disposition != SAVE_TO_DISK); // No code for this yet
[email protected]b680ad22009-04-15 23:19:421787 DCHECK(disposition != CURRENT_TAB); // Can't create a new contents for the
1788 // current tab.
initial.commit09911bf2008-07-26 23:55:291789
1790 // If this is an application we can only have one tab so we need to process
[email protected]ebdcf9742009-01-23 05:25:281791 // this in tabbed browser window.
1792 if (tabstrip_model_.count() > 0 &&
initial.commit09911bf2008-07-26 23:55:291793 disposition != NEW_WINDOW && disposition != NEW_POPUP &&
[email protected]299dabd2008-11-19 02:27:161794 type_ != TYPE_NORMAL) {
initial.commit09911bf2008-07-26 23:55:291795 Browser* b = GetOrCreateTabbedBrowser();
1796 DCHECK(b);
1797 PageTransition::Type transition = PageTransition::LINK;
1798 // If we were called from an "installed webapp" we want to emulate the code
1799 // that is run from browser_init.cc for links from external applications.
1800 // This means we need to open the tab with the START PAGE transition.
1801 // AddNewContents doesn't support this but the TabStripModel's
1802 // AddTabContents method does.
[email protected]d5fbc002009-02-27 22:12:581803 if (type_ & TYPE_APP)
initial.commit09911bf2008-07-26 23:55:291804 transition = PageTransition::START_PAGE;
[email protected]4d34e2e2009-05-26 22:55:281805 b->tabstrip_model()->AddTabContents(new_contents, -1, false, transition,
1806 true);
[email protected]ebdcf9742009-01-23 05:25:281807 b->window()->Show();
initial.commit09911bf2008-07-26 23:55:291808 return;
1809 }
1810
1811 if (disposition == NEW_POPUP) {
1812 BuildPopupWindow(source, new_contents, initial_pos);
1813 } else if (disposition == NEW_WINDOW) {
[email protected]15952e462008-11-14 00:29:051814 Browser* browser = Browser::Create(profile_);
1815 browser->AddNewContents(source, new_contents, NEW_FOREGROUND_TAB,
1816 initial_pos, user_gesture);
1817 browser->window()->Show();
initial.commit09911bf2008-07-26 23:55:291818 } else if (disposition != SUPPRESS_OPEN) {
[email protected]4d34e2e2009-05-26 22:55:281819 tabstrip_model_.AddTabContents(new_contents, -1, false,
1820 PageTransition::LINK,
initial.commit09911bf2008-07-26 23:55:291821 disposition == NEW_FOREGROUND_TAB);
1822 }
1823}
1824
initial.commit09911bf2008-07-26 23:55:291825void Browser::ActivateContents(TabContents* contents) {
1826 tabstrip_model_.SelectTabContentsAt(
1827 tabstrip_model_.GetIndexOfTabContents(contents), false);
[email protected]f3e99e32008-07-30 04:48:391828 window_->Activate();
initial.commit09911bf2008-07-26 23:55:291829}
1830
initial.commit09911bf2008-07-26 23:55:291831void Browser::LoadingStateChanged(TabContents* source) {
[email protected]afb73882008-11-14 22:40:441832 window_->UpdateLoadingAnimations(tabstrip_model_.TabsAreLoading());
[email protected]f3e99e32008-07-30 04:48:391833 window_->UpdateTitleBar();
initial.commit09911bf2008-07-26 23:55:291834
initial.commit09911bf2008-07-26 23:55:291835 if (source == GetSelectedTabContents()) {
[email protected]c3989812009-04-15 18:08:491836 UpdateStopGoState(source->is_loading(), false);
[email protected]be3877f2009-01-14 15:51:101837 if (GetStatusBubble())
1838 GetStatusBubble()->SetStatus(GetSelectedTabContents()->GetStatusText());
initial.commit09911bf2008-07-26 23:55:291839 }
1840}
1841
1842void Browser::CloseContents(TabContents* source) {
[email protected]04b4a6c2008-08-02 00:44:471843 if (is_attempting_to_close_browser_) {
1844 // If we're trying to close the browser, just clear the state related to
[email protected]adf650f2008-12-09 16:10:061845 // waiting for unload to fire. Don't actually try to close the tab as it
[email protected]04b4a6c2008-08-02 00:44:471846 // will go down the slow shutdown path instead of the fast path of killing
1847 // all the renderer processes.
[email protected]8a2ce5a2008-08-11 23:43:081848 ClearUnloadState(source);
[email protected]04b4a6c2008-08-02 00:44:471849 return;
1850 }
1851
initial.commit09911bf2008-07-26 23:55:291852 int index = tabstrip_model_.GetIndexOfTabContents(source);
1853 if (index == TabStripModel::kNoTab) {
1854 NOTREACHED() << "CloseContents called for tab not in our strip";
1855 return;
1856 }
1857 tabstrip_model_.CloseTabContentsAt(index);
1858}
1859
[email protected]15e8abe2008-08-20 22:40:401860void Browser::MoveContents(TabContents* source, const gfx::Rect& pos) {
[email protected]d5fbc002009-02-27 22:12:581861 if ((type() & TYPE_POPUP) == 0) {
initial.commit09911bf2008-07-26 23:55:291862 NOTREACHED() << "moving invalid browser type";
1863 return;
1864 }
[email protected]2d46c842008-11-14 19:24:311865 window_->SetBounds(pos);
initial.commit09911bf2008-07-26 23:55:291866}
1867
[email protected]b6c874582009-05-08 19:38:311868void Browser::DetachContents(TabContents* source) {
1869 int index = tabstrip_model_.GetIndexOfTabContents(source);
1870 if (index >= 0)
1871 tabstrip_model_.DetachTabContentsAt(index);
1872}
1873
initial.commit09911bf2008-07-26 23:55:291874bool Browser::IsPopup(TabContents* source) {
1875 // A non-tabbed BROWSER is an unconstrained popup.
[email protected]d5fbc002009-02-27 22:12:581876 return (type() & TYPE_POPUP);
initial.commit09911bf2008-07-26 23:55:291877}
1878
[email protected]36b6dcb2008-11-12 01:19:571879void Browser::ToolbarSizeChanged(TabContents* source, bool is_animating) {
1880 if (source == GetSelectedTabContents() || source == NULL) {
1881 // This will refresh the shelf if needed.
1882 window_->SelectedTabToolbarSizeChanged(is_animating);
1883 }
1884}
1885
1886void Browser::URLStarredChanged(TabContents* source, bool starred) {
1887 if (source == GetSelectedTabContents())
[email protected]b7ca4e62009-01-23 20:37:291888 window_->SetStarredState(starred);
[email protected]36b6dcb2008-11-12 01:19:571889}
1890
[email protected]b6406032009-03-19 15:10:151891void Browser::ContentsMouseEvent(TabContents* source, bool motion) {
[email protected]be3877f2009-01-14 15:51:101892 if (!GetStatusBubble())
1893 return;
1894
[email protected]36b6dcb2008-11-12 01:19:571895 if (source == GetSelectedTabContents()) {
[email protected]b6406032009-03-19 15:10:151896 if (motion) {
[email protected]36b6dcb2008-11-12 01:19:571897 GetStatusBubble()->MouseMoved();
[email protected]b6406032009-03-19 15:10:151898 } else {
[email protected]36b6dcb2008-11-12 01:19:571899 GetStatusBubble()->SetURL(GURL(), std::wstring());
1900 }
1901 }
1902}
1903
1904void Browser::UpdateTargetURL(TabContents* source, const GURL& url) {
[email protected]be3877f2009-01-14 15:51:101905 if (!GetStatusBubble())
1906 return;
1907
[email protected]36b6dcb2008-11-12 01:19:571908 if (source == GetSelectedTabContents()) {
1909 PrefService* prefs = profile_->GetPrefs();
1910 GetStatusBubble()->SetURL(url, prefs->GetString(prefs::kAcceptLanguages));
1911 }
1912}
1913
[email protected]3a6a3b62009-05-27 21:36:201914void Browser::UpdateDownloadShelfVisibility(bool visible) {
1915 GetStatusBubble()->UpdateDownloadShelfVisibility(visible);
1916}
1917
[email protected]36b6dcb2008-11-12 01:19:571918void Browser::ContentsZoomChange(bool zoom_in) {
[email protected]1fc025202009-01-20 23:03:141919 ExecuteCommand(zoom_in ? IDC_ZOOM_PLUS : IDC_ZOOM_MINUS);
[email protected]36b6dcb2008-11-12 01:19:571920}
1921
1922bool Browser::IsApplication() const {
[email protected]d5fbc002009-02-27 22:12:581923 return (type_ & TYPE_APP) != 0;
[email protected]36b6dcb2008-11-12 01:19:571924}
1925
1926void Browser::ConvertContentsToApplication(TabContents* contents) {
[email protected]ce3fa3c2009-04-20 19:55:571927 const GURL& url = contents->controller().GetActiveEntry()->url();
[email protected]0303f31c2009-02-02 06:42:051928 std::wstring app_name = ComputeApplicationNameFromURL(url);
[email protected]36b6dcb2008-11-12 01:19:571929 RegisterAppPrefs(app_name);
1930
[email protected]b6c874582009-05-08 19:38:311931 DetachContents(contents);
[email protected]d5fbc002009-02-27 22:12:581932 Browser* browser = Browser::CreateForApp(app_name, profile_, false);
[email protected]15952e462008-11-14 00:29:051933 browser->tabstrip_model()->AppendTabContents(contents, true);
1934 browser->window()->Show();
[email protected]36b6dcb2008-11-12 01:19:571935}
1936
[email protected]36b6dcb2008-11-12 01:19:571937bool Browser::ShouldDisplayURLField() {
1938 return !IsApplication();
1939}
1940
1941void Browser::BeforeUnloadFired(TabContents* tab,
1942 bool proceed,
1943 bool* proceed_to_fire_unload) {
1944 if (!is_attempting_to_close_browser_) {
1945 *proceed_to_fire_unload = proceed;
1946 return;
1947 }
1948
1949 if (!proceed) {
1950 CancelWindowClose();
1951 *proceed_to_fire_unload = false;
1952 return;
1953 }
1954
[email protected]06b42f032008-12-03 18:43:051955 if (RemoveFromSet(&tabs_needing_before_unload_fired_, tab)) {
[email protected]2d46c842008-11-14 19:24:311956 // Now that beforeunload has fired, put the tab on the queue to fire
1957 // unload.
[email protected]06b42f032008-12-03 18:43:051958 tabs_needing_unload_fired_.insert(tab);
[email protected]36b6dcb2008-11-12 01:19:571959 ProcessPendingTabs();
[email protected]adf650f2008-12-09 16:10:061960 // We want to handle firing the unload event ourselves since we want to
[email protected]36b6dcb2008-11-12 01:19:571961 // fire all the beforeunload events before attempting to fire the unload
1962 // events should the user cancel closing the browser.
1963 *proceed_to_fire_unload = false;
1964 return;
1965 }
1966
1967 *proceed_to_fire_unload = true;
1968}
1969
[email protected]f21c613a2009-02-12 14:46:171970gfx::Rect Browser::GetRootWindowResizerRect() const {
1971 return window_->GetRootWindowResizerRect();
1972}
1973
[email protected]4acc19a62009-04-03 03:05:111974void Browser::ShowHtmlDialog(HtmlDialogUIDelegate* delegate,
[email protected]322f3ff2009-05-22 16:19:541975 gfx::NativeWindow parent_window) {
[email protected]2d46c842008-11-14 19:24:311976 window_->ShowHTMLDialog(delegate, parent_window);
initial.commit09911bf2008-07-26 23:55:291977}
1978
[email protected]4bcefee2009-01-29 15:57:571979void Browser::SetFocusToLocationBar() {
[email protected]1a380622009-02-17 17:33:131980 // Two differences between this and FocusLocationBar():
1981 // (1) This doesn't get recorded in user metrics, since it's called
1982 // internally.
1983 // (2) This checks whether the location bar can be focused, and if not, clears
1984 // the focus. FocusLocationBar() is only reached when the location bar is
1985 // focusable, but this may be reached at other times, e.g. while in
1986 // fullscreen mode, where we need to leave focus in a consistent state.
1987 window_->SetFocusToLocationBar();
[email protected]4bcefee2009-01-29 15:57:571988}
1989
[email protected]7d5925a2009-03-03 02:59:121990void Browser::RenderWidgetShowing() {
1991 window_->DisableInactiveFrame();
1992}
[email protected]a239c3f2009-02-17 22:13:191993
[email protected]6dfed102009-04-28 03:09:531994ExtensionFunctionDispatcher* Browser::CreateExtensionFunctionDispatcher(
1995 RenderViewHost* render_view_host,
1996 const std::string& extension_id) {
1997 return new ExtensionFunctionDispatcher(render_view_host, this, extension_id);
1998}
1999
[email protected]0a2aeb82009-05-15 21:52:482000int Browser::GetExtraRenderViewHeight() const {
2001 return window_->GetExtraRenderViewHeight();
2002}
2003
[email protected]36b6dcb2008-11-12 01:19:572004///////////////////////////////////////////////////////////////////////////////
2005// Browser, SelectFileDialog::Listener implementation:
2006
[email protected]561abe62009-04-06 18:08:342007void Browser::FileSelected(const FilePath& path, int index, void* params) {
[email protected]72cbd322009-04-07 10:17:122008 GURL file_url = net::FilePathToFileURL(path);
[email protected]36b6dcb2008-11-12 01:19:572009 if (!file_url.is_empty())
2010 OpenURL(file_url, GURL(), CURRENT_TAB, PageTransition::TYPED);
2011}
2012
[email protected]a239c3f2009-02-17 22:13:192013
[email protected]36b6dcb2008-11-12 01:19:572014///////////////////////////////////////////////////////////////////////////////
2015// Browser, NotificationObserver implementation:
2016
initial.commit09911bf2008-07-26 23:55:292017void Browser::Observe(NotificationType type,
2018 const NotificationSource& source,
2019 const NotificationDetails& details) {
[email protected]bfd04a62009-02-01 18:16:562020 switch (type.value) {
[email protected]57c6a652009-05-04 07:58:342021 case NotificationType::TAB_CONTENTS_DISCONNECTED:
[email protected]e83f1682008-09-07 23:57:402022 if (is_attempting_to_close_browser_) {
2023 // Need to do this asynchronously as it will close the tab, which is
2024 // currently on the call stack above us.
2025 MessageLoop::current()->PostTask(FROM_HERE,
2026 method_factory_.NewRunnableMethod(&Browser::ClearUnloadState,
2027 Source<TabContents>(source).ptr()));
2028 }
2029 break;
2030
[email protected]b4a19ea2009-03-17 10:08:242031 case NotificationType::SSL_VISIBLE_STATE_CHANGED:
[email protected]e83f1682008-09-07 23:57:402032 // When the current tab's SSL state changes, we need to update the URL
[email protected]90e8d062008-09-08 02:26:322033 // bar to reflect the new state. Note that it's possible for the selected
2034 // tab contents to be NULL. This is because we listen for all sources
2035 // (NavigationControllers) for convenience, so the notification could
2036 // actually be for a different window while we're doing asynchronous
2037 // closing of this one.
2038 if (GetSelectedTabContents() &&
[email protected]ce3fa3c2009-04-20 19:55:572039 &GetSelectedTabContents()->controller() ==
[email protected]e83f1682008-09-07 23:57:402040 Source<NavigationController>(source).ptr())
[email protected]36b6dcb2008-11-12 01:19:572041 UpdateToolbar(false);
[email protected]e83f1682008-09-07 23:57:402042 break;
2043
[email protected]894bb502009-05-21 22:39:572044 case NotificationType::EXTENSION_UNLOADED: {
2045 // Close any tabs from the unloaded extension.
2046 Extension* extension = Details<Extension>(details).ptr();
2047 for (int i = 0; i < tabstrip_model_.count(); i++) {
2048 TabContents* tc = tabstrip_model_.GetTabContentsAt(i);
2049 if (tc->GetURL().SchemeIs(chrome::kExtensionScheme) &&
2050 tc->GetURL().host() == extension->id()) {
2051 CloseTabContents(tc);
2052 return;
2053 }
2054 }
2055 break;
2056 }
2057
[email protected]e83f1682008-09-07 23:57:402058 default:
2059 NOTREACHED() << "Got a notification we didn't register for.";
initial.commit09911bf2008-07-26 23:55:292060 }
2061}
2062
[email protected]88d74942009-01-21 22:04:442063
[email protected]36b6dcb2008-11-12 01:19:572064///////////////////////////////////////////////////////////////////////////////
2065// Browser, Command and state updating (private):
2066
2067void Browser::InitCommandState() {
2068 // All browser commands whose state isn't set automagically some other way
2069 // (like Back & Forward with initial page load) must have their state
2070 // initialized here, otherwise they will be forever disabled.
2071
[email protected]84214982008-12-10 18:49:102072 // Navigation commands
[email protected]1fc025202009-01-20 23:03:142073 command_updater_.UpdateCommandEnabled(IDC_RELOAD, true);
[email protected]84214982008-12-10 18:49:102074
2075 // Window management commands
[email protected]1fc025202009-01-20 23:03:142076 command_updater_.UpdateCommandEnabled(IDC_NEW_WINDOW, true);
2077 command_updater_.UpdateCommandEnabled(IDC_NEW_INCOGNITO_WINDOW, true);
[email protected]84214982008-12-10 18:49:102078 // TODO(pkasting): Perhaps the code that populates this submenu should do
2079 // this?
[email protected]1fc025202009-01-20 23:03:142080 command_updater_.UpdateCommandEnabled(IDC_NEW_WINDOW_PROFILE_0, true);
2081 command_updater_.UpdateCommandEnabled(IDC_NEW_WINDOW_PROFILE_1, true);
2082 command_updater_.UpdateCommandEnabled(IDC_NEW_WINDOW_PROFILE_2, true);
2083 command_updater_.UpdateCommandEnabled(IDC_NEW_WINDOW_PROFILE_3, true);
2084 command_updater_.UpdateCommandEnabled(IDC_NEW_WINDOW_PROFILE_4, true);
2085 command_updater_.UpdateCommandEnabled(IDC_NEW_WINDOW_PROFILE_5, true);
2086 command_updater_.UpdateCommandEnabled(IDC_NEW_WINDOW_PROFILE_6, true);
2087 command_updater_.UpdateCommandEnabled(IDC_NEW_WINDOW_PROFILE_7, true);
2088 command_updater_.UpdateCommandEnabled(IDC_NEW_WINDOW_PROFILE_8, true);
2089 command_updater_.UpdateCommandEnabled(IDC_CLOSE_WINDOW, true);
2090 command_updater_.UpdateCommandEnabled(IDC_NEW_TAB, true);
2091 command_updater_.UpdateCommandEnabled(IDC_CLOSE_TAB, true);
2092 command_updater_.UpdateCommandEnabled(IDC_DUPLICATE_TAB, true);
[email protected]9282cea2009-02-18 18:49:002093 command_updater_.UpdateCommandEnabled(IDC_FULLSCREEN, true);
[email protected]1fc025202009-01-20 23:03:142094 command_updater_.UpdateCommandEnabled(IDC_EXIT, true);
[email protected]84214982008-12-10 18:49:102095
2096 // Page-related commands
[email protected]1fc025202009-01-20 23:03:142097 command_updater_.UpdateCommandEnabled(IDC_CLOSE_POPUPS, true);
2098 command_updater_.UpdateCommandEnabled(IDC_ENCODING_AUTO_DETECT, true);
2099 command_updater_.UpdateCommandEnabled(IDC_ENCODING_UTF8, true);
2100 command_updater_.UpdateCommandEnabled(IDC_ENCODING_UTF16LE, true);
2101 command_updater_.UpdateCommandEnabled(IDC_ENCODING_ISO88591, true);
2102 command_updater_.UpdateCommandEnabled(IDC_ENCODING_WINDOWS1252, true);
2103 command_updater_.UpdateCommandEnabled(IDC_ENCODING_GBK, true);
2104 command_updater_.UpdateCommandEnabled(IDC_ENCODING_GB18030, true);
2105 command_updater_.UpdateCommandEnabled(IDC_ENCODING_BIG5HKSCS, true);
2106 command_updater_.UpdateCommandEnabled(IDC_ENCODING_BIG5, true);
2107 command_updater_.UpdateCommandEnabled(IDC_ENCODING_THAI, true);
2108 command_updater_.UpdateCommandEnabled(IDC_ENCODING_KOREAN, true);
2109 command_updater_.UpdateCommandEnabled(IDC_ENCODING_SHIFTJIS, true);
2110 command_updater_.UpdateCommandEnabled(IDC_ENCODING_ISO2022JP, true);
2111 command_updater_.UpdateCommandEnabled(IDC_ENCODING_EUCJP, true);
2112 command_updater_.UpdateCommandEnabled(IDC_ENCODING_ISO885915, true);
2113 command_updater_.UpdateCommandEnabled(IDC_ENCODING_MACINTOSH, true);
2114 command_updater_.UpdateCommandEnabled(IDC_ENCODING_ISO88592, true);
2115 command_updater_.UpdateCommandEnabled(IDC_ENCODING_WINDOWS1250, true);
2116 command_updater_.UpdateCommandEnabled(IDC_ENCODING_ISO88595, true);
2117 command_updater_.UpdateCommandEnabled(IDC_ENCODING_WINDOWS1251, true);
2118 command_updater_.UpdateCommandEnabled(IDC_ENCODING_KOI8R, true);
2119 command_updater_.UpdateCommandEnabled(IDC_ENCODING_KOI8U, true);
2120 command_updater_.UpdateCommandEnabled(IDC_ENCODING_ISO88597, true);
2121 command_updater_.UpdateCommandEnabled(IDC_ENCODING_WINDOWS1253, true);
2122 command_updater_.UpdateCommandEnabled(IDC_ENCODING_ISO88594, true);
2123 command_updater_.UpdateCommandEnabled(IDC_ENCODING_ISO885913, true);
2124 command_updater_.UpdateCommandEnabled(IDC_ENCODING_WINDOWS1257, true);
2125 command_updater_.UpdateCommandEnabled(IDC_ENCODING_ISO88593, true);
2126 command_updater_.UpdateCommandEnabled(IDC_ENCODING_ISO885910, true);
2127 command_updater_.UpdateCommandEnabled(IDC_ENCODING_ISO885914, true);
2128 command_updater_.UpdateCommandEnabled(IDC_ENCODING_ISO885916, true);
2129 command_updater_.UpdateCommandEnabled(IDC_ENCODING_WINDOWS1254, true);
2130 command_updater_.UpdateCommandEnabled(IDC_ENCODING_ISO88596, true);
2131 command_updater_.UpdateCommandEnabled(IDC_ENCODING_WINDOWS1256, true);
2132 command_updater_.UpdateCommandEnabled(IDC_ENCODING_ISO88598, true);
[email protected]e13271f2009-03-07 00:26:002133 command_updater_.UpdateCommandEnabled(IDC_ENCODING_ISO88598I, true);
[email protected]1fc025202009-01-20 23:03:142134 command_updater_.UpdateCommandEnabled(IDC_ENCODING_WINDOWS1255, true);
2135 command_updater_.UpdateCommandEnabled(IDC_ENCODING_WINDOWS1258, true);
[email protected]84214982008-12-10 18:49:102136
2137 // Clipboard commands
[email protected]1fc025202009-01-20 23:03:142138 command_updater_.UpdateCommandEnabled(IDC_CUT, true);
2139 command_updater_.UpdateCommandEnabled(IDC_COPY, true);
2140 command_updater_.UpdateCommandEnabled(IDC_COPY_URL, true);
2141 command_updater_.UpdateCommandEnabled(IDC_PASTE, true);
[email protected]84214982008-12-10 18:49:102142
[email protected]84214982008-12-10 18:49:102143 // Show various bits of UI
[email protected]1fc025202009-01-20 23:03:142144 command_updater_.UpdateCommandEnabled(IDC_OPEN_FILE, true);
2145 command_updater_.UpdateCommandEnabled(IDC_CREATE_SHORTCUTS, false);
[email protected]0800c662009-05-08 19:41:492146#if defined(OS_WIN)
2147 // Command line debugger conflicts with the new oop one.
[email protected]2ef9c452009-05-13 13:03:142148 bool in_proc_devtools = CommandLine::ForCurrentProcess()->HasSwitch(
2149 switches::kDisableOutOfProcessDevTools);
[email protected]0800c662009-05-08 19:41:492150 command_updater_.UpdateCommandEnabled(IDC_DEBUGGER,
2151 // The debugger doesn't work in single process mode.
[email protected]2ef9c452009-05-13 13:03:142152 in_proc_devtools && !RenderProcessHost::run_renderer_in_process());
[email protected]0800c662009-05-08 19:41:492153#endif
[email protected]1fc025202009-01-20 23:03:142154 command_updater_.UpdateCommandEnabled(IDC_TASK_MANAGER, true);
2155 command_updater_.UpdateCommandEnabled(IDC_SELECT_PROFILE, true);
2156 command_updater_.UpdateCommandEnabled(IDC_SHOW_HISTORY, true);
2157 command_updater_.UpdateCommandEnabled(IDC_SHOW_BOOKMARK_MANAGER, true);
2158 command_updater_.UpdateCommandEnabled(IDC_SHOW_DOWNLOADS, true);
2159 command_updater_.UpdateCommandEnabled(IDC_HELP_PAGE, true);
[email protected]64ff7942008-12-17 18:11:232160
2161 // Initialize other commands based on the window type.
2162 {
2163 bool normal_window = type() == TYPE_NORMAL;
2164
2165 // Navigation commands
[email protected]1fc025202009-01-20 23:03:142166 command_updater_.UpdateCommandEnabled(IDC_HOME, normal_window);
[email protected]64ff7942008-12-17 18:11:232167
2168 // Window management commands
[email protected]1fc025202009-01-20 23:03:142169 command_updater_.UpdateCommandEnabled(IDC_SELECT_NEXT_TAB, normal_window);
2170 command_updater_.UpdateCommandEnabled(IDC_SELECT_PREVIOUS_TAB,
2171 normal_window);
2172 command_updater_.UpdateCommandEnabled(IDC_SELECT_TAB_0, normal_window);
2173 command_updater_.UpdateCommandEnabled(IDC_SELECT_TAB_1, normal_window);
2174 command_updater_.UpdateCommandEnabled(IDC_SELECT_TAB_2, normal_window);
2175 command_updater_.UpdateCommandEnabled(IDC_SELECT_TAB_3, normal_window);
2176 command_updater_.UpdateCommandEnabled(IDC_SELECT_TAB_4, normal_window);
2177 command_updater_.UpdateCommandEnabled(IDC_SELECT_TAB_5, normal_window);
2178 command_updater_.UpdateCommandEnabled(IDC_SELECT_TAB_6, normal_window);
2179 command_updater_.UpdateCommandEnabled(IDC_SELECT_TAB_7, normal_window);
2180 command_updater_.UpdateCommandEnabled(IDC_SELECT_LAST_TAB, normal_window);
2181 command_updater_.UpdateCommandEnabled(IDC_RESTORE_TAB,
[email protected]64ff7942008-12-17 18:11:232182 normal_window && !profile_->IsOffTheRecord());
[email protected]d5c99b172009-02-25 17:09:212183
2184 // Show various bits of UI
[email protected]7fd4cc32009-04-15 23:17:372185 command_updater_.UpdateCommandEnabled(IDC_CLEAR_BROWSING_DATA,
2186 normal_window);
[email protected]64ff7942008-12-17 18:11:232187 }
[email protected]9282cea2009-02-18 18:49:002188
2189 // Initialize other commands whose state changes based on fullscreen mode.
2190 UpdateCommandsForFullscreenMode(false);
[email protected]36b6dcb2008-11-12 01:19:572191}
2192
[email protected]84214982008-12-10 18:49:102193void Browser::UpdateCommandsForTabState() {
[email protected]c7c42332008-11-15 01:10:542194 TabContents* current_tab = GetSelectedTabContents();
[email protected]64ff7942008-12-17 18:11:232195 if (!current_tab) // May be NULL during tab restore.
[email protected]d8375fd2008-11-25 22:45:392196 return;
[email protected]d8375fd2008-11-25 22:45:392197
[email protected]84214982008-12-10 18:49:102198 // Navigation commands
[email protected]ce3fa3c2009-04-20 19:55:572199 NavigationController& nc = current_tab->controller();
2200 command_updater_.UpdateCommandEnabled(IDC_BACK, nc.CanGoBack());
2201 command_updater_.UpdateCommandEnabled(IDC_FORWARD, nc.CanGoForward());
initial.commit09911bf2008-07-26 23:55:292202
[email protected]84214982008-12-10 18:49:102203 // Window management commands
[email protected]1fc025202009-01-20 23:03:142204 command_updater_.UpdateCommandEnabled(IDC_DUPLICATE_TAB,
2205 CanDuplicateContentsAt(selected_index()));
[email protected]84214982008-12-10 18:49:102206
[email protected]57c6a652009-05-04 07:58:342207 // Current navigation entry, may be NULL.
2208 NavigationEntry* active_entry = current_tab->controller().GetActiveEntry();
[email protected]2bfd94d2009-04-29 20:32:032209 bool is_source_viewable =
[email protected]2bfd94d2009-04-29 20:32:032210 net::IsSupportedNonImageMimeType(
[email protected]57c6a652009-05-04 07:58:342211 current_tab->contents_mime_type().c_str());
[email protected]84214982008-12-10 18:49:102212
[email protected]57c6a652009-05-04 07:58:342213 // Page-related commands
2214 // Only allow bookmarking for web content in normal windows.
2215 command_updater_.UpdateCommandEnabled(IDC_STAR, (type() == TYPE_NORMAL));
2216 window_->SetStarredState(current_tab->is_starred());
2217 // View-source should not be enabled if already in view-source mode or
2218 // the source is not viewable.
2219 command_updater_.UpdateCommandEnabled(IDC_VIEW_SOURCE,
2220 active_entry && !active_entry->IsViewSourceMode() &&
2221 is_source_viewable);
2222 command_updater_.UpdateCommandEnabled(IDC_PRINT, true);
2223 command_updater_.UpdateCommandEnabled(IDC_SAVE_PAGE,
2224 SavePackage::IsSavableURL(current_tab->GetURL()));
2225 command_updater_.UpdateCommandEnabled(IDC_ENCODING_MENU,
2226 SavePackage::IsSavableContents(current_tab->contents_mime_type()) &&
2227 SavePackage::IsSavableURL(current_tab->GetURL()));
[email protected]6de74452009-02-25 18:04:592228
[email protected]fcce10d2009-05-04 10:00:182229 // Find-in-page
2230 command_updater_.UpdateCommandEnabled(IDC_FIND, true);
2231 command_updater_.UpdateCommandEnabled(IDC_FIND_NEXT, true);
2232 command_updater_.UpdateCommandEnabled(IDC_FIND_PREVIOUS, true);
2233
[email protected]57c6a652009-05-04 07:58:342234 // Zoom
2235 command_updater_.UpdateCommandEnabled(IDC_ZOOM_MENU, true);
2236 command_updater_.UpdateCommandEnabled(IDC_ZOOM_PLUS, true);
2237 command_updater_.UpdateCommandEnabled(IDC_ZOOM_NORMAL, true);
2238 command_updater_.UpdateCommandEnabled(IDC_ZOOM_MINUS, true);
[email protected]84214982008-12-10 18:49:102239
[email protected]57c6a652009-05-04 07:58:342240 // Show various bits of UI
2241 command_updater_.UpdateCommandEnabled(IDC_JS_CONSOLE, true);
2242 command_updater_.UpdateCommandEnabled(IDC_CREATE_SHORTCUTS,
2243 !current_tab->GetFavIcon().isNull());
initial.commit09911bf2008-07-26 23:55:292244}
2245
[email protected]9282cea2009-02-18 18:49:002246void Browser::UpdateCommandsForFullscreenMode(bool is_fullscreen) {
2247 const bool show_main_ui = (type() == TYPE_NORMAL) && !is_fullscreen;
2248
2249 // Navigation commands
2250 command_updater_.UpdateCommandEnabled(IDC_OPEN_CURRENT_URL, show_main_ui);
2251
2252 // Window management commands
2253 command_updater_.UpdateCommandEnabled(IDC_PROFILE_MENU, show_main_ui);
2254 command_updater_.UpdateCommandEnabled(IDC_SHOW_AS_TAB,
[email protected]d5fbc002009-02-27 22:12:582255 (type() & TYPE_POPUP) && !is_fullscreen);
[email protected]9282cea2009-02-18 18:49:002256
2257 // Focus various bits of UI
2258 command_updater_.UpdateCommandEnabled(IDC_FOCUS_TOOLBAR, show_main_ui);
2259 command_updater_.UpdateCommandEnabled(IDC_FOCUS_LOCATION, show_main_ui);
2260 command_updater_.UpdateCommandEnabled(IDC_FOCUS_SEARCH, show_main_ui);
2261
2262 // Show various bits of UI
2263 command_updater_.UpdateCommandEnabled(IDC_DEVELOPER_MENU, show_main_ui);
[email protected]9282cea2009-02-18 18:49:002264 command_updater_.UpdateCommandEnabled(IDC_NEW_PROFILE, show_main_ui);
2265 command_updater_.UpdateCommandEnabled(IDC_REPORT_BUG, show_main_ui);
2266 command_updater_.UpdateCommandEnabled(IDC_SHOW_BOOKMARK_BAR, show_main_ui);
[email protected]9282cea2009-02-18 18:49:002267 command_updater_.UpdateCommandEnabled(IDC_IMPORT_SETTINGS, show_main_ui);
2268 command_updater_.UpdateCommandEnabled(IDC_OPTIONS, show_main_ui);
2269 command_updater_.UpdateCommandEnabled(IDC_EDIT_SEARCH_ENGINES, show_main_ui);
2270 command_updater_.UpdateCommandEnabled(IDC_VIEW_PASSWORDS, show_main_ui);
2271 command_updater_.UpdateCommandEnabled(IDC_ABOUT, show_main_ui);
2272}
2273
[email protected]c3989812009-04-15 18:08:492274void Browser::UpdateStopGoState(bool is_loading, bool force) {
2275 window_->UpdateStopGoState(is_loading, force);
[email protected]1fc025202009-01-20 23:03:142276 command_updater_.UpdateCommandEnabled(IDC_GO, !is_loading);
2277 command_updater_.UpdateCommandEnabled(IDC_STOP, is_loading);
[email protected]64ff7942008-12-17 18:11:232278}
2279
[email protected]d938aed92009-01-22 19:49:332280
[email protected]36b6dcb2008-11-12 01:19:572281///////////////////////////////////////////////////////////////////////////////
2282// Browser, UI update coalescing and handling (private):
2283
2284void Browser::UpdateToolbar(bool should_restore_state) {
2285 window_->UpdateToolbar(GetSelectedTabContents(), should_restore_state);
initial.commit09911bf2008-07-26 23:55:292286}
2287
[email protected]36b6dcb2008-11-12 01:19:572288void Browser::ScheduleUIUpdate(const TabContents* source,
2289 unsigned changed_flags) {
[email protected]2b4355c2009-04-04 17:55:462290 // Do some synchronous updates.
[email protected]36b6dcb2008-11-12 01:19:572291 if (changed_flags & TabContents::INVALIDATE_URL &&
2292 source == GetSelectedTabContents()) {
2293 // Only update the URL for the current tab. Note that we do not update
2294 // the navigation commands since those would have already been updated
2295 // synchronously by NavigationStateChanged.
2296 UpdateToolbar(false);
[email protected]36b6dcb2008-11-12 01:19:572297 }
[email protected]2b4355c2009-04-04 17:55:462298 if (changed_flags & TabContents::INVALIDATE_LOAD && source) {
2299 // Update the loading state synchronously. This is so the throbber will
2300 // immediately start/stop, which gives a more snappy feel. We want to do
2301 // this for any tab so they start & stop quickly, but the source can be
2302 // NULL, so we have to check for that.
2303 tabstrip_model_.UpdateTabContentsStateAt(
[email protected]902cdf772009-05-06 15:08:122304 tabstrip_model_.GetIndexOfController(&source->controller()), true);
[email protected]2b4355c2009-04-04 17:55:462305 }
2306
2307 // If the only updates were synchronously handled above, we're done.
2308 if (changed_flags ==
2309 (TabContents::INVALIDATE_URL | TabContents::INVALIDATE_LOAD))
2310 return;
[email protected]36b6dcb2008-11-12 01:19:572311
2312 // Save the dirty bits.
2313 scheduled_updates_.push_back(UIUpdate(source, changed_flags));
2314
2315 if (chrome_updater_factory_.empty()) {
2316 // No task currently scheduled, start another.
2317 MessageLoop::current()->PostDelayedTask(FROM_HERE,
2318 chrome_updater_factory_.NewRunnableMethod(
2319 &Browser::ProcessPendingUIUpdates),
2320 kUIUpdateCoalescingTimeMS);
2321 }
2322}
2323
2324void Browser::ProcessPendingUIUpdates() {
2325#ifndef NDEBUG
2326 // Validate that all tabs we have pending updates for exist. This is scary
2327 // because the pending list must be kept in sync with any detached or
2328 // deleted tabs. This code does not dereference any TabContents pointers.
2329 for (size_t i = 0; i < scheduled_updates_.size(); i++) {
2330 bool found = false;
2331 for (int tab = 0; tab < tab_count(); tab++) {
[email protected]ce3fa3c2009-04-20 19:55:572332 if (&GetTabContentsAt(tab)->controller() ==
2333 &scheduled_updates_[i].source->controller()) {
[email protected]36b6dcb2008-11-12 01:19:572334 found = true;
2335 break;
2336 }
2337 }
2338 DCHECK(found);
2339 }
2340#endif
2341
2342 chrome_updater_factory_.RevokeAll();
2343
[email protected]2d46c842008-11-14 19:24:312344 // We could have many updates for the same thing in the queue. This map
2345 // tracks the bits of the stuff we've already updated for each TabContents so
2346 // we don't update again.
[email protected]36b6dcb2008-11-12 01:19:572347 typedef std::map<const TabContents*, unsigned> UpdateTracker;
2348 UpdateTracker updated_stuff;
2349
2350 for (size_t i = 0; i < scheduled_updates_.size(); i++) {
2351 // Do not dereference |contents|, it may be out-of-date!
2352 const TabContents* contents = scheduled_updates_[i].source;
2353 unsigned flags = scheduled_updates_[i].changed_flags;
2354
2355 // Remove any bits we have already updated, and save the new bits.
2356 UpdateTracker::iterator updated = updated_stuff.find(contents);
2357 if (updated != updated_stuff.end()) {
2358 // Turn off bits already set.
2359 flags &= ~updated->second;
2360 if (!flags)
2361 continue;
2362
2363 updated->second |= flags;
2364 } else {
2365 updated_stuff[contents] = flags;
2366 }
2367
[email protected]f7f3a5f2009-05-01 22:02:342368 if (flags & TabContents::INVALIDATE_PAGE_ACTIONS)
2369 window()->GetLocationBar()->UpdatePageActions();
2370
[email protected]36b6dcb2008-11-12 01:19:572371 // Updating the URL happens synchronously in ScheduleUIUpdate.
[email protected]ba8c48212009-05-12 21:20:402372 TabContents* selected_tab = GetSelectedTabContents();
[email protected]4d34e2e2009-05-26 22:55:282373 if (selected_tab &&
2374 flags & TabContents::INVALIDATE_LOAD && GetStatusBubble()) {
[email protected]ba8c48212009-05-12 21:20:402375 GetStatusBubble()->SetStatus(selected_tab->GetStatusText());
[email protected]4d34e2e2009-05-26 22:55:282376 }
[email protected]36b6dcb2008-11-12 01:19:572377
[email protected]c9cd2222009-05-06 05:16:502378 if (flags & TabContents::INVALIDATE_TAB) {
[email protected]36b6dcb2008-11-12 01:19:572379 tabstrip_model_.UpdateTabContentsStateAt(
[email protected]902cdf772009-05-06 15:08:122380 tabstrip_model_.GetIndexOfController(&contents->controller()), false);
[email protected]36b6dcb2008-11-12 01:19:572381 window_->UpdateTitleBar();
2382
[email protected]ba8c48212009-05-12 21:20:402383 if (selected_tab && contents == selected_tab) {
[email protected]1fc025202009-01-20 23:03:142384 command_updater_.UpdateCommandEnabled(IDC_CREATE_SHORTCUTS,
[email protected]ba8c48212009-05-12 21:20:402385 !selected_tab->GetFavIcon().isNull());
[email protected]36b6dcb2008-11-12 01:19:572386 }
2387 }
2388
2389 // We don't need to process INVALIDATE_STATE, since that's not visible.
2390 }
2391
2392 scheduled_updates_.clear();
2393}
2394
2395void Browser::RemoveScheduledUpdatesFor(TabContents* contents) {
2396 if (!contents)
2397 return;
2398
2399 // Remove any pending UI updates for the detached tab.
2400 UpdateVector::iterator cur_update = scheduled_updates_.begin();
2401 while (cur_update != scheduled_updates_.end()) {
2402 if (cur_update->source == contents) {
2403 cur_update = scheduled_updates_.erase(cur_update);
2404 } else {
2405 ++cur_update;
initial.commit09911bf2008-07-26 23:55:292406 }
2407 }
2408}
2409
[email protected]d938aed92009-01-22 19:49:332410
[email protected]36b6dcb2008-11-12 01:19:572411///////////////////////////////////////////////////////////////////////////////
2412// Browser, Getters for UI (private):
initial.commit09911bf2008-07-26 23:55:292413
[email protected]36b6dcb2008-11-12 01:19:572414StatusBubble* Browser::GetStatusBubble() {
2415 return window_->GetStatusBubble();
initial.commit09911bf2008-07-26 23:55:292416}
2417
[email protected]36b6dcb2008-11-12 01:19:572418///////////////////////////////////////////////////////////////////////////////
2419// Browser, Session restore functions (private):
initial.commit09911bf2008-07-26 23:55:292420
2421void Browser::SyncHistoryWithTabs(int index) {
2422 if (!profile()->HasSessionService())
2423 return;
2424 SessionService* session_service = profile()->GetSessionService();
2425 if (session_service) {
2426 for (int i = index; i < tab_count(); ++i) {
2427 TabContents* contents = GetTabContentsAt(i);
2428 if (contents) {
2429 session_service->SetTabIndexInWindow(
[email protected]ce3fa3c2009-04-20 19:55:572430 session_id(), contents->controller().session_id(), i);
initial.commit09911bf2008-07-26 23:55:292431 }
2432 }
2433 }
2434}
2435
[email protected]ce3fa3c2009-04-20 19:55:572436TabContents* Browser::BuildRestoredTab(
[email protected]36b6dcb2008-11-12 01:19:572437 const std::vector<TabNavigation>& navigations,
2438 int selected_navigation) {
2439 if (!navigations.empty()) {
2440 DCHECK(selected_navigation >= 0 &&
2441 selected_navigation < static_cast<int>(navigations.size()));
[email protected]36b6dcb2008-11-12 01:19:572442 // Create a NavigationController. This constructor creates the appropriate
2443 // set of TabContents.
[email protected]57c6a652009-05-04 07:58:342444 TabContents* new_tab = new TabContents(profile_, NULL,
[email protected]ce3fa3c2009-04-20 19:55:572445 MSG_ROUTING_NONE, NULL);
2446 new_tab->controller().RestoreFromState(navigations, selected_navigation);
2447 return new_tab;
[email protected]36b6dcb2008-11-12 01:19:572448 } else {
2449 // No navigations. Create a tab with about:blank.
[email protected]ce3fa3c2009-04-20 19:55:572450 return CreateTabContentsForURL(GURL("about:blank"), GURL(), profile_,
2451 PageTransition::START_PAGE, false, NULL);
initial.commit09911bf2008-07-26 23:55:292452 }
2453}
2454
[email protected]36b6dcb2008-11-12 01:19:572455///////////////////////////////////////////////////////////////////////////////
2456// Browser, OnBeforeUnload handling (private):
initial.commit09911bf2008-07-26 23:55:292457
[email protected]04b4a6c2008-08-02 00:44:472458void Browser::ProcessPendingTabs() {
2459 DCHECK(is_attempting_to_close_browser_);
initial.commit09911bf2008-07-26 23:55:292460
[email protected]04b4a6c2008-08-02 00:44:472461 if (HasCompletedUnloadProcessing()) {
2462 // We've finished all the unload events and can proceed to close the
2463 // browser.
2464 OnWindowClosing();
initial.commit09911bf2008-07-26 23:55:292465 return;
2466 }
2467
[email protected]04b4a6c2008-08-02 00:44:472468 // Process beforeunload tabs first. When that queue is empty, process
2469 // unload tabs.
[email protected]04b4a6c2008-08-02 00:44:472470 if (!tabs_needing_before_unload_fired_.empty()) {
[email protected]06b42f032008-12-03 18:43:052471 TabContents* tab = *(tabs_needing_before_unload_fired_.begin());
[email protected]57c6a652009-05-04 07:58:342472 tab->render_view_host()->FirePageBeforeUnload();
[email protected]04b4a6c2008-08-02 00:44:472473 } else if (!tabs_needing_unload_fired_.empty()) {
initial.commit09911bf2008-07-26 23:55:292474 // We've finished firing all beforeunload events and can proceed with unload
2475 // events.
2476 // TODO(ojan): We should add a call to browser_shutdown::OnShutdownStarting
2477 // somewhere around here so that we have accurate measurements of shutdown
2478 // time.
[email protected]04b4a6c2008-08-02 00:44:472479 // TODO(ojan): We can probably fire all the unload events in parallel and
2480 // get a perf benefit from that in the cases where the tab hangs in it's
2481 // unload handler or takes a long time to page in.
[email protected]06b42f032008-12-03 18:43:052482 TabContents* tab = *(tabs_needing_unload_fired_.begin());
[email protected]57c6a652009-05-04 07:58:342483 tab->render_view_host()->FirePageUnload();
initial.commit09911bf2008-07-26 23:55:292484 } else {
[email protected]04b4a6c2008-08-02 00:44:472485 NOTREACHED();
initial.commit09911bf2008-07-26 23:55:292486 }
2487}
2488
[email protected]d043c2cc2009-03-25 18:30:452489bool Browser::HasCompletedUnloadProcessing() const {
[email protected]04b4a6c2008-08-02 00:44:472490 return is_attempting_to_close_browser_ &&
2491 tabs_needing_before_unload_fired_.empty() &&
2492 tabs_needing_unload_fired_.empty();
2493}
2494
2495void Browser::CancelWindowClose() {
2496 DCHECK(is_attempting_to_close_browser_);
2497 // Only cancelling beforeunload should be able to cancel the window's close.
2498 // So there had better be a tab that we think needs beforeunload fired.
2499 DCHECK(!tabs_needing_before_unload_fired_.empty());
2500
[email protected]8f673f3a2008-08-05 22:34:282501 tabs_needing_before_unload_fired_.clear();
2502 tabs_needing_unload_fired_.clear();
[email protected]04b4a6c2008-08-02 00:44:472503 is_attempting_to_close_browser_ = false;
2504}
2505
[email protected]06b42f032008-12-03 18:43:052506bool Browser::RemoveFromSet(UnloadListenerSet* set, TabContents* tab) {
[email protected]04b4a6c2008-08-02 00:44:472507 DCHECK(is_attempting_to_close_browser_);
2508
[email protected]06b42f032008-12-03 18:43:052509 UnloadListenerSet::iterator iter = std::find(set->begin(), set->end(), tab);
2510 if (iter != set->end()) {
2511 set->erase(iter);
2512 return true;
[email protected]04b4a6c2008-08-02 00:44:472513 }
2514 return false;
2515}
initial.commit09911bf2008-07-26 23:55:292516
[email protected]36b6dcb2008-11-12 01:19:572517void Browser::ClearUnloadState(TabContents* tab) {
2518 DCHECK(is_attempting_to_close_browser_);
[email protected]06b42f032008-12-03 18:43:052519 RemoveFromSet(&tabs_needing_before_unload_fired_, tab);
2520 RemoveFromSet(&tabs_needing_unload_fired_, tab);
[email protected]36b6dcb2008-11-12 01:19:572521 ProcessPendingTabs();
initial.commit09911bf2008-07-26 23:55:292522}
2523
[email protected]f7454892009-01-29 19:24:212524
[email protected]36b6dcb2008-11-12 01:19:572525///////////////////////////////////////////////////////////////////////////////
[email protected]69444cc2009-04-09 20:40:062526// Browser, In-progress download termination handling (private):
2527
2528bool Browser::CanCloseWithInProgressDownloads() {
2529 if (cancel_download_confirmation_state_ != NOT_PROMPTED) {
2530 // This should probably not happen.
2531 DCHECK(cancel_download_confirmation_state_ != WAITING_FOR_RESPONSE);
2532 return true;
2533 }
2534
2535 // If there are no download in-progress, our job is done.
2536 DownloadManager* download_manager = profile_->GetDownloadManager();
2537 if (!download_manager || download_manager->in_progress_count() == 0)
2538 return true;
2539
2540 // Let's figure out if we are the last window for our profile.
2541 // Note that we cannot just use BrowserList::GetBrowserCount as browser
2542 // windows closing is delayed and the returned count might include windows
2543 // that are being closed.
2544 int count = 0;
2545 for (BrowserList::const_iterator iter = BrowserList::begin();
2546 iter != BrowserList::end(); ++iter) {
2547 // Don't count this browser window or any other in the process of closing.
2548 if (*iter == this || (*iter)->is_attempting_to_close_browser_)
2549 continue;
2550
2551 // We test the original profile, because an incognito browser window keeps
2552 // the original profile alive (and its DownloadManager).
2553 // We also need to test explicitly the profile directly so that 2 incognito
2554 // profiles count as a match.
2555 if ((*iter)->profile() == profile() ||
2556 (*iter)->profile()->GetOriginalProfile() == profile())
2557 count++;
2558 }
2559 if (count > 0)
2560 return true;
2561
2562 cancel_download_confirmation_state_ = WAITING_FOR_RESPONSE;
2563 window_->ConfirmBrowserCloseWithPendingDownloads();
2564
2565 // Return false so the browser does not close. We'll close if the user
2566 // confirms in the dialog.
2567 return false;
2568}
2569
2570///////////////////////////////////////////////////////////////////////////////
[email protected]36b6dcb2008-11-12 01:19:572571// Browser, Assorted utility functions (private):
initial.commit09911bf2008-07-26 23:55:292572
initial.commit09911bf2008-07-26 23:55:292573Browser* Browser::GetOrCreateTabbedBrowser() {
2574 Browser* browser = BrowserList::FindBrowserWithType(
[email protected]299dabd2008-11-19 02:27:162575 profile_, TYPE_NORMAL);
[email protected]15952e462008-11-14 00:29:052576 if (!browser)
2577 browser = Browser::Create(profile_);
initial.commit09911bf2008-07-26 23:55:292578 return browser;
2579}
2580
initial.commit09911bf2008-07-26 23:55:292581void Browser::BuildPopupWindow(TabContents* source,
2582 TabContents* new_contents,
2583 const gfx::Rect& initial_pos) {
[email protected]9f5b80a2009-04-08 01:26:072584 BuildPopupWindowHelper(source, new_contents, initial_pos,
2585 (type_ & TYPE_APP) ? TYPE_APP_POPUP : TYPE_POPUP,
2586 profile_, false);
2587}
2588
2589void Browser::BuildPopupWindowHelper(TabContents* source,
2590 TabContents* new_contents,
2591 const gfx::Rect& initial_pos,
2592 Browser::Type browser_type,
2593 Profile* profile,
2594 bool start_restored) {
2595 Browser* browser = new Browser(browser_type, profile);
[email protected]15952e462008-11-14 00:29:052596 browser->set_override_bounds(initial_pos);
[email protected]9f5b80a2009-04-08 01:26:072597
2598 if (start_restored)
2599 browser->set_maximized_state(MAXIMIZED_STATE_UNMAXIMIZED);
2600
[email protected]15952e462008-11-14 00:29:052601 browser->CreateBrowserWindow();
[email protected]6b2ee922009-04-30 20:40:532602 browser->tabstrip_model()->AppendTabContents(new_contents, true);
[email protected]2f69fb52008-12-12 18:50:392603 browser->window()->Show();
initial.commit09911bf2008-07-26 23:55:292604}
2605
[email protected]d043c2cc2009-03-25 18:30:452606GURL Browser::GetHomePage() const {
[email protected]15952e462008-11-14 00:29:052607 if (profile_->GetPrefs()->GetBoolean(prefs::kHomePageIsNewTabPage))
[email protected]b689fce72009-03-17 22:45:342608 return GURL(chrome::kChromeUINewTabURL);
[email protected]15952e462008-11-14 00:29:052609 GURL home_page = GURL(URLFixerUpper::FixupURL(
[email protected]a239c3f2009-02-17 22:13:192610 WideToUTF8(profile_->GetPrefs()->GetString(prefs::kHomePage)),
2611 std::string()));
[email protected]15952e462008-11-14 00:29:052612 if (!home_page.is_valid())
[email protected]b689fce72009-03-17 22:45:342613 return GURL(chrome::kChromeUINewTabURL);
[email protected]15952e462008-11-14 00:29:052614 return home_page;
[email protected]36b6dcb2008-11-12 01:19:572615}
initial.commit09911bf2008-07-26 23:55:292616
[email protected]4f3dc372009-02-24 00:10:292617void Browser::FindInPage(bool find_next, bool forward_direction) {
[email protected]4801ecc2009-04-05 04:52:582618 ShowFindBar();
[email protected]4f3dc372009-02-24 00:10:292619 if (find_next) {
[email protected]57c6a652009-05-04 07:58:342620 GetSelectedTabContents()->StartFinding(string16(),
[email protected]e491f1c2009-05-22 20:28:122621 forward_direction,
2622 false); // Not case sensitive.
[email protected]4f3dc372009-02-24 00:10:292623 }
[email protected]fbd77592008-11-12 20:50:272624}
[email protected]cb17f7f2009-02-06 18:14:482625
[email protected]36b6dcb2008-11-12 01:19:572626void Browser::CloseFrame() {
2627 window_->Close();
initial.commit09911bf2008-07-26 23:55:292628}
2629
2630// static
2631std::wstring Browser::ComputeApplicationNameFromURL(const GURL& url) {
2632 std::string t;
2633 t.append(url.host());
2634 t.append("_");
2635 t.append(url.path());
2636 return UTF8ToWide(t);
2637}
2638
2639// static
initial.commit09911bf2008-07-26 23:55:292640void Browser::RegisterAppPrefs(const std::wstring& app_name) {
2641 // A set of apps that we've already started.
2642 static std::set<std::wstring>* g_app_names = NULL;
2643
2644 if (!g_app_names)
2645 g_app_names = new std::set<std::wstring>;
2646
2647 // Only register once for each app name.
2648 if (g_app_names->find(app_name) != g_app_names->end())
2649 return;
2650 g_app_names->insert(app_name);
2651
2652 // We need to register the window position pref.
2653 std::wstring window_pref(prefs::kBrowserWindowPlacement);
2654 window_pref.append(L"_");
2655 window_pref.append(app_name);
2656 PrefService* prefs = g_browser_process->local_state();
2657 DCHECK(prefs);
2658
2659 prefs->RegisterDictionaryPref(window_pref.c_str());
2660}