blob: 8567bd0438b29450a94624f9e4e2fa72194880c7 [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]6289beb2009-06-06 10:04:157#include "app/animation.h"
[email protected]a92b8642009-05-05 23:38:568#include "app/l10n_util.h"
[email protected]8a53ee042009-01-21 16:41:339#include "base/command_line.h"
10#include "base/idle_timer.h"
11#include "base/logging.h"
12#include "base/string_util.h"
[email protected]b689fce72009-03-17 22:45:3413#include "base/thread.h"
[email protected]88d74942009-01-21 22:04:4414#include "chrome/app/chrome_dll_resource.h"
[email protected]a9afddb2009-02-12 17:49:4215#include "chrome/browser/bookmarks/bookmark_model.h"
[email protected]8a53ee042009-01-21 16:41:3316#include "chrome/browser/browser_list.h"
[email protected]5c238752009-06-13 10:29:0717#include "chrome/browser/browser_process.h"
[email protected]c61db1d2009-02-06 03:39:1818#include "chrome/browser/browser_shutdown.h"
[email protected]c98fe6f2009-02-25 20:33:2319#include "chrome/browser/browser_window.h"
[email protected]40d59ce52009-03-06 23:20:1420#include "chrome/browser/character_encoding.h"
[email protected]40ecc902009-03-16 13:42:4721#include "chrome/browser/debugger/devtools_manager.h"
[email protected]59560e0b2009-06-04 03:30:2222#include "chrome/browser/download/download_item_model.h"
[email protected]69444cc2009-04-09 20:40:0623#include "chrome/browser/download/download_manager.h"
[email protected]59560e0b2009-06-04 03:30:2224#include "chrome/browser/download/download_shelf.h"
25#include "chrome/browser/download/download_started_animation.h"
[email protected]4801ecc2009-04-05 04:52:5826#include "chrome/browser/find_bar.h"
27#include "chrome/browser/find_bar_controller.h"
[email protected]7745b822009-01-27 20:15:3528#include "chrome/browser/location_bar.h"
[email protected]d938aed92009-01-22 19:49:3329#include "chrome/browser/metrics/user_metrics.h"
[email protected]a239c3f2009-02-17 22:13:1930#include "chrome/browser/net/url_fixer_upper.h"
[email protected]0e3e3e32009-05-14 01:00:5331#include "chrome/browser/options_window.h"
[email protected]f7011fcb2009-01-28 21:54:3232#include "chrome/browser/profile.h"
[email protected]14e60c8d2009-06-29 03:56:5133#include "chrome/browser/renderer_host/site_instance.h"
[email protected]85e921fb82009-02-11 23:19:4434#include "chrome/browser/sessions/session_service.h"
[email protected]c61db1d2009-02-06 03:39:1835#include "chrome/browser/sessions/session_types.h"
[email protected]bd580a252009-02-12 01:16:3036#include "chrome/browser/sessions/tab_restore_service.h"
[email protected]abf6c7a2009-03-03 16:24:1037#include "chrome/browser/status_bubble.h"
[email protected]a165a052009-02-18 21:43:0038#include "chrome/browser/tab_contents/interstitial_page.h"
[email protected]c61db1d2009-02-06 03:39:1839#include "chrome/browser/tab_contents/navigation_controller.h"
40#include "chrome/browser/tab_contents/navigation_entry.h"
[email protected]57c6a652009-05-04 07:58:3441#include "chrome/browser/tab_contents/tab_contents.h"
[email protected]81af9392009-04-21 02:37:4542#include "chrome/browser/tab_contents/tab_contents_view.h"
[email protected]4d34e2e2009-05-26 22:55:2843#include "chrome/browser/window_sizer.h"
[email protected]d938aed92009-01-22 19:49:3344#include "chrome/common/chrome_constants.h"
45#include "chrome/common/chrome_switches.h"
[email protected]5b1a0e22009-05-26 19:00:5846#include "chrome/common/extensions/extension.h"
[email protected]bfd04a62009-02-01 18:16:5647#include "chrome/common/notification_service.h"
[email protected]d938aed92009-01-22 19:49:3348#include "chrome/common/page_transition_types.h"
[email protected]59560e0b2009-06-04 03:30:2249#include "chrome/common/platform_util.h"
[email protected]8a53ee042009-01-21 16:41:3350#include "chrome/common/pref_names.h"
51#include "chrome/common/pref_service.h"
[email protected]b689fce72009-03-17 22:45:3452#include "chrome/common/url_constants.h"
[email protected]026e34a2009-02-06 00:06:1253#ifdef CHROME_PERSONALIZATION
54#include "chrome/personalization/personalization.h"
55#endif
[email protected]a3e18c42009-03-04 23:36:0556#include "grit/chromium_strings.h"
57#include "grit/generated_resources.h"
58#include "grit/locale_settings.h"
[email protected]8a53ee042009-01-21 16:41:3359#include "net/base/cookie_monster.h"
60#include "net/base/cookie_policy.h"
[email protected]2bfd94d2009-04-29 20:32:0361#include "net/base/mime_util.h"
[email protected]8a53ee042009-01-21 16:41:3362#include "net/base/net_util.h"
63#include "net/base/registry_controlled_domain.h"
64#include "net/url_request/url_request_context.h"
[email protected]d938aed92009-01-22 19:49:3365#include "webkit/glue/window_open_disposition.h"
[email protected]8a53ee042009-01-21 16:41:3366
67#if defined(OS_WIN)
initial.commit09911bf2008-07-26 23:55:2968#include <windows.h>
69#include <shellapi.h>
70
[email protected]4a0765a2009-05-08 23:12:2571#include "app/win_util.h"
[email protected]36b6dcb2008-11-12 01:19:5772#include "chrome/browser/automation/ui_controls.h"
initial.commit09911bf2008-07-26 23:55:2973#include "chrome/browser/browser_process.h"
initial.commit09911bf2008-07-26 23:55:2974#include "chrome/browser/browser_url_handler.h"
75#include "chrome/browser/cert_store.h"
[email protected]37936ee2008-09-14 01:09:5076#include "chrome/browser/download/save_package.h"
[email protected]3b073b22009-01-16 03:29:0377#include "chrome/browser/ssl/ssl_error_info.h"
[email protected]36b6dcb2008-11-12 01:19:5778#include "chrome/browser/task_manager.h"
[email protected]f2530062008-12-03 23:52:0379#include "chrome/browser/user_data_manager.h"
initial.commit09911bf2008-07-26 23:55:2980#include "chrome/browser/view_ids.h"
initial.commit09911bf2008-07-26 23:55:2981#include "chrome/browser/views/location_bar_view.h"
[email protected]6dffde322009-02-18 03:47:4882#include "chrome/common/child_process_host.h"
[email protected]8a53ee042009-01-21 16:41:3383#endif // OS_WIN
[email protected]e1acf6f2008-10-27 20:43:3384
[email protected]33e5f442009-05-28 03:30:2785#if !defined(OS_MACOSX)
[email protected]7d3feb912009-05-15 20:37:4286#include "chrome/browser/dock_info.h"
87#endif
88
[email protected]8a53ee042009-01-21 16:41:3389using base::TimeDelta;
initial.commit09911bf2008-07-26 23:55:2990
91// How long we wait before updating the browser chrome while loading a page.
92static const int kUIUpdateCoalescingTimeMS = 200;
93
94// Idle time before helping prune memory consumption.
95static const int kBrowserReleaseMemoryInterval = 30; // In seconds.
96
[email protected]36b6dcb2008-11-12 01:19:5797///////////////////////////////////////////////////////////////////////////////
initial.commit09911bf2008-07-26 23:55:2998
[email protected]a436d922009-02-13 23:16:4299// A task to reduce the working set of the child processes that live on the IO
100// thread (i.e. plugins, workers).
101class ReduceChildProcessesWorkingSetTask : public Task {
initial.commit09911bf2008-07-26 23:55:29102 public:
103 virtual void Run() {
[email protected]8a53ee042009-01-21 16:41:33104#if defined(OS_WIN)
[email protected]6dffde322009-02-18 03:47:48105 for (ChildProcessHost::Iterator iter; !iter.Done(); ++iter)
106 iter->ReduceWorkingSet();
[email protected]8a53ee042009-01-21 16:41:33107#endif
initial.commit09911bf2008-07-26 23:55:29108 }
109};
110
111// A browser task to run when the user is not using the browser.
112// In our case, we're trying to be nice to the operating system and release
113// memory not in use.
[email protected]aeab57ea2008-08-28 20:50:12114class BrowserIdleTimer : public base::IdleTimer {
initial.commit09911bf2008-07-26 23:55:29115 public:
[email protected]aeab57ea2008-08-28 20:50:12116 BrowserIdleTimer()
117 : base::IdleTimer(TimeDelta::FromSeconds(kBrowserReleaseMemoryInterval),
118 false) {
initial.commit09911bf2008-07-26 23:55:29119 }
120
121 virtual void OnIdle() {
[email protected]8a53ee042009-01-21 16:41:33122#if defined(OS_WIN)
initial.commit09911bf2008-07-26 23:55:29123 // We're idle. Release browser and renderer unused pages.
124
125 // Handle the Browser.
[email protected]176aa482008-11-14 03:25:15126 base::Process process(GetCurrentProcess());
initial.commit09911bf2008-07-26 23:55:29127 process.ReduceWorkingSet();
128
129 // Handle the Renderer(s).
130 RenderProcessHost::iterator renderer_iter;
131 for (renderer_iter = RenderProcessHost::begin(); renderer_iter !=
[email protected]176aa482008-11-14 03:25:15132 RenderProcessHost::end(); renderer_iter++) {
133 base::Process process = renderer_iter->second->process();
initial.commit09911bf2008-07-26 23:55:29134 process.ReduceWorkingSet();
135 }
136
[email protected]a436d922009-02-13 23:16:42137 // Handle the child processe. We need to iterate through them on the IO
138 // thread because that thread manages the child process collection.
initial.commit09911bf2008-07-26 23:55:29139 g_browser_process->io_thread()->message_loop()->PostTask(FROM_HERE,
[email protected]a436d922009-02-13 23:16:42140 new ReduceChildProcessesWorkingSetTask());
[email protected]8a53ee042009-01-21 16:41:33141#endif
initial.commit09911bf2008-07-26 23:55:29142 }
143};
144
[email protected]36b6dcb2008-11-12 01:19:57145///////////////////////////////////////////////////////////////////////////////
initial.commit09911bf2008-07-26 23:55:29146
147struct Browser::UIUpdate {
148 UIUpdate(const TabContents* src, unsigned flags)
149 : source(src),
150 changed_flags(flags) {
151 }
152
153 // The source of the update.
154 const TabContents* source;
155
156 // What changed in the UI.
157 unsigned changed_flags;
158};
159
[email protected]505323e22009-01-24 02:47:58160namespace {
161
162// Returns true if the specified TabContents has unload listeners registered.
163bool TabHasUnloadListener(TabContents* contents) {
[email protected]57c6a652009-05-04 07:58:34164 return contents->notify_disconnection() &&
165 !contents->showing_interstitial_page() &&
166 !contents->render_view_host()->SuddenTerminationAllowed();
[email protected]505323e22009-01-24 02:47:58167}
168
169} // namespace
170
[email protected]36b6dcb2008-11-12 01:19:57171///////////////////////////////////////////////////////////////////////////////
172// Browser, Constructors, Creation, Showing:
initial.commit09911bf2008-07-26 23:55:29173
[email protected]299dabd2008-11-19 02:27:16174Browser::Browser(Type type, Profile* profile)
[email protected]15952e462008-11-14 00:29:05175 : type_(type),
176 profile_(profile),
[email protected]f3e99e32008-07-30 04:48:39177 window_(NULL),
initial.commit09911bf2008-07-26 23:55:29178 tabstrip_model_(this, profile),
[email protected]1fc025202009-01-20 23:03:14179 command_updater_(this),
initial.commit09911bf2008-07-26 23:55:29180 toolbar_model_(this),
[email protected]15952e462008-11-14 00:29:05181 chrome_updater_factory_(this),
182 is_attempting_to_close_browser_(false),
[email protected]69444cc2009-04-09 20:40:06183 cancel_download_confirmation_state_(NOT_PROMPTED),
[email protected]2e716622009-03-09 21:11:01184 maximized_state_(MAXIMIZED_STATE_DEFAULT),
[email protected]15952e462008-11-14 00:29:05185 method_factory_(this),
[email protected]ebdcf9742009-01-23 05:25:28186 idle_task_(new BrowserIdleTimer) {
initial.commit09911bf2008-07-26 23:55:29187 tabstrip_model_.AddObserver(this);
188
[email protected]0cb94102009-05-22 19:51:21189 registrar_.Add(this, NotificationType::SSL_VISIBLE_STATE_CHANGED,
190 NotificationService::AllSources());
191 registrar_.Add(this, NotificationType::EXTENSION_UNLOADED,
192 NotificationService::AllSources());
[email protected]e001d412009-06-26 20:53:25193 registrar_.Add(this, NotificationType::BROWSER_THEME_CHANGED,
194 NotificationService::AllSources());
initial.commit09911bf2008-07-26 23:55:29195
initial.commit09911bf2008-07-26 23:55:29196 InitCommandState();
197 BrowserList::AddBrowser(this);
198
199 encoding_auto_detect_.Init(prefs::kWebKitUsesUniversalDetector,
200 profile_->GetPrefs(), NULL);
201
202 // Trim browser memory on idle for low & medium memory models.
203 if (g_browser_process->memory_model() < BrowserProcess::HIGH_MEMORY_MODEL)
204 idle_task_->Start();
[email protected]80d96fa2009-06-10 22:34:51205
206 renderer_preferences_.can_accept_load_drops = (this->type() == TYPE_NORMAL);
initial.commit09911bf2008-07-26 23:55:29207}
208
209Browser::~Browser() {
210 // The tab strip should be empty at this point.
211 DCHECK(tabstrip_model_.empty());
212 tabstrip_model_.RemoveObserver(this);
213
214 BrowserList::RemoveBrowser(this);
215
[email protected]fbc947b2009-06-19 13:28:24216#if defined(OS_WIN) || defined(OS_LINUX)
initial.commit09911bf2008-07-26 23:55:29217 if (!BrowserList::HasBrowserWithProfile(profile_)) {
218 // We're the last browser window with this profile. We need to nuke the
219 // TabRestoreService, which will start the shutdown of the
220 // NavigationControllers and allow for proper shutdown. If we don't do this
221 // chrome won't shutdown cleanly, and may end up crashing when some
222 // thread tries to use the IO thread (or another thread) that is no longer
223 // valid.
[email protected]fbc947b2009-06-19 13:28:24224 // This isn't a valid assumption for Mac OS, as it stays running after
225 // the last browser has closed. The Mac equivalent is in its app
226 // controller.
initial.commit09911bf2008-07-26 23:55:29227 profile_->ResetTabRestoreService();
228 }
[email protected]fbc947b2009-06-19 13:28:24229#endif
initial.commit09911bf2008-07-26 23:55:29230
231 SessionService* session_service = profile_->GetSessionService();
232 if (session_service)
233 session_service->WindowClosed(session_id_);
234
[email protected]d8375fd2008-11-25 22:45:39235 TabRestoreService* tab_restore_service = profile()->GetTabRestoreService();
236 if (tab_restore_service)
237 tab_restore_service->BrowserClosed(this);
238
initial.commit09911bf2008-07-26 23:55:29239 if (profile_->IsOffTheRecord() &&
240 !BrowserList::IsOffTheRecordSessionActive()) {
[email protected]860f55492009-03-27 19:50:59241 // An off-the-record profile is no longer needed, this indirectly
242 // frees its cache and cookies.
243 profile_->GetOriginalProfile()->DestroyOffTheRecordProfile();
initial.commit09911bf2008-07-26 23:55:29244 }
245
246 // There may be pending file dialogs, we need to tell them that we've gone
247 // away so they don't try and call back to us.
248 if (select_file_dialog_.get())
249 select_file_dialog_->ListenerDestroyed();
250}
251
[email protected]15952e462008-11-14 00:29:05252// static
253Browser* Browser::Create(Profile* profile) {
[email protected]299dabd2008-11-19 02:27:16254 Browser* browser = new Browser(TYPE_NORMAL, profile);
[email protected]15952e462008-11-14 00:29:05255 browser->CreateBrowserWindow();
256 return browser;
257}
[email protected]6104acf2008-11-11 22:27:34258
[email protected]15952e462008-11-14 00:29:05259// static
260Browser* Browser::CreateForPopup(Profile* profile) {
[email protected]299dabd2008-11-19 02:27:16261 Browser* browser = new Browser(TYPE_POPUP, profile);
[email protected]15952e462008-11-14 00:29:05262 browser->CreateBrowserWindow();
263 return browser;
264}
265
266// static
267Browser* Browser::CreateForApp(const std::wstring& app_name,
[email protected]d5fbc002009-02-27 22:12:58268 Profile* profile, bool is_popup) {
269 Browser* browser = new Browser(is_popup? TYPE_APP_POPUP : TYPE_APP, profile);
[email protected]15952e462008-11-14 00:29:05270 browser->app_name_ = app_name;
271 browser->CreateBrowserWindow();
272 return browser;
273}
274
275void Browser::CreateBrowserWindow() {
276 DCHECK(!window_);
277 window_ = BrowserWindow::CreateBrowserWindow(this);
278
279 // Show the First Run information bubble if we've been told to.
280 PrefService* local_state = g_browser_process->local_state();
[email protected]be3877f2009-01-14 15:51:10281 if (!local_state)
282 return;
[email protected]15952e462008-11-14 00:29:05283 if (local_state->IsPrefRegistered(prefs::kShouldShowFirstRunBubble) &&
284 local_state->GetBoolean(prefs::kShouldShowFirstRunBubble)) {
[email protected]b1390d02009-05-19 23:50:37285 bool show_OEM_bubble = (local_state->
286 IsPrefRegistered(prefs::kShouldUseOEMFirstRunBubble) &&
287 local_state->GetBoolean(prefs::kShouldUseOEMFirstRunBubble));
[email protected]15952e462008-11-14 00:29:05288 // Reset the preference so we don't show the bubble for subsequent windows.
289 local_state->ClearPref(prefs::kShouldShowFirstRunBubble);
[email protected]b1390d02009-05-19 23:50:37290 window_->GetLocationBar()->ShowFirstRunBubble(show_OEM_bubble);
initial.commit09911bf2008-07-26 23:55:29291 }
[email protected]4801ecc2009-04-05 04:52:58292
[email protected]d87301172009-05-31 04:28:18293#if !(defined(OS_LINUX) && defined(TOOLKIT_VIEWS))
[email protected]4801ecc2009-04-05 04:52:58294 FindBar* find_bar = BrowserWindow::CreateFindBar(this);
295 find_bar_controller_.reset(new FindBarController(find_bar));
296 find_bar->SetFindBarController(find_bar_controller_.get());
[email protected]21230ca2009-05-30 08:27:29297#endif
initial.commit09911bf2008-07-26 23:55:29298}
299
[email protected]36b6dcb2008-11-12 01:19:57300///////////////////////////////////////////////////////////////////////////////
[email protected]5c238752009-06-13 10:29:07301// Getters & Setters
302
303const std::vector<std::wstring>& Browser::user_data_dir_profiles() const {
304 return g_browser_process->user_data_dir_profiles();
305}
306
307void Browser::set_user_data_dir_profiles(
308 const std::vector<std::wstring>& profiles) {
309 g_browser_process->user_data_dir_profiles() = profiles;
310}
311
312///////////////////////////////////////////////////////////////////////////////
[email protected]36b6dcb2008-11-12 01:19:57313// Browser, Creation Helpers:
314
315// static
[email protected]15952e462008-11-14 00:29:05316void Browser::OpenEmptyWindow(Profile* profile) {
317 Browser* browser = Browser::Create(profile);
[email protected]36b6dcb2008-11-12 01:19:57318 browser->AddBlankTab(true);
[email protected]15952e462008-11-14 00:29:05319 browser->window()->Show();
initial.commit09911bf2008-07-26 23:55:29320}
321
[email protected]36b6dcb2008-11-12 01:19:57322// static
[email protected]fbc947b2009-06-19 13:28:24323void Browser::OpenWindowWithRestoredTabs(Profile* profile) {
324 TabRestoreService* service = profile->GetTabRestoreService();
325 if (service)
326 service->RestoreMostRecentEntry(NULL);
327}
328
329// static
[email protected]36b6dcb2008-11-12 01:19:57330void Browser::OpenURLOffTheRecord(Profile* profile, const GURL& url) {
331 Profile* off_the_record_profile = profile->GetOffTheRecordProfile();
332 Browser* browser = BrowserList::FindBrowserWithType(
[email protected]15952e462008-11-14 00:29:05333 off_the_record_profile,
[email protected]299dabd2008-11-19 02:27:16334 TYPE_NORMAL);
[email protected]15952e462008-11-14 00:29:05335 if (!browser)
336 browser = Browser::Create(off_the_record_profile);
[email protected]36b6dcb2008-11-12 01:19:57337 // TODO(eroman): should we have referrer here?
[email protected]5a4940be2009-05-06 06:44:39338 browser->AddTabWithURL(url, GURL(), PageTransition::LINK, true, -1, false,
339 NULL);
[email protected]15952e462008-11-14 00:29:05340 browser->window()->Show();
[email protected]2baf83d2008-07-30 05:58:17341}
342
[email protected]36b6dcb2008-11-12 01:19:57343// static
[email protected]0303f31c2009-02-02 06:42:05344void Browser::OpenApplicationWindow(Profile* profile, const GURL& url) {
345 std::wstring app_name = ComputeApplicationNameFromURL(url);
[email protected]36b6dcb2008-11-12 01:19:57346 RegisterAppPrefs(app_name);
[email protected]15952e462008-11-14 00:29:05347
[email protected]d5fbc002009-02-27 22:12:58348 Browser* browser = Browser::CreateForApp(app_name, profile, false);
[email protected]22735af62009-04-07 21:09:58349 browser->AddTabWithURL(url, GURL(), PageTransition::START_PAGE, true, -1,
[email protected]5a4940be2009-05-06 06:44:39350 false, NULL);
[email protected]80d96fa2009-06-10 22:34:51351 browser->GetSelectedTabContents()->render_view_host()->SetRendererPrefs(
352 browser->GetSelectedTabContents()->delegate()->GetRendererPrefs());
[email protected]15952e462008-11-14 00:29:05353 browser->window()->Show();
[email protected]68f009f2009-02-26 19:43:35354 // TODO(jcampan): http://crbug.com/8123 we should not need to set the initial
355 // focus explicitly.
[email protected]57c6a652009-05-04 07:58:34356 browser->GetSelectedTabContents()->view()->SetInitialFocus();
[email protected]d6a3c772009-01-27 19:41:20357}
initial.commit09911bf2008-07-26 23:55:29358
[email protected]36b6dcb2008-11-12 01:19:57359///////////////////////////////////////////////////////////////////////////////
[email protected]36b6dcb2008-11-12 01:19:57360// Browser, State Storage and Retrieval for UI:
361
[email protected]bc9a5152008-11-15 00:32:04362std::wstring Browser::GetWindowPlacementKey() const {
[email protected]36b6dcb2008-11-12 01:19:57363 std::wstring name(prefs::kBrowserWindowPlacement);
364 if (!app_name_.empty()) {
365 name.append(L"_");
366 name.append(app_name_);
367 }
[email protected]bc9a5152008-11-15 00:32:04368 return name;
369}
[email protected]36b6dcb2008-11-12 01:19:57370
[email protected]bc9a5152008-11-15 00:32:04371bool Browser::ShouldSaveWindowPlacement() const {
372 // We don't save window position for popups.
[email protected]d5fbc002009-02-27 22:12:58373 return (type() & TYPE_POPUP) == 0;
[email protected]bc9a5152008-11-15 00:32:04374}
[email protected]36b6dcb2008-11-12 01:19:57375
[email protected]bc9a5152008-11-15 00:32:04376void Browser::SaveWindowPlacement(const gfx::Rect& bounds, bool maximized) {
377 // Save to the session storage service, used when reloading a past session.
378 // Note that we don't want to be the ones who cause lazy initialization of
379 // the session service. This function gets called during initial window
380 // showing, and we don't want to bring in the session service this early.
[email protected]36b6dcb2008-11-12 01:19:57381 if (profile()->HasSessionService()) {
382 SessionService* session_service = profile()->GetSessionService();
383 if (session_service)
384 session_service->SetWindowBounds(session_id_, bounds, maximized);
385 }
386}
387
[email protected]15952e462008-11-14 00:29:05388gfx::Rect Browser::GetSavedWindowBounds() const {
[email protected]bb975362009-01-21 01:00:22389 const CommandLine& parsed_command_line = *CommandLine::ForCurrentProcess();
[email protected]15952e462008-11-14 00:29:05390 bool record_mode = parsed_command_line.HasSwitch(switches::kRecordMode);
391 bool playback_mode = parsed_command_line.HasSwitch(switches::kPlaybackMode);
392 if (record_mode || playback_mode) {
393 // In playback/record mode we always fix the size of the browser and
394 // move it to (0,0). The reason for this is two reasons: First we want
395 // resize/moves in the playback to still work, and Second we want
396 // playbacks to work (as much as possible) on machines w/ different
397 // screen sizes.
398 return gfx::Rect(0, 0, 800, 600);
399 }
400
401 gfx::Rect restored_bounds = override_bounds_;
402 bool maximized;
[email protected]6dfed102009-04-28 03:09:53403 WindowSizer::GetBrowserWindowBounds(app_name_, restored_bounds, NULL,
[email protected]15952e462008-11-14 00:29:05404 &restored_bounds, &maximized);
405 return restored_bounds;
406}
407
408// TODO(beng): obtain maximized state some other way so we don't need to go
409// through all this hassle.
410bool Browser::GetSavedMaximizedState() const {
[email protected]bb975362009-01-21 01:00:22411 if (CommandLine::ForCurrentProcess()->HasSwitch(switches::kStartMaximized))
[email protected]15952e462008-11-14 00:29:05412 return true;
413
[email protected]2e716622009-03-09 21:11:01414 if (maximized_state_ == MAXIMIZED_STATE_MAXIMIZED)
415 return true;
416 if (maximized_state_ == MAXIMIZED_STATE_UNMAXIMIZED)
417 return false;
418
419 // An explicit maximized state was not set. Query the window sizer.
[email protected]15952e462008-11-14 00:29:05420 gfx::Rect restored_bounds;
[email protected]2e716622009-03-09 21:11:01421 bool maximized = false;
[email protected]6dfed102009-04-28 03:09:53422 WindowSizer::GetBrowserWindowBounds(app_name_, restored_bounds, NULL,
[email protected]15952e462008-11-14 00:29:05423 &restored_bounds, &maximized);
424 return maximized;
[email protected]36b6dcb2008-11-12 01:19:57425}
426
427SkBitmap Browser::GetCurrentPageIcon() const {
[email protected]ce5348a82008-12-18 18:36:23428 TabContents* contents = GetSelectedTabContents();
429 // |contents| can be NULL since GetCurrentPageIcon() is called by the window
430 // during the window's creation (before tabs have been added).
431 return contents ? contents->GetFavIcon() : SkBitmap();
[email protected]36b6dcb2008-11-12 01:19:57432}
433
[email protected]731f8a42009-07-20 22:07:32434string16 Browser::GetWindowTitleForCurrentTab() const {
[email protected]36b6dcb2008-11-12 01:19:57435 TabContents* contents = tabstrip_model_.GetSelectedTabContents();
[email protected]dda5dfa32009-07-10 00:33:29436 string16 title;
[email protected]c7c42332008-11-15 01:10:54437
[email protected]731f8a42009-07-20 22:07:32438 // |contents| can be NULL because GetWindowTitleForCurrentTab is called by the
439 // window during the window's creation (before tabs have been added).
[email protected]36b6dcb2008-11-12 01:19:57440 if (contents) {
[email protected]dda5dfa32009-07-10 00:33:29441 title = contents->GetTitle();
[email protected]36b6dcb2008-11-12 01:19:57442 FormatTitleForDisplay(&title);
443 }
444 if (title.empty())
[email protected]dda5dfa32009-07-10 00:33:29445 title = l10n_util::GetStringUTF16(IDS_TAB_UNTITLED_TITLE);
[email protected]36b6dcb2008-11-12 01:19:57446
[email protected]16779842009-07-08 23:45:29447#if defined(OS_MACOSX) || defined(OS_CHROMEOS)
[email protected]d904bc82009-07-07 00:41:04448 // On Mac, we don't want to suffix the page title with the application name.
449 return title;
450#elif defined(OS_WIN) || defined(OS_LINUX)
[email protected]edb5e6a2009-04-08 23:46:17451 int string_id = IDS_BROWSER_WINDOW_TITLE_FORMAT;
452 // Don't append the app name to window titles when we're not displaying a
453 // distributor logo for the frame.
454 if (!ShouldShowDistributorLogo())
455 string_id = IDS_BROWSER_WINDOW_TITLE_FORMAT_NO_LOGO;
[email protected]dda5dfa32009-07-10 00:33:29456 return l10n_util::GetStringFUTF16(string_id, title);
[email protected]57e68dba2009-05-15 21:30:50457#endif
[email protected]36b6dcb2008-11-12 01:19:57458}
459
460// static
[email protected]dda5dfa32009-07-10 00:33:29461void Browser::FormatTitleForDisplay(string16* title) {
[email protected]36b6dcb2008-11-12 01:19:57462 size_t current_index = 0;
463 size_t match_index;
464 while ((match_index = title->find(L'\n', current_index)) !=
465 std::wstring::npos) {
[email protected]dda5dfa32009-07-10 00:33:29466 title->replace(match_index, 1, EmptyString16());
[email protected]36b6dcb2008-11-12 01:19:57467 current_index = match_index;
468 }
469}
470
[email protected]edb5e6a2009-04-08 23:46:17471bool Browser::ShouldShowDistributorLogo() const {
472 // Don't show the distributor logo on app frames and app popups.
473 return !(type_ & TYPE_APP);
474}
[email protected]c61db1d2009-02-06 03:39:18475
[email protected]36b6dcb2008-11-12 01:19:57476///////////////////////////////////////////////////////////////////////////////
477// Browser, OnBeforeUnload handling:
478
479bool Browser::ShouldCloseWindow() {
[email protected]69444cc2009-04-09 20:40:06480 if (!CanCloseWithInProgressDownloads())
481 return false;
482
483 if (HasCompletedUnloadProcessing())
[email protected]36b6dcb2008-11-12 01:19:57484 return true;
[email protected]69444cc2009-04-09 20:40:06485
[email protected]36b6dcb2008-11-12 01:19:57486 is_attempting_to_close_browser_ = true;
487
488 for (int i = 0; i < tab_count(); ++i) {
[email protected]505323e22009-01-24 02:47:58489 TabContents* contents = GetTabContentsAt(i);
490 if (TabHasUnloadListener(contents))
491 tabs_needing_before_unload_fired_.insert(contents);
[email protected]36b6dcb2008-11-12 01:19:57492 }
493
494 if (tabs_needing_before_unload_fired_.empty())
495 return true;
496
497 ProcessPendingTabs();
498 return false;
499}
500
501void Browser::OnWindowClosing() {
502 if (!ShouldCloseWindow())
503 return;
504
[email protected]a239c3f2009-02-17 22:13:19505#if defined(OS_WIN) || defined(OS_LINUX)
506 // We don't want to do this on Mac since closing all windows isn't a sign
507 // that the app is shutting down.
[email protected]36b6dcb2008-11-12 01:19:57508 if (BrowserList::size() == 1)
509 browser_shutdown::OnShutdownStarting(browser_shutdown::WINDOW_CLOSE);
[email protected]a239c3f2009-02-17 22:13:19510#endif
[email protected]36b6dcb2008-11-12 01:19:57511
512 // Don't use HasSessionService here, we want to force creation of the
513 // session service so that user can restore what was open.
514 SessionService* session_service = profile()->GetSessionService();
515 if (session_service)
516 session_service->WindowClosing(session_id());
517
[email protected]d8375fd2008-11-25 22:45:39518 TabRestoreService* tab_restore_service = profile()->GetTabRestoreService();
519 if (tab_restore_service)
520 tab_restore_service->BrowserClosing(this);
521
[email protected]36b6dcb2008-11-12 01:19:57522 CloseAllTabs();
523}
524
[email protected]69444cc2009-04-09 20:40:06525////////////////////////////////////////////////////////////////////////////////
526// In-progress download termination handling:
527
528void Browser::InProgressDownloadResponse(bool cancel_downloads) {
529 if (cancel_downloads) {
530 cancel_download_confirmation_state_ = RESPONSE_RECEIVED;
531 CloseWindow();
532 return;
533 }
534
535 // Sets the confirmation state to NOT_PROMPTED so that if the user tries to
536 // close again we'll show the warning again.
537 cancel_download_confirmation_state_ = NOT_PROMPTED;
538
539 // Show the download page so the user can figure-out what downloads are still
540 // in-progress.
541 ShowDownloadsTab();
542}
543
544
545////////////////////////////////////////////////////////////////////////////////
[email protected]36b6dcb2008-11-12 01:19:57546// Browser, Tab adding/showing functions:
547
548TabContents* Browser::AddTabWithURL(
549 const GURL& url, const GURL& referrer, PageTransition::Type transition,
[email protected]5a4940be2009-05-06 06:44:39550 bool foreground, int index, bool force_index,
551 SiteInstance* instance) {
[email protected]22735af62009-04-07 21:09:58552 TabContents* contents = NULL;
553 if (type_ == TYPE_NORMAL || tabstrip_model()->empty()) {
554 GURL url_to_load = url;
555 if (url_to_load.is_empty())
556 url_to_load = GetHomePage();
557 contents = CreateTabContentsForURL(url_to_load, referrer, profile_,
558 transition, false, instance);
[email protected]5a4940be2009-05-06 06:44:39559 tabstrip_model_.AddTabContents(contents, index, force_index,
560 transition, foreground);
[email protected]22735af62009-04-07 21:09:58561 // By default, content believes it is not hidden. When adding contents
562 // in the background, tell it that it's hidden.
563 if (!foreground)
564 contents->WasHidden();
565 } else {
566 // We're in an app window or a popup window. Find an existing browser to
567 // open this URL in, creating one if none exists.
568 Browser* b = GetOrCreateTabbedBrowser();
569 contents = b->AddTabWithURL(url, referrer, transition, foreground, index,
[email protected]5a4940be2009-05-06 06:44:39570 force_index, instance);
[email protected]22735af62009-04-07 21:09:58571 b->window()->Show();
[email protected]36b6dcb2008-11-12 01:19:57572 }
[email protected]36b6dcb2008-11-12 01:19:57573 return contents;
574}
575
[email protected]ce3fa3c2009-04-20 19:55:57576// TODO(brettw) this should be just AddTab and it should take a TabContents.
[email protected]36b6dcb2008-11-12 01:19:57577TabContents* Browser::AddTabWithNavigationController(
578 NavigationController* ctrl, PageTransition::Type type) {
[email protected]7f0005a2009-04-15 03:25:11579 TabContents* tc = ctrl->tab_contents();
[email protected]5a4940be2009-05-06 06:44:39580 tabstrip_model_.AddTabContents(tc, -1, false, type, true);
[email protected]36b6dcb2008-11-12 01:19:57581 return tc;
582}
583
[email protected]e0c7c262009-04-23 23:09:43584void Browser::AddTabContents(TabContents* new_contents,
585 WindowOpenDisposition disposition,
586 const gfx::Rect& initial_pos,
587 bool user_gesture) {
588 AddNewContents(NULL, new_contents, disposition, initial_pos, user_gesture);
589}
590
591void Browser::CloseTabContents(TabContents* contents) {
592 CloseContents(contents);
593}
594
595void Browser::BrowserShowHtmlDialog(HtmlDialogUIDelegate* delegate,
[email protected]322f3ff2009-05-22 16:19:54596 gfx::NativeWindow parent_window) {
[email protected]e0c7c262009-04-23 23:09:43597 ShowHtmlDialog(delegate, parent_window);
598}
599
600void Browser::BrowserRenderWidgetShowing() {
601 RenderWidgetShowing();
602}
603
604void Browser::ToolbarSizeChanged(bool is_animating) {
605 ToolbarSizeChanged(NULL, is_animating);
606}
607
[email protected]ce3fa3c2009-04-20 19:55:57608TabContents* Browser::AddRestoredTab(
[email protected]36b6dcb2008-11-12 01:19:57609 const std::vector<TabNavigation>& navigations,
610 int tab_index,
611 int selected_navigation,
[email protected]5c0e6482009-07-14 20:20:09612 bool select,
613 bool pin) {
[email protected]57c6a652009-05-04 07:58:34614 TabContents* new_tab = new TabContents(profile(), NULL,
[email protected]ce3fa3c2009-04-20 19:55:57615 MSG_ROUTING_NONE, NULL);
616 new_tab->controller().RestoreFromState(navigations, selected_navigation);
[email protected]36b6dcb2008-11-12 01:19:57617
[email protected]5c0e6482009-07-14 20:20:09618 bool really_pin =
619 (pin && tab_index == tabstrip_model()->IndexOfFirstNonPinnedTab());
[email protected]ce3fa3c2009-04-20 19:55:57620 tabstrip_model_.InsertTabContentsAt(tab_index, new_tab, select, false);
[email protected]5c0e6482009-07-14 20:20:09621 if (really_pin)
622 tabstrip_model_.SetTabPinned(tab_index, true);
[email protected]77bc6732009-04-20 22:01:03623 if (select)
624 window_->Activate();
[email protected]36b6dcb2008-11-12 01:19:57625 if (profile_->HasSessionService()) {
626 SessionService* session_service = profile_->GetSessionService();
627 if (session_service)
[email protected]5c0e6482009-07-14 20:20:09628 session_service->TabRestored(&new_tab->controller(), really_pin);
[email protected]36b6dcb2008-11-12 01:19:57629 }
[email protected]ce3fa3c2009-04-20 19:55:57630 return new_tab;
[email protected]36b6dcb2008-11-12 01:19:57631}
632
633void Browser::ReplaceRestoredTab(
634 const std::vector<TabNavigation>& navigations,
635 int selected_navigation) {
[email protected]57c6a652009-05-04 07:58:34636 TabContents* replacement = new TabContents(profile(), NULL,
[email protected]ce3fa3c2009-04-20 19:55:57637 MSG_ROUTING_NONE, NULL);
638 replacement->controller().RestoreFromState(navigations, selected_navigation);
[email protected]36b6dcb2008-11-12 01:19:57639
640 tabstrip_model_.ReplaceNavigationControllerAt(
641 tabstrip_model_.selected_index(),
[email protected]ce3fa3c2009-04-20 19:55:57642 &replacement->controller());
[email protected]36b6dcb2008-11-12 01:19:57643}
644
[email protected]a8eff102009-04-14 15:23:43645bool Browser::CanRestoreTab() {
646 TabRestoreService* service = profile_->GetTabRestoreService();
647 return service && !service->entries().empty();
648}
649
[email protected]7a5f33d2009-03-03 04:35:36650void Browser::ShowSingleDOMUITab(const GURL& url) {
[email protected]b689fce72009-03-17 22:45:34651 // See if we already have a tab with the given URL and select it if so.
652 for (int i = 0; i < tabstrip_model_.count(); i++) {
653 TabContents* tc = tabstrip_model_.GetTabContentsAt(i);
654 if (tc->GetURL() == url) {
[email protected]36b6dcb2008-11-12 01:19:57655 tabstrip_model_.SelectTabContentsAt(i, false);
656 return;
657 }
658 }
[email protected]b689fce72009-03-17 22:45:34659
660 // Otherwise, just create a new tab.
[email protected]5a4940be2009-05-06 06:44:39661 AddTabWithURL(url, GURL(), PageTransition::AUTO_BOOKMARK, true, -1,
662 false, NULL);
[email protected]36b6dcb2008-11-12 01:19:57663}
[email protected]d938aed92009-01-22 19:49:33664
[email protected]36b6dcb2008-11-12 01:19:57665///////////////////////////////////////////////////////////////////////////////
666// Browser, Assorted browser commands:
667
[email protected]485fba42009-03-24 23:27:29668void Browser::GoBack(WindowOpenDisposition disposition) {
[email protected]fbd77592008-11-12 20:50:27669 UserMetrics::RecordAction(L"Back", profile_);
670
[email protected]36b6dcb2008-11-12 01:19:57671 // If we are showing an interstitial, just hide it.
672 TabContents* current_tab = GetSelectedTabContents();
[email protected]57c6a652009-05-04 07:58:34673 if (current_tab->interstitial_page()) {
[email protected]a3a1d142008-12-19 00:42:30674 // The GoBack() case is a special case when an interstitial is shown because
675 // the "previous" page is still available, just hidden by the interstitial.
676 // We treat the back as a "Don't proceed", this hides the interstitial and
677 // reveals the previous page.
[email protected]57c6a652009-05-04 07:58:34678 current_tab->interstitial_page()->DontProceed();
[email protected]c7c42332008-11-15 01:10:54679 return;
[email protected]36b6dcb2008-11-12 01:19:57680 }
[email protected]485fba42009-03-24 23:27:29681
[email protected]ce3fa3c2009-04-20 19:55:57682 if (current_tab->controller().CanGoBack()) {
683 NavigationController* controller = NULL;
684 if (disposition == NEW_FOREGROUND_TAB ||
685 disposition == NEW_BACKGROUND_TAB) {
[email protected]90ba8dd2009-04-25 19:43:52686 TabContents* cloned = GetSelectedTabContents()->Clone();
[email protected]5a4940be2009-05-06 06:44:39687 tabstrip_model_.AddTabContents(cloned, -1, false,
[email protected]90ba8dd2009-04-25 19:43:52688 PageTransition::LINK,
689 disposition == NEW_FOREGROUND_TAB);
690 controller = &cloned->controller();
[email protected]485fba42009-03-24 23:27:29691 } else {
692 // Default disposition is CURRENT_TAB.
[email protected]ce3fa3c2009-04-20 19:55:57693 controller = &current_tab->controller();
[email protected]485fba42009-03-24 23:27:29694 }
695 controller->GoBack();
696 }
[email protected]36b6dcb2008-11-12 01:19:57697}
698
[email protected]485fba42009-03-24 23:27:29699void Browser::GoForward(WindowOpenDisposition disp) {
[email protected]ce3fa3c2009-04-20 19:55:57700 // TODO(brettw) this is mostly duplicated from GoBack, these should have a
701 // common backend or something.
[email protected]fbd77592008-11-12 20:50:27702 UserMetrics::RecordAction(L"Forward", profile_);
[email protected]ce3fa3c2009-04-20 19:55:57703 if (GetSelectedTabContents()->controller().CanGoForward()) {
[email protected]485fba42009-03-24 23:27:29704 NavigationController* controller = 0;
705 if (disp == NEW_FOREGROUND_TAB || disp == NEW_BACKGROUND_TAB) {
[email protected]90ba8dd2009-04-25 19:43:52706 TabContents* cloned = GetSelectedTabContents()->Clone();
[email protected]5a4940be2009-05-06 06:44:39707 tabstrip_model_.AddTabContents(cloned, -1, false,
[email protected]90ba8dd2009-04-25 19:43:52708 PageTransition::LINK,
709 disp == NEW_FOREGROUND_TAB);
710 controller = &cloned->controller();
[email protected]485fba42009-03-24 23:27:29711 } else {
712 // Default disposition is CURRENT_TAB.
[email protected]ce3fa3c2009-04-20 19:55:57713 controller = &GetSelectedTabContents()->controller();
[email protected]485fba42009-03-24 23:27:29714 }
715 controller->GoForward();
716 }
[email protected]36b6dcb2008-11-12 01:19:57717}
718
719void Browser::Reload() {
[email protected]fbd77592008-11-12 20:50:27720 UserMetrics::RecordAction(L"Reload", profile_);
721
[email protected]36b6dcb2008-11-12 01:19:57722 // If we are showing an interstitial, treat this as an OpenURL.
723 TabContents* current_tab = GetSelectedTabContents();
724 if (current_tab) {
[email protected]57c6a652009-05-04 07:58:34725 if (current_tab->showing_interstitial_page()) {
[email protected]ce3fa3c2009-04-20 19:55:57726 NavigationEntry* entry = current_tab->controller().GetActiveEntry();
[email protected]36b6dcb2008-11-12 01:19:57727 DCHECK(entry); // Should exist if interstitial is showing.
728 OpenURL(entry->url(), GURL(), CURRENT_TAB, PageTransition::RELOAD);
729 return;
730 }
[email protected]36b6dcb2008-11-12 01:19:57731
[email protected]0a4a3c12009-05-04 17:10:29732 // Forcibly reset the location bar, since otherwise it won't discard any
733 // ongoing user edits, since it doesn't realize this is a user-initiated
734 // action.
735 window_->GetLocationBar()->Revert();
736
[email protected]20142ba2009-05-04 16:58:47737 // As this is caused by a user action, give the focus to the page.
[email protected]36b6dcb2008-11-12 01:19:57738 current_tab->Focus();
[email protected]ce3fa3c2009-04-20 19:55:57739 current_tab->controller().Reload(true);
[email protected]36b6dcb2008-11-12 01:19:57740 }
741}
742
[email protected]485fba42009-03-24 23:27:29743void Browser::Home(WindowOpenDisposition disposition) {
[email protected]fbd77592008-11-12 20:50:27744 UserMetrics::RecordAction(L"Home", profile_);
[email protected]485fba42009-03-24 23:27:29745 OpenURL(GetHomePage(), GURL(), disposition, PageTransition::AUTO_BOOKMARK);
[email protected]36b6dcb2008-11-12 01:19:57746}
747
[email protected]fbd77592008-11-12 20:50:27748void Browser::OpenCurrentURL() {
749 UserMetrics::RecordAction(L"LoadURL", profile_);
[email protected]7745b822009-01-27 20:15:35750 LocationBar* location_bar = window_->GetLocationBar();
[email protected]1f7d7e92009-06-02 20:55:04751 OpenURLAtIndex(NULL, GURL(WideToUTF8(location_bar->GetInputString())), GURL(),
752 location_bar->GetWindowOpenDisposition(),
753 location_bar->GetPageTransition(), -1, true);
[email protected]fbd77592008-11-12 20:50:27754}
755
[email protected]485fba42009-03-24 23:27:29756void Browser::Go(WindowOpenDisposition disposition) {
[email protected]84214982008-12-10 18:49:10757 UserMetrics::RecordAction(L"Go", profile_);
[email protected]485fba42009-03-24 23:27:29758 window_->GetLocationBar()->AcceptInputWithDisposition(disposition);
[email protected]84214982008-12-10 18:49:10759}
760
761void Browser::Stop() {
762 UserMetrics::RecordAction(L"Stop", profile_);
[email protected]0daf94732008-12-17 01:08:33763 GetSelectedTabContents()->Stop();
[email protected]84214982008-12-10 18:49:10764}
765
766void Browser::NewWindow() {
767 UserMetrics::RecordAction(L"NewWindow", profile_);
768 Browser::OpenEmptyWindow(profile_->GetOriginalProfile());
769}
770
771void Browser::NewIncognitoWindow() {
772 UserMetrics::RecordAction(L"NewIncognitoWindow", profile_);
773 Browser::OpenEmptyWindow(profile_->GetOffTheRecordProfile());
774}
775
776void Browser::NewProfileWindowByIndex(int index) {
[email protected]d938aed92009-01-22 19:49:33777#if defined(OS_WIN)
[email protected]ac926362009-02-26 01:33:18778 const CommandLine& command_line = *CommandLine::ForCurrentProcess();
779 if (!command_line.HasSwitch(switches::kEnableUserDataDirProfiles))
780 return;
[email protected]84214982008-12-10 18:49:10781 UserMetrics::RecordAction(L"NewProfileWindowByIndex", profile_);
782 UserDataManager::Get()->LaunchChromeForProfile(index);
[email protected]d938aed92009-01-22 19:49:33783#endif
[email protected]84214982008-12-10 18:49:10784}
785
786void Browser::CloseWindow() {
787 UserMetrics::RecordAction(L"CloseWindow", profile_);
788 window_->Close();
789}
790
[email protected]fbd77592008-11-12 20:50:27791void Browser::NewTab() {
792 UserMetrics::RecordAction(L"NewTab", profile_);
[email protected]299dabd2008-11-19 02:27:16793 if (type() == TYPE_NORMAL) {
[email protected]fbd77592008-11-12 20:50:27794 AddBlankTab(true);
795 } else {
796 Browser* b = GetOrCreateTabbedBrowser();
[email protected]fbd77592008-11-12 20:50:27797 b->AddBlankTab(true);
[email protected]15952e462008-11-14 00:29:05798 b->window()->Show();
[email protected]e54f30d2009-01-14 21:17:11799 // The call to AddBlankTab above did not set the focus to the tab as its
800 // window was not active, so we have to do it explicitly.
801 // See http://crbug.com/6380.
[email protected]57c6a652009-05-04 07:58:34802 b->GetSelectedTabContents()->view()->RestoreFocus();
[email protected]fbd77592008-11-12 20:50:27803 }
804}
805
806void Browser::CloseTab() {
807 UserMetrics::RecordAction(L"CloseTab_Accelerator", profile_);
808 tabstrip_model_.CloseTabContentsAt(tabstrip_model_.selected_index());
809}
810
[email protected]fbd77592008-11-12 20:50:27811void Browser::SelectNextTab() {
812 UserMetrics::RecordAction(L"SelectNextTab", profile_);
813 tabstrip_model_.SelectNextTab();
814}
815
816void Browser::SelectPreviousTab() {
817 UserMetrics::RecordAction(L"SelectPrevTab", profile_);
818 tabstrip_model_.SelectPreviousTab();
819}
820
821void Browser::SelectNumberedTab(int index) {
822 if (index < tab_count()) {
823 UserMetrics::RecordAction(L"SelectNumberedTab", profile_);
824 tabstrip_model_.SelectTabContentsAt(index, true);
825 }
826}
827
828void Browser::SelectLastTab() {
829 UserMetrics::RecordAction(L"SelectLastTab", profile_);
830 tabstrip_model_.SelectLastTab();
831}
832
833void Browser::DuplicateTab() {
834 UserMetrics::RecordAction(L"Duplicate", profile_);
835 DuplicateContentsAt(selected_index());
836}
837
838void Browser::RestoreTab() {
839 UserMetrics::RecordAction(L"RestoreTab", profile_);
840 TabRestoreService* service = profile_->GetTabRestoreService();
841 if (!service)
842 return;
843
[email protected]d8375fd2008-11-25 22:45:39844 service->RestoreMostRecentEntry(this);
[email protected]fbd77592008-11-12 20:50:27845}
846
847void Browser::ConvertPopupToTabbedBrowser() {
848 UserMetrics::RecordAction(L"ShowAsTab", profile_);
[email protected]fbd77592008-11-12 20:50:27849 int tab_strip_index = tabstrip_model_.selected_index();
850 TabContents* contents = tabstrip_model_.DetachTabContentsAt(tab_strip_index);
[email protected]15952e462008-11-14 00:29:05851 Browser* browser = Browser::Create(profile_);
852 browser->tabstrip_model()->AppendTabContents(contents, true);
853 browser->window()->Show();
[email protected]fbd77592008-11-12 20:50:27854}
855
[email protected]9282cea2009-02-18 18:49:00856void Browser::ToggleFullscreenMode() {
857 UserMetrics::RecordAction(L"ToggleFullscreen", profile_);
858 window_->SetFullscreen(!window_->IsFullscreen());
859 UpdateCommandsForFullscreenMode(window_->IsFullscreen());
860}
861
[email protected]fbd77592008-11-12 20:50:27862void Browser::Exit() {
863 UserMetrics::RecordAction(L"Exit", profile_);
864 BrowserList::CloseAllBrowsers(true);
865}
866
[email protected]36b6dcb2008-11-12 01:19:57867void Browser::BookmarkCurrentPage() {
[email protected]fbd77592008-11-12 20:50:27868 UserMetrics::RecordAction(L"Star", profile_);
869
[email protected]b7ca4e62009-01-23 20:37:29870 TabContents* contents = GetSelectedTabContents();
[email protected]85408b7c2009-06-03 19:11:54871 if (!contents->ShouldDisplayURL())
872 return;
873 const GURL& url = contents->GetURL();
874 if (url.is_empty() || !url.is_valid())
875 return;
876 std::wstring title = UTF16ToWideHack(contents->GetTitle());
877
[email protected]b7ca4e62009-01-23 20:37:29878 BookmarkModel* model = contents->profile()->GetBookmarkModel();
[email protected]36b6dcb2008-11-12 01:19:57879 if (!model || !model->IsLoaded())
880 return; // Ignore requests until bookmarks are loaded.
881
[email protected]c50d0d42009-03-03 17:37:44882 bool was_bookmarked = model->IsBookmarked(url);
[email protected]85408b7c2009-06-03 19:11:54883 model->SetURLStarred(url, title, true);
[email protected]5f2731c52009-02-28 00:41:27884 if (window_->IsActive()) {
885 // Only show the bubble if the window is active, otherwise we may get into
886 // weird situations were the bubble is deleted as soon as it is shown.
[email protected]c50d0d42009-03-03 17:37:44887 window_->ShowBookmarkBubble(url, was_bookmarked);
[email protected]5f2731c52009-02-28 00:41:27888 }
[email protected]36b6dcb2008-11-12 01:19:57889}
890
[email protected]40bdb6d92009-02-25 00:22:27891void Browser::SavePage() {
892 UserMetrics::RecordAction(L"SavePage", profile_);
[email protected]57c6a652009-05-04 07:58:34893 GetSelectedTabContents()->OnSavePage();
[email protected]40bdb6d92009-02-25 00:22:27894}
895
[email protected]fbd77592008-11-12 20:50:27896void Browser::ViewSource() {
897 UserMetrics::RecordAction(L"ViewSource", profile_);
[email protected]36b6dcb2008-11-12 01:19:57898
[email protected]36b6dcb2008-11-12 01:19:57899 TabContents* current_tab = GetSelectedTabContents();
[email protected]ce3fa3c2009-04-20 19:55:57900 NavigationEntry* entry = current_tab->controller().GetLastCommittedEntry();
[email protected]fbd77592008-11-12 20:50:27901 if (entry) {
902 GURL url("view-source:" + entry->url().spec());
[email protected]749eea042009-01-05 22:35:54903 OpenURL(url, GURL(), NEW_FOREGROUND_TAB, PageTransition::LINK);
[email protected]36b6dcb2008-11-12 01:19:57904 }
905}
initial.commit09911bf2008-07-26 23:55:29906
[email protected]4801ecc2009-04-05 04:52:58907void Browser::ShowFindBar() {
908 find_bar_controller_->Show();
909}
910
[email protected]a3e18c42009-03-04 23:36:05911bool Browser::SupportsWindowFeature(WindowFeature feature) const {
912 unsigned int features = FEATURE_INFOBAR | FEATURE_DOWNLOADSHELF;
[email protected]653c9ea2009-05-06 16:58:56913 if (type() == TYPE_NORMAL) {
914 features |= FEATURE_BOOKMARKBAR;
915 features |= FEATURE_EXTENSIONSHELF;
916 }
[email protected]a3e18c42009-03-04 23:36:05917 if (!window_ || !window_->IsFullscreen()) {
918 if (type() == TYPE_NORMAL)
919 features |= FEATURE_TABSTRIP | FEATURE_TOOLBAR;
920 else
921 features |= FEATURE_TITLEBAR;
922 if ((type() & Browser::TYPE_APP) == 0)
923 features |= FEATURE_LOCATIONBAR;
924 }
925 return !!(features & feature);
926}
927
[email protected]c61db1d2009-02-06 03:39:18928#if defined(OS_WIN)
929
[email protected]fbd77592008-11-12 20:50:27930void Browser::ClosePopups() {
931 UserMetrics::RecordAction(L"CloseAllSuppressedPopups", profile_);
932 GetSelectedTabContents()->CloseAllSuppressedPopups();
933}
initial.commit09911bf2008-07-26 23:55:29934
[email protected]fbd77592008-11-12 20:50:27935void Browser::Print() {
936 UserMetrics::RecordAction(L"PrintPreview", profile_);
[email protected]57c6a652009-05-04 07:58:34937 GetSelectedTabContents()->PrintPreview();
[email protected]fbd77592008-11-12 20:50:27938}
[email protected]40d59ce52009-03-06 23:20:14939#endif // #if defined(OS_WIN)
[email protected]fbd77592008-11-12 20:50:27940
[email protected]fbd77592008-11-12 20:50:27941void Browser::ToggleEncodingAutoDetect() {
942 UserMetrics::RecordAction(L"AutoDetectChange", profile_);
943 encoding_auto_detect_.SetValue(!encoding_auto_detect_.GetValue());
944 // Reload the page so we can try to auto-detect the charset.
945 Reload();
946}
947
948void Browser::OverrideEncoding(int encoding_id) {
949 UserMetrics::RecordAction(L"OverrideEncoding", profile_);
950 const std::wstring selected_encoding =
951 CharacterEncoding::GetCanonicalEncodingNameByCommandId(encoding_id);
[email protected]57c6a652009-05-04 07:58:34952 TabContents* contents = GetSelectedTabContents();
953 if (!selected_encoding.empty() && contents)
954 contents->override_encoding(selected_encoding);
[email protected]fbd77592008-11-12 20:50:27955 // Update the list of recently selected encodings.
956 std::wstring new_selected_encoding_list;
957 if (CharacterEncoding::UpdateRecentlySelectdEncoding(
958 profile_->GetPrefs()->GetString(prefs::kRecentlySelectedEncoding),
959 encoding_id,
960 &new_selected_encoding_list)) {
961 profile_->GetPrefs()->SetString(prefs::kRecentlySelectedEncoding,
962 new_selected_encoding_list);
963 }
[email protected]36b6dcb2008-11-12 01:19:57964}
965
[email protected]40d59ce52009-03-06 23:20:14966#if defined(OS_WIN)
[email protected]84214982008-12-10 18:49:10967// TODO(devint): http://b/issue?id=1117225 Cut, Copy, and Paste are always
968// enabled in the page menu regardless of whether the command will do
969// anything. When someone selects the menu item, we just act as if they hit
970// the keyboard shortcut for the command by sending the associated key press
971// to windows. The real fix to this bug is to disable the commands when they
972// won't do anything. We'll need something like an overall clipboard command
973// manager to do that.
974
975void Browser::Cut() {
976 UserMetrics::RecordAction(L"Cut", profile_);
977 ui_controls::SendKeyPress(L'X', true, false, false);
[email protected]36b6dcb2008-11-12 01:19:57978}
979
[email protected]84214982008-12-10 18:49:10980void Browser::Copy() {
981 UserMetrics::RecordAction(L"Copy", profile_);
982 ui_controls::SendKeyPress(L'C', true, false, false);
[email protected]36b6dcb2008-11-12 01:19:57983}
984
[email protected]84214982008-12-10 18:49:10985void Browser::CopyCurrentPageURL() {
986 UserMetrics::RecordAction(L"CopyURLToClipBoard", profile_);
987 std::string url = GetSelectedTabContents()->GetURL().spec();
988
989 if (!::OpenClipboard(NULL)) {
990 NOTREACHED();
991 return;
992 }
993
994 if (::EmptyClipboard()) {
995 HGLOBAL text = ::GlobalAlloc(GMEM_MOVEABLE, url.size() + 1);
996 LPSTR ptr = static_cast<LPSTR>(::GlobalLock(text));
997 memcpy(ptr, url.c_str(), url.size());
998 ptr[url.size()] = '\0';
999 ::GlobalUnlock(text);
1000
1001 ::SetClipboardData(CF_TEXT, text);
1002 }
1003
1004 if (!::CloseClipboard()) {
1005 NOTREACHED();
1006 }
[email protected]36b6dcb2008-11-12 01:19:571007}
1008
[email protected]84214982008-12-10 18:49:101009void Browser::Paste() {
1010 UserMetrics::RecordAction(L"Paste", profile_);
1011 ui_controls::SendKeyPress(L'V', true, false, false);
1012}
[email protected]31b1bc3a2009-03-10 19:26:191013#endif // #if defined(OS_WIN)
[email protected]84214982008-12-10 18:49:101014
1015void Browser::Find() {
1016 UserMetrics::RecordAction(L"Find", profile_);
[email protected]4f3dc372009-02-24 00:10:291017 FindInPage(false, false);
[email protected]84214982008-12-10 18:49:101018}
1019
1020void Browser::FindNext() {
1021 UserMetrics::RecordAction(L"FindNext", profile_);
[email protected]4f3dc372009-02-24 00:10:291022 FindInPage(true, true);
[email protected]84214982008-12-10 18:49:101023}
1024
1025void Browser::FindPrevious() {
1026 UserMetrics::RecordAction(L"FindPrevious", profile_);
[email protected]4f3dc372009-02-24 00:10:291027 FindInPage(true, false);
[email protected]84214982008-12-10 18:49:101028}
1029
1030void Browser::ZoomIn() {
1031 UserMetrics::RecordAction(L"ZoomPlus", profile_);
[email protected]57c6a652009-05-04 07:58:341032 GetSelectedTabContents()->render_view_host()->Zoom(PageZoom::LARGER);
[email protected]84214982008-12-10 18:49:101033}
1034
1035void Browser::ZoomReset() {
1036 UserMetrics::RecordAction(L"ZoomNormal", profile_);
[email protected]57c6a652009-05-04 07:58:341037 GetSelectedTabContents()->render_view_host()->Zoom(PageZoom::STANDARD);
[email protected]84214982008-12-10 18:49:101038}
1039
1040void Browser::ZoomOut() {
1041 UserMetrics::RecordAction(L"ZoomMinus", profile_);
[email protected]57c6a652009-05-04 07:58:341042 GetSelectedTabContents()->render_view_host()->Zoom(PageZoom::SMALLER);
[email protected]84214982008-12-10 18:49:101043}
1044
1045void Browser::FocusToolbar() {
1046 UserMetrics::RecordAction(L"FocusToolbar", profile_);
1047 window_->FocusToolbar();
1048}
1049
1050void Browser::FocusLocationBar() {
1051 UserMetrics::RecordAction(L"FocusLocation", profile_);
[email protected]d56bcd22009-03-16 19:51:561052 window_->SetFocusToLocationBar();
[email protected]84214982008-12-10 18:49:101053}
1054
1055void Browser::FocusSearch() {
1056 // TODO(beng): replace this with FocusLocationBar
1057 UserMetrics::RecordAction(L"FocusSearch", profile_);
[email protected]7745b822009-01-27 20:15:351058 window_->GetLocationBar()->FocusSearch();
[email protected]84214982008-12-10 18:49:101059}
1060
1061void Browser::OpenFile() {
1062 UserMetrics::RecordAction(L"OpenFile", profile_);
1063 if (!select_file_dialog_.get())
1064 select_file_dialog_ = SelectFileDialog::Create(this);
1065
1066 // TODO(beng): figure out how to juggle this.
[email protected]d56bcd22009-03-16 19:51:561067 gfx::NativeWindow parent_window = window_->GetNativeHandle();
[email protected]84214982008-12-10 18:49:101068 select_file_dialog_->SelectFile(SelectFileDialog::SELECT_OPEN_FILE,
[email protected]561abe62009-04-06 18:08:341069 string16(), FilePath(),
[email protected]b949f1112009-04-12 20:03:081070 NULL, 0, FILE_PATH_LITERAL(""),
[email protected]d56bcd22009-03-16 19:51:561071 parent_window, NULL);
[email protected]84214982008-12-10 18:49:101072}
1073
1074void Browser::OpenCreateShortcutsDialog() {
1075 UserMetrics::RecordAction(L"CreateShortcut", profile_);
[email protected]98f6e022009-06-05 22:49:531076#if defined(OS_WIN)
[email protected]57c6a652009-05-04 07:58:341077 GetSelectedTabContents()->CreateShortcut();
[email protected]98f6e022009-06-05 22:49:531078#else
1079 NOTIMPLEMENTED();
1080#endif
[email protected]36b6dcb2008-11-12 01:19:571081}
1082
[email protected]3061ccf32009-07-13 14:17:491083void Browser::ToggleJavaScriptConsole() {
[email protected]fbd77592008-11-12 20:50:271084 UserMetrics::RecordAction(L"ShowJSConsole", profile_);
[email protected]3061ccf32009-07-13 14:17:491085 DevToolsManager::GetInstance()->ToggleDevToolsWindow(
[email protected]d9f9b792009-06-24 13:17:121086 GetSelectedTabContents()->render_view_host());
[email protected]fbd77592008-11-12 20:50:271087}
1088
[email protected]84214982008-12-10 18:49:101089void Browser::OpenTaskManager() {
1090 UserMetrics::RecordAction(L"TaskManager", profile_);
[email protected]8f90afd72009-06-22 22:44:381091 window_->ShowTaskManager();
[email protected]84214982008-12-10 18:49:101092}
1093
1094void Browser::OpenSelectProfileDialog() {
[email protected]12a6f0362009-03-09 19:37:361095 const CommandLine& command_line = *CommandLine::ForCurrentProcess();
1096 if (!command_line.HasSwitch(switches::kEnableUserDataDirProfiles))
1097 return;
[email protected]84214982008-12-10 18:49:101098 UserMetrics::RecordAction(L"SelectProfile", profile_);
[email protected]505323e22009-01-24 02:47:581099 window_->ShowSelectProfileDialog();
[email protected]84214982008-12-10 18:49:101100}
1101
1102void Browser::OpenNewProfileDialog() {
[email protected]ac926362009-02-26 01:33:181103 const CommandLine& command_line = *CommandLine::ForCurrentProcess();
1104 if (!command_line.HasSwitch(switches::kEnableUserDataDirProfiles))
1105 return;
[email protected]84214982008-12-10 18:49:101106 UserMetrics::RecordAction(L"CreateProfile", profile_);
[email protected]505323e22009-01-24 02:47:581107 window_->ShowNewProfileDialog();
[email protected]84214982008-12-10 18:49:101108}
1109
1110void Browser::OpenBugReportDialog() {
1111 UserMetrics::RecordAction(L"ReportBug", profile_);
1112 window_->ShowReportBugDialog();
1113}
[email protected]44b2c8852009-03-18 00:57:491114
[email protected]84214982008-12-10 18:49:101115void Browser::ToggleBookmarkBar() {
1116 UserMetrics::RecordAction(L"ShowBookmarksBar", profile_);
1117 window_->ToggleBookmarkBar();
1118}
1119
[email protected]84214982008-12-10 18:49:101120void Browser::OpenBookmarkManager() {
1121 UserMetrics::RecordAction(L"ShowBookmarkManager", profile_);
1122 window_->ShowBookmarkManager();
1123}
[email protected]8bf80e922009-03-09 20:56:361124
1125void Browser::ShowHistoryTab() {
1126 UserMetrics::RecordAction(L"ShowHistory", profile_);
[email protected]b689fce72009-03-17 22:45:341127 ShowSingleDOMUITab(GURL(chrome::kChromeUIHistoryURL));
[email protected]8bf80e922009-03-09 20:56:361128}
[email protected]84214982008-12-10 18:49:101129
1130void Browser::ShowDownloadsTab() {
1131 UserMetrics::RecordAction(L"ShowDownloads", profile_);
[email protected]b689fce72009-03-17 22:45:341132 ShowSingleDOMUITab(GURL(chrome::kChromeUIDownloadsURL));
[email protected]84214982008-12-10 18:49:101133}
1134
1135void Browser::OpenClearBrowsingDataDialog() {
1136 UserMetrics::RecordAction(L"ClearBrowsingData_ShowDlg", profile_);
1137 window_->ShowClearBrowsingDataDialog();
1138}
1139
[email protected]84214982008-12-10 18:49:101140void Browser::OpenOptionsDialog() {
1141 UserMetrics::RecordAction(L"ShowOptions", profile_);
1142 ShowOptionsWindow(OPTIONS_PAGE_DEFAULT, OPTIONS_GROUP_NONE, profile_);
1143}
1144
1145void Browser::OpenKeywordEditor() {
1146 UserMetrics::RecordAction(L"EditSearchEngines", profile_);
1147 window_->ShowSearchEnginesDialog();
[email protected]fbd77592008-11-12 20:50:271148}
1149
1150void Browser::OpenPasswordManager() {
[email protected]2d46c842008-11-14 19:24:311151 window_->ShowPasswordManager();
[email protected]fbd77592008-11-12 20:50:271152}
1153
[email protected]1bdf29e2009-05-11 23:45:251154void Browser::OpenImportSettingsDialog() {
1155 UserMetrics::RecordAction(L"Import_ShowDlg", profile_);
1156 window_->ShowImportDialog();
1157}
[email protected]1bdf29e2009-05-11 23:45:251158
[email protected]fbd77592008-11-12 20:50:271159void Browser::OpenAboutChromeDialog() {
1160 UserMetrics::RecordAction(L"AboutChrome", profile_);
[email protected]2d46c842008-11-14 19:24:311161 window_->ShowAboutChromeDialog();
[email protected]fbd77592008-11-12 20:50:271162}
1163
[email protected]fbd77592008-11-12 20:50:271164void Browser::OpenHelpTab() {
[email protected]40d59ce52009-03-06 23:20:141165 GURL help_url(WideToASCII(l10n_util::GetString(IDS_HELP_CONTENT_URL)));
[email protected]22735af62009-04-07 21:09:581166 AddTabWithURL(help_url, GURL(), PageTransition::AUTO_BOOKMARK, true, -1,
[email protected]5a4940be2009-05-06 06:44:391167 false, NULL);
[email protected]fbd77592008-11-12 20:50:271168}
1169
[email protected]16779842009-07-08 23:45:291170#if defined(OS_CHROMEOS)
[email protected]be715072009-07-07 15:43:201171void Browser::ShowControlPanel() {
1172 GURL url("http://localhost:8080");
1173 AddTabWithURL(url, GURL(), PageTransition::AUTO_BOOKMARK, true, -1,
1174 false, NULL);
1175}
1176#endif
1177
[email protected]36b6dcb2008-11-12 01:19:571178///////////////////////////////////////////////////////////////////////////////
1179
1180// static
1181void Browser::RegisterPrefs(PrefService* prefs) {
1182 prefs->RegisterDictionaryPref(prefs::kBrowserWindowPlacement);
1183 prefs->RegisterIntegerPref(prefs::kOptionsWindowLastTabIndex, 0);
[email protected]749380bb2009-07-20 08:57:551184 prefs->RegisterIntegerPref(prefs::kDevToolsSplitLocation, -1);
[email protected]36b6dcb2008-11-12 01:19:571185}
1186
1187// static
1188void Browser::RegisterUserPrefs(PrefService* prefs) {
1189 prefs->RegisterStringPref(prefs::kHomePage, L"chrome-internal:");
1190 prefs->RegisterBooleanPref(prefs::kHomePageIsNewTabPage, true);
1191 prefs->RegisterIntegerPref(prefs::kCookieBehavior,
1192 net::CookiePolicy::ALLOW_ALL_COOKIES);
1193 prefs->RegisterBooleanPref(prefs::kShowHomeButton, false);
[email protected]93a2c7242009-07-07 18:43:091194#if defined(OS_MACOSX)
1195 // This really belongs in platform code, but there's no good place to
1196 // initialize it between the time when the AppController is created
1197 // (where there's no profile) and the time the controller gets another
1198 // crack at the start of the main event loop. By that time, BrowserInit
1199 // has already created the browser window, and it's too late: we need the
1200 // pref to be already initialized. Doing it here also saves us from having
1201 // to hard-code pref registration in the several unit tests that use
1202 // this preference.
1203 prefs->RegisterBooleanPref(prefs::kShowPageOptionsButtons, false);
1204#endif
[email protected]36b6dcb2008-11-12 01:19:571205 prefs->RegisterStringPref(prefs::kRecentlySelectedEncoding, L"");
[email protected]36b6dcb2008-11-12 01:19:571206 prefs->RegisterBooleanPref(prefs::kDeleteBrowsingHistory, true);
1207 prefs->RegisterBooleanPref(prefs::kDeleteDownloadHistory, true);
1208 prefs->RegisterBooleanPref(prefs::kDeleteCache, true);
1209 prefs->RegisterBooleanPref(prefs::kDeleteCookies, true);
1210 prefs->RegisterBooleanPref(prefs::kDeletePasswords, false);
1211 prefs->RegisterBooleanPref(prefs::kDeleteFormData, true);
1212 prefs->RegisterIntegerPref(prefs::kDeleteTimePeriod, 0);
[email protected]48b47ffa2009-05-02 07:18:301213 prefs->RegisterBooleanPref(prefs::kCheckDefaultBrowser, true);
[email protected]e116a522009-06-04 20:10:311214 prefs->RegisterBooleanPref(prefs::kUseCustomChromeFrame, false);
[email protected]36b6dcb2008-11-12 01:19:571215}
1216
1217// static
1218Browser* Browser::GetBrowserForController(
1219 const NavigationController* controller, int* index_result) {
1220 BrowserList::const_iterator it;
1221 for (it = BrowserList::begin(); it != BrowserList::end(); ++it) {
[email protected]902cdf772009-05-06 15:08:121222 int index = (*it)->tabstrip_model_.GetIndexOfController(controller);
[email protected]36b6dcb2008-11-12 01:19:571223 if (index != TabStripModel::kNoTab) {
1224 if (index_result)
1225 *index_result = index;
1226 return *it;
1227 }
1228 }
1229
1230 return NULL;
1231}
1232
[email protected]485fba42009-03-24 23:27:291233void Browser::ExecuteCommandWithDisposition(
1234 int id, WindowOpenDisposition disposition) {
[email protected]1fc025202009-01-20 23:03:141235 // No commands are enabled if there is not yet any selected tab.
1236 // TODO(pkasting): It seems like we should not need this, because either
1237 // most/all commands should not have been enabled yet anyway or the ones that
1238 // are enabled should be global, or safe themselves against having no selected
1239 // tab. However, Ben says he tried removing this before and got lots of
1240 // crashes, e.g. from Windows sending WM_COMMANDs at random times during
1241 // window construction. This probably could use closer examination someday.
1242 if (!GetSelectedTabContents())
1243 return;
1244
1245 DCHECK(command_updater_.IsCommandEnabled(id)) << "Invalid/disabled command";
[email protected]36b6dcb2008-11-12 01:19:571246
[email protected]fbd77592008-11-12 20:50:271247 // The order of commands in this switch statement must match the function
1248 // declaration order in browser.h!
[email protected]36b6dcb2008-11-12 01:19:571249 switch (id) {
[email protected]84214982008-12-10 18:49:101250 // Navigation commands
[email protected]485fba42009-03-24 23:27:291251 case IDC_BACK: GoBack(disposition); break;
1252 case IDC_FORWARD: GoForward(disposition); break;
[email protected]cb525c82008-12-08 23:04:541253 case IDC_RELOAD: Reload(); break;
[email protected]485fba42009-03-24 23:27:291254 case IDC_HOME: Home(disposition); break;
[email protected]cb525c82008-12-08 23:04:541255 case IDC_OPEN_CURRENT_URL: OpenCurrentURL(); break;
[email protected]485fba42009-03-24 23:27:291256 case IDC_GO: Go(disposition); break;
[email protected]84214982008-12-10 18:49:101257 case IDC_STOP: Stop(); break;
[email protected]36b6dcb2008-11-12 01:19:571258
[email protected]84214982008-12-10 18:49:101259 // Window management commands
[email protected]cb525c82008-12-08 23:04:541260 case IDC_NEW_WINDOW: NewWindow(); break;
1261 case IDC_NEW_INCOGNITO_WINDOW: NewIncognitoWindow(); break;
[email protected]84214982008-12-10 18:49:101262 case IDC_NEW_WINDOW_PROFILE_0:
1263 case IDC_NEW_WINDOW_PROFILE_1:
1264 case IDC_NEW_WINDOW_PROFILE_2:
1265 case IDC_NEW_WINDOW_PROFILE_3:
1266 case IDC_NEW_WINDOW_PROFILE_4:
1267 case IDC_NEW_WINDOW_PROFILE_5:
1268 case IDC_NEW_WINDOW_PROFILE_6:
1269 case IDC_NEW_WINDOW_PROFILE_7:
[email protected]f21c613a2009-02-12 14:46:171270 case IDC_NEW_WINDOW_PROFILE_8:
[email protected]84214982008-12-10 18:49:101271 NewProfileWindowByIndex(id - IDC_NEW_WINDOW_PROFILE_0); break;
[email protected]cb525c82008-12-08 23:04:541272 case IDC_CLOSE_WINDOW: CloseWindow(); break;
[email protected]84214982008-12-10 18:49:101273 case IDC_NEW_TAB: NewTab(); break;
1274 case IDC_CLOSE_TAB: CloseTab(); break;
[email protected]cb525c82008-12-08 23:04:541275 case IDC_SELECT_NEXT_TAB: SelectNextTab(); break;
1276 case IDC_SELECT_PREVIOUS_TAB: SelectPreviousTab(); break;
[email protected]36b6dcb2008-11-12 01:19:571277 case IDC_SELECT_TAB_0:
1278 case IDC_SELECT_TAB_1:
1279 case IDC_SELECT_TAB_2:
1280 case IDC_SELECT_TAB_3:
1281 case IDC_SELECT_TAB_4:
1282 case IDC_SELECT_TAB_5:
1283 case IDC_SELECT_TAB_6:
[email protected]cb525c82008-12-08 23:04:541284 case IDC_SELECT_TAB_7: SelectNumberedTab(id - IDC_SELECT_TAB_0);
1285 break;
1286 case IDC_SELECT_LAST_TAB: SelectLastTab(); break;
1287 case IDC_DUPLICATE_TAB: DuplicateTab(); break;
1288 case IDC_RESTORE_TAB: RestoreTab(); break;
1289 case IDC_SHOW_AS_TAB: ConvertPopupToTabbedBrowser(); break;
[email protected]9282cea2009-02-18 18:49:001290 case IDC_FULLSCREEN: ToggleFullscreenMode(); break;
[email protected]cb525c82008-12-08 23:04:541291 case IDC_EXIT: Exit(); break;
[email protected]36b6dcb2008-11-12 01:19:571292
[email protected]84214982008-12-10 18:49:101293 // Page-related commands
[email protected]40bdb6d92009-02-25 00:22:271294 case IDC_SAVE_PAGE: SavePage(); break;
[email protected]cb525c82008-12-08 23:04:541295 case IDC_STAR: BookmarkCurrentPage(); break;
1296 case IDC_VIEW_SOURCE: ViewSource(); break;
[email protected]c61db1d2009-02-06 03:39:181297#if defined(OS_WIN)
[email protected]cb525c82008-12-08 23:04:541298 case IDC_CLOSE_POPUPS: ClosePopups(); break;
1299 case IDC_PRINT: Print(); break;
[email protected]40d59ce52009-03-06 23:20:141300#endif
[email protected]cb525c82008-12-08 23:04:541301 case IDC_ENCODING_AUTO_DETECT: ToggleEncodingAutoDetect(); break;
[email protected]36b6dcb2008-11-12 01:19:571302 case IDC_ENCODING_UTF8:
1303 case IDC_ENCODING_UTF16LE:
1304 case IDC_ENCODING_ISO88591:
1305 case IDC_ENCODING_WINDOWS1252:
[email protected]1c5bf632008-12-11 20:30:491306 case IDC_ENCODING_GBK:
[email protected]36b6dcb2008-11-12 01:19:571307 case IDC_ENCODING_GB18030:
1308 case IDC_ENCODING_BIG5HKSCS:
1309 case IDC_ENCODING_BIG5:
1310 case IDC_ENCODING_KOREAN:
1311 case IDC_ENCODING_SHIFTJIS:
1312 case IDC_ENCODING_ISO2022JP:
1313 case IDC_ENCODING_EUCJP:
1314 case IDC_ENCODING_THAI:
1315 case IDC_ENCODING_ISO885915:
1316 case IDC_ENCODING_MACINTOSH:
1317 case IDC_ENCODING_ISO88592:
1318 case IDC_ENCODING_WINDOWS1250:
1319 case IDC_ENCODING_ISO88595:
1320 case IDC_ENCODING_WINDOWS1251:
1321 case IDC_ENCODING_KOI8R:
1322 case IDC_ENCODING_KOI8U:
1323 case IDC_ENCODING_ISO88597:
1324 case IDC_ENCODING_WINDOWS1253:
1325 case IDC_ENCODING_ISO88594:
1326 case IDC_ENCODING_ISO885913:
1327 case IDC_ENCODING_WINDOWS1257:
1328 case IDC_ENCODING_ISO88593:
1329 case IDC_ENCODING_ISO885910:
1330 case IDC_ENCODING_ISO885914:
1331 case IDC_ENCODING_ISO885916:
[email protected]36b6dcb2008-11-12 01:19:571332 case IDC_ENCODING_WINDOWS1254:
1333 case IDC_ENCODING_ISO88596:
1334 case IDC_ENCODING_WINDOWS1256:
1335 case IDC_ENCODING_ISO88598:
[email protected]e13271f2009-03-07 00:26:001336 case IDC_ENCODING_ISO88598I:
[email protected]36b6dcb2008-11-12 01:19:571337 case IDC_ENCODING_WINDOWS1255:
[email protected]cb525c82008-12-08 23:04:541338 case IDC_ENCODING_WINDOWS1258: OverrideEncoding(id); break;
[email protected]36b6dcb2008-11-12 01:19:571339
[email protected]40d59ce52009-03-06 23:20:141340#if defined(OS_WIN)
[email protected]84214982008-12-10 18:49:101341 // Clipboard commands
1342 case IDC_CUT: Cut(); break;
1343 case IDC_COPY: Copy(); break;
1344 case IDC_COPY_URL: CopyCurrentPageURL(); break;
1345 case IDC_PASTE: Paste(); break;
[email protected]31b1bc3a2009-03-10 19:26:191346#endif
[email protected]84214982008-12-10 18:49:101347
1348 // Find-in-page
1349 case IDC_FIND: Find(); break;
1350 case IDC_FIND_NEXT: FindNext(); break;
1351 case IDC_FIND_PREVIOUS: FindPrevious(); break;
1352
1353 // Zoom
1354 case IDC_ZOOM_PLUS: ZoomIn(); break;
1355 case IDC_ZOOM_NORMAL: ZoomReset(); break;
1356 case IDC_ZOOM_MINUS: ZoomOut(); break;
1357
1358 // Focus various bits of UI
1359 case IDC_FOCUS_TOOLBAR: FocusToolbar(); break;
1360 case IDC_FOCUS_LOCATION: FocusLocationBar(); break;
1361 case IDC_FOCUS_SEARCH: FocusSearch(); break;
1362
1363 // Show various bits of UI
1364 case IDC_OPEN_FILE: OpenFile(); break;
1365 case IDC_CREATE_SHORTCUTS: OpenCreateShortcutsDialog(); break;
[email protected]3061ccf32009-07-13 14:17:491366 case IDC_JS_CONSOLE: ToggleJavaScriptConsole(); break;
[email protected]cb525c82008-12-08 23:04:541367 case IDC_TASK_MANAGER: OpenTaskManager(); break;
[email protected]cb525c82008-12-08 23:04:541368 case IDC_SELECT_PROFILE: OpenSelectProfileDialog(); break;
1369 case IDC_NEW_PROFILE: OpenNewProfileDialog(); break;
[email protected]84214982008-12-10 18:49:101370 case IDC_REPORT_BUG: OpenBugReportDialog(); break;
[email protected]44b2c8852009-03-18 00:57:491371
[email protected]84214982008-12-10 18:49:101372 case IDC_SHOW_BOOKMARK_BAR: ToggleBookmarkBar(); break;
[email protected]44b2c8852009-03-18 00:57:491373
[email protected]84214982008-12-10 18:49:101374 case IDC_SHOW_BOOKMARK_MANAGER: OpenBookmarkManager(); break;
[email protected]8bf80e922009-03-09 20:56:361375 case IDC_SHOW_HISTORY: ShowHistoryTab(); break;
[email protected]84214982008-12-10 18:49:101376 case IDC_SHOW_DOWNLOADS: ShowDownloadsTab(); break;
[email protected]8bf80e922009-03-09 20:56:361377#if defined(OS_WIN)
[email protected]026e34a2009-02-06 00:06:121378#ifdef CHROME_PERSONALIZATION
1379 case IDC_P13N_INFO:
1380 Personalization::HandleMenuItemClick(profile()); break;
1381#endif
[email protected]0e3e3e32009-05-14 01:00:531382#endif
[email protected]84214982008-12-10 18:49:101383 case IDC_OPTIONS: OpenOptionsDialog(); break;
1384 case IDC_EDIT_SEARCH_ENGINES: OpenKeywordEditor(); break;
1385 case IDC_VIEW_PASSWORDS: OpenPasswordManager(); break;
[email protected]25364e12009-05-22 01:37:191386 case IDC_CLEAR_BROWSING_DATA: OpenClearBrowsingDataDialog(); break;
[email protected]1bdf29e2009-05-11 23:45:251387 case IDC_IMPORT_SETTINGS: OpenImportSettingsDialog(); break;
[email protected]4dbac172009-04-24 20:23:491388 case IDC_ABOUT: OpenAboutChromeDialog(); break;
[email protected]40d59ce52009-03-06 23:20:141389 case IDC_HELP_PAGE: OpenHelpTab(); break;
[email protected]16779842009-07-08 23:45:291390#if defined(OS_CHROMEOS)
[email protected]be715072009-07-07 15:43:201391 case IDC_CONTROL_PANEL: ShowControlPanel(); break;
1392#endif
[email protected]d938aed92009-01-22 19:49:331393
[email protected]36b6dcb2008-11-12 01:19:571394 default:
[email protected]84214982008-12-10 18:49:101395 LOG(WARNING) << "Received Unimplemented Command: " << id;
[email protected]fbd77592008-11-12 20:50:271396 break;
[email protected]36b6dcb2008-11-12 01:19:571397 }
1398}
1399
1400///////////////////////////////////////////////////////////////////////////////
[email protected]485fba42009-03-24 23:27:291401// Browser, CommandUpdater::CommandUpdaterDelegate implementation:
1402
1403void Browser::ExecuteCommand(int id) {
1404 ExecuteCommandWithDisposition(id, CURRENT_TAB);
1405}
1406
1407///////////////////////////////////////////////////////////////////////////////
[email protected]36b6dcb2008-11-12 01:19:571408// Browser, TabStripModelDelegate implementation:
1409
[email protected]22735af62009-04-07 21:09:581410TabContents* Browser::AddBlankTab(bool foreground) {
1411 return AddBlankTabAt(-1, foreground);
1412}
1413
1414TabContents* Browser::AddBlankTabAt(int index, bool foreground) {
1415 return AddTabWithURL(GURL(chrome::kChromeUINewTabURL), GURL(),
[email protected]5a4940be2009-05-06 06:44:391416 PageTransition::TYPED, foreground, index, false, NULL);
[email protected]15952e462008-11-14 00:29:051417}
1418
[email protected]3d1104f2009-03-26 15:30:281419Browser* Browser::CreateNewStripWithContents(TabContents* detached_contents,
1420 const gfx::Rect& window_bounds,
1421 const DockInfo& dock_info) {
[email protected]299dabd2008-11-19 02:27:161422 DCHECK(type_ == TYPE_NORMAL);
[email protected]adf650f2008-12-09 16:10:061423
[email protected]5e495462008-11-20 23:07:411424 gfx::Rect new_window_bounds = window_bounds;
1425 bool maximize = false;
1426 if (dock_info.GetNewWindowBounds(&new_window_bounds, &maximize))
1427 dock_info.AdjustOtherWindowBounds();
1428
[email protected]36b6dcb2008-11-12 01:19:571429 // Create an empty new browser window the same size as the old one.
[email protected]299dabd2008-11-19 02:27:161430 Browser* browser = new Browser(TYPE_NORMAL, profile_);
[email protected]5e495462008-11-20 23:07:411431 browser->set_override_bounds(new_window_bounds);
[email protected]2e716622009-03-09 21:11:011432 browser->set_maximized_state(
1433 maximize ? MAXIMIZED_STATE_MAXIMIZED : MAXIMIZED_STATE_UNMAXIMIZED);
[email protected]15952e462008-11-14 00:29:051434 browser->CreateBrowserWindow();
1435 browser->tabstrip_model()->AppendTabContents(detached_contents, true);
[email protected]159f7762008-12-19 14:58:271436 // Make sure the loading state is updated correctly, otherwise the throbber
1437 // won't start if the page is loading.
1438 browser->LoadingStateChanged(detached_contents);
[email protected]3d1104f2009-03-26 15:30:281439 return browser;
[email protected]36b6dcb2008-11-12 01:19:571440}
1441
[email protected]7c0560f2009-07-07 18:44:311442void Browser::ContinueDraggingDetachedTab(TabContents* contents,
1443 const gfx::Rect& window_bounds,
1444 const gfx::Rect& tab_bounds) {
1445 Browser* browser = new Browser(TYPE_NORMAL, profile_);
1446 browser->set_override_bounds(window_bounds);
1447 browser->CreateBrowserWindow();
1448 browser->tabstrip_model()->AppendTabContents(contents, true);
1449 browser->LoadingStateChanged(contents);
1450 browser->window()->Show();
1451 browser->window()->ContinueDraggingDetachedTab(tab_bounds);
1452}
1453
[email protected]36b6dcb2008-11-12 01:19:571454int Browser::GetDragActions() const {
[email protected]d54f6a002009-03-18 17:17:251455 return TAB_TEAROFF_ACTION | (tab_count() > 1 ? TAB_MOVE_ACTION : 0);
[email protected]36b6dcb2008-11-12 01:19:571456}
1457
1458TabContents* Browser::CreateTabContentsForURL(
1459 const GURL& url, const GURL& referrer, Profile* profile,
1460 PageTransition::Type transition, bool defer_load,
1461 SiteInstance* instance) const {
[email protected]57c6a652009-05-04 07:58:341462 TabContents* contents = new TabContents(profile, instance,
[email protected]9423d9412009-04-14 22:13:551463 MSG_ROUTING_NONE, NULL);
[email protected]36b6dcb2008-11-12 01:19:571464
1465 if (!defer_load) {
1466 // Load the initial URL before adding the new tab contents to the tab strip
1467 // so that the tab contents has navigation state.
[email protected]ce3fa3c2009-04-20 19:55:571468 contents->controller().LoadURL(url, referrer, transition);
[email protected]36b6dcb2008-11-12 01:19:571469 }
1470
1471 return contents;
1472}
1473
1474bool Browser::CanDuplicateContentsAt(int index) {
[email protected]ce3fa3c2009-04-20 19:55:571475 NavigationController& nc = GetTabContentsAt(index)->controller();
1476 return nc.tab_contents() && nc.GetLastCommittedEntry();
[email protected]36b6dcb2008-11-12 01:19:571477}
1478
1479void Browser::DuplicateContentsAt(int index) {
1480 TabContents* contents = GetTabContentsAt(index);
1481 TabContents* new_contents = NULL;
1482 DCHECK(contents);
[email protected]5c0e6482009-07-14 20:20:091483 bool pinned = false;
[email protected]36b6dcb2008-11-12 01:19:571484
[email protected]299dabd2008-11-19 02:27:161485 if (type_ == TYPE_NORMAL) {
[email protected]36b6dcb2008-11-12 01:19:571486 // If this is a tabbed browser, just create a duplicate tab inside the same
1487 // window next to the tab being duplicated.
[email protected]ce3fa3c2009-04-20 19:55:571488 new_contents = contents->Clone();
[email protected]5c0e6482009-07-14 20:20:091489 // Make sure we force the index, otherwise the duplicate tab may appear at
1490 // the wrong location.
1491 tabstrip_model_.AddTabContents(new_contents, index + 1, true,
[email protected]36b6dcb2008-11-12 01:19:571492 PageTransition::LINK, true);
[email protected]5c0e6482009-07-14 20:20:091493 if (tabstrip_model_.IsTabPinned(index)) {
1494 pinned = true;
1495 tabstrip_model_.SetTabPinned(index + 1, true);
1496 }
[email protected]36b6dcb2008-11-12 01:19:571497 } else {
[email protected]15952e462008-11-14 00:29:051498 Browser* browser = NULL;
[email protected]d5fbc002009-02-27 22:12:581499 if (type_ & TYPE_APP) {
1500 browser = Browser::CreateForApp(app_name_, profile_, type_ & TYPE_POPUP);
[email protected]299dabd2008-11-19 02:27:161501 } else if (type_ == TYPE_POPUP) {
[email protected]15952e462008-11-14 00:29:051502 browser = Browser::CreateForPopup(profile_);
1503 }
[email protected]36b6dcb2008-11-12 01:19:571504
[email protected]b1fed962008-12-18 00:54:081505 // Preserve the size of the original window. The new window has already
1506 // been given an offset by the OS, so we shouldn't copy the old bounds.
1507 BrowserWindow* new_window = browser->window();
1508 new_window->SetBounds(gfx::Rect(new_window->GetNormalBounds().origin(),
1509 window()->GetNormalBounds().size()));
1510
[email protected]36b6dcb2008-11-12 01:19:571511 // We need to show the browser now. Otherwise ContainerWin assumes the
1512 // TabContents is invisible and won't size it.
[email protected]15952e462008-11-14 00:29:051513 browser->window()->Show();
[email protected]36b6dcb2008-11-12 01:19:571514
1515 // The page transition below is only for the purpose of inserting the tab.
[email protected]15952e462008-11-14 00:29:051516 new_contents = browser->AddTabWithNavigationController(
[email protected]ce3fa3c2009-04-20 19:55:571517 &contents->Clone()->controller(),
[email protected]36b6dcb2008-11-12 01:19:571518 PageTransition::LINK);
[email protected]36b6dcb2008-11-12 01:19:571519 }
1520
1521 if (profile_->HasSessionService()) {
1522 SessionService* session_service = profile_->GetSessionService();
1523 if (session_service)
[email protected]5c0e6482009-07-14 20:20:091524 session_service->TabRestored(&new_contents->controller(), pinned);
[email protected]36b6dcb2008-11-12 01:19:571525 }
1526}
1527
[email protected]36b6dcb2008-11-12 01:19:571528void Browser::CloseFrameAfterDragSession() {
[email protected]9aefecc92009-06-10 21:31:321529#if defined(OS_WIN) || defined(OS_LINUX)
[email protected]36b6dcb2008-11-12 01:19:571530 // This is scheduled to run after we return to the message loop because
1531 // otherwise the frame will think the drag session is still active and ignore
1532 // the request.
[email protected]d6a3c772009-01-27 19:41:201533 // TODO(port): figure out what is required here in a cross-platform world
[email protected]36b6dcb2008-11-12 01:19:571534 MessageLoop::current()->PostTask(FROM_HERE,
1535 method_factory_.NewRunnableMethod(&Browser::CloseFrame));
[email protected]d6a3c772009-01-27 19:41:201536#endif
initial.commit09911bf2008-07-26 23:55:291537}
1538
[email protected]505323e22009-01-24 02:47:581539void Browser::CreateHistoricalTab(TabContents* contents) {
1540 // We don't create historical tabs for incognito windows or windows without
1541 // profiles.
1542 if (!profile() || profile()->IsOffTheRecord() ||
1543 !profile()->GetTabRestoreService()) {
1544 return;
1545 }
1546
1547 // We only create historical tab entries for normal tabbed browser windows.
1548 if (type() == TYPE_NORMAL) {
1549 profile()->GetTabRestoreService()->CreateHistoricalTab(
[email protected]ce3fa3c2009-04-20 19:55:571550 &contents->controller());
[email protected]505323e22009-01-24 02:47:581551 }
1552}
1553
1554bool Browser::RunUnloadListenerBeforeClosing(TabContents* contents) {
[email protected]57c6a652009-05-04 07:58:341555 // If the TabContents is not connected yet, then there's no unload
1556 // handler we can fire even if the TabContents has an unload listener.
1557 // One case where we hit this is in a tab that has an infinite loop
1558 // before load.
1559 if (TabHasUnloadListener(contents)) {
1560 // If the page has unload listeners, then we tell the renderer to fire
1561 // them. Once they have fired, we'll get a message back saying whether
1562 // to proceed closing the page or not, which sends us back to this method
1563 // with the HasUnloadListener bit cleared.
1564 contents->render_view_host()->FirePageBeforeUnload();
1565 return true;
[email protected]505323e22009-01-24 02:47:581566 }
1567 return false;
1568}
1569
[email protected]940ccb22009-04-30 17:11:101570bool Browser::CanCloseContentsAt(int index) {
1571 if (tabstrip_model_.count() > 1)
1572 return true;
1573 // We are closing the last tab for this browser. Make sure to check for
1574 // in-progress downloads.
1575 // Note that the next call when it returns false will ask the user for
1576 // confirmation before closing the browser if the user decides so.
1577 return CanCloseWithInProgressDownloads();
1578}
[email protected]d6a3c772009-01-27 19:41:201579
[email protected]2d46c842008-11-14 19:24:311580///////////////////////////////////////////////////////////////////////////////
[email protected]36b6dcb2008-11-12 01:19:571581// Browser, TabStripModelObserver implementation:
1582
1583void Browser::TabInsertedAt(TabContents* contents,
1584 int index,
1585 bool foreground) {
1586 contents->set_delegate(this);
[email protected]ce3fa3c2009-04-20 19:55:571587 contents->controller().SetWindowID(session_id());
[email protected]36b6dcb2008-11-12 01:19:571588
1589 SyncHistoryWithTabs(tabstrip_model_.GetIndexOfTabContents(contents));
1590
[email protected]159f7762008-12-19 14:58:271591 // Make sure the loading state is updated correctly, otherwise the throbber
1592 // won't start if the page is loading.
1593 LoadingStateChanged(contents);
1594
[email protected]36b6dcb2008-11-12 01:19:571595 // If the tab crashes in the beforeunload or unload handler, it won't be
1596 // able to ack. But we know we can close it.
[email protected]0cb94102009-05-22 19:51:211597 registrar_.Add(this, NotificationType::TAB_CONTENTS_DISCONNECTED,
1598 Source<TabContents>(contents));
[email protected]36b6dcb2008-11-12 01:19:571599}
1600
1601void Browser::TabClosingAt(TabContents* contents, int index) {
[email protected]bfd04a62009-02-01 18:16:561602 NotificationService::current()->Notify(
1603 NotificationType::TAB_CLOSING,
[email protected]ce3fa3c2009-04-20 19:55:571604 Source<NavigationController>(&contents->controller()),
[email protected]bfd04a62009-02-01 18:16:561605 NotificationService::NoDetails());
[email protected]36b6dcb2008-11-12 01:19:571606
1607 // Sever the TabContents' connection back to us.
1608 contents->set_delegate(NULL);
1609}
1610
1611void Browser::TabDetachedAt(TabContents* contents, int index) {
[email protected]aacfcc72009-05-27 19:39:541612 // Save what the user's currently typing.
1613 window_->GetLocationBar()->SaveStateToContents(contents);
1614
[email protected]36b6dcb2008-11-12 01:19:571615 contents->set_delegate(NULL);
1616 if (!tabstrip_model_.closing_all())
1617 SyncHistoryWithTabs(0);
1618
1619 RemoveScheduledUpdatesFor(contents);
1620
[email protected]4801ecc2009-04-05 04:52:581621 if (find_bar_controller_.get() && index == tabstrip_model_.selected_index())
[email protected]57c6a652009-05-04 07:58:341622 find_bar_controller_->ChangeTabContents(NULL);
[email protected]4801ecc2009-04-05 04:52:581623
[email protected]0cb94102009-05-22 19:51:211624 registrar_.Remove(this, NotificationType::TAB_CONTENTS_DISCONNECTED,
1625 Source<TabContents>(contents));
[email protected]36b6dcb2008-11-12 01:19:571626}
1627
[email protected]85ff2c42009-05-29 21:22:031628void Browser::TabDeselectedAt(TabContents* contents, int index) {
1629 // Save what the user's currently typing, so it can be restored when we
1630 // switch back to this tab.
1631 window_->GetLocationBar()->SaveStateToContents(contents);
1632}
1633
[email protected]36b6dcb2008-11-12 01:19:571634void Browser::TabSelectedAt(TabContents* old_contents,
1635 TabContents* new_contents,
1636 int index,
1637 bool user_gesture) {
1638 DCHECK(old_contents != new_contents);
1639
1640 // If we have any update pending, do it now.
1641 if (!chrome_updater_factory_.empty() && old_contents)
1642 ProcessPendingUIUpdates();
1643
[email protected]36b6dcb2008-11-12 01:19:571644 // Propagate the profile to the location bar.
1645 UpdateToolbar(true);
1646
[email protected]64ff7942008-12-17 18:11:231647 // Update stop/go state.
[email protected]c3989812009-04-15 18:08:491648 UpdateStopGoState(new_contents->is_loading(), true);
[email protected]36b6dcb2008-11-12 01:19:571649
[email protected]84214982008-12-10 18:49:101650 // Update commands to reflect current state.
1651 UpdateCommandsForTabState();
[email protected]36b6dcb2008-11-12 01:19:571652
1653 // Reset the status bubble.
[email protected]be3877f2009-01-14 15:51:101654 StatusBubble* status_bubble = GetStatusBubble();
1655 if (status_bubble) {
1656 status_bubble->Hide();
[email protected]36b6dcb2008-11-12 01:19:571657
[email protected]be3877f2009-01-14 15:51:101658 // Show the loading state (if any).
1659 status_bubble->SetStatus(GetSelectedTabContents()->GetStatusText());
1660 }
[email protected]36b6dcb2008-11-12 01:19:571661
[email protected]4801ecc2009-04-05 04:52:581662 if (find_bar_controller_.get()) {
[email protected]57c6a652009-05-04 07:58:341663 find_bar_controller_->ChangeTabContents(new_contents);
[email protected]4801ecc2009-04-05 04:52:581664 find_bar_controller_->find_bar()->MoveWindowIfNecessary(gfx::Rect(),
1665 true);
1666 }
1667
[email protected]36b6dcb2008-11-12 01:19:571668 // Update sessions. Don't force creation of sessions. If sessions doesn't
1669 // exist, the change will be picked up by sessions when created.
1670 if (profile_->HasSessionService()) {
1671 SessionService* session_service = profile_->GetSessionService();
1672 if (session_service && !tabstrip_model_.closing_all()) {
[email protected]2d46c842008-11-14 19:24:311673 session_service->SetSelectedTabInWindow(
1674 session_id(), tabstrip_model_.selected_index());
[email protected]36b6dcb2008-11-12 01:19:571675 }
1676 }
1677}
1678
1679void Browser::TabMoved(TabContents* contents,
1680 int from_index,
[email protected]c8db09162009-07-13 23:48:481681 int to_index,
1682 bool pinned_state_changed) {
[email protected]36b6dcb2008-11-12 01:19:571683 DCHECK(from_index >= 0 && to_index >= 0);
1684 // Notify the history service.
1685 SyncHistoryWithTabs(std::min(from_index, to_index));
1686}
1687
[email protected]5c0e6482009-07-14 20:20:091688void Browser::TabPinnedStateChanged(TabContents* contents, int index) {
1689 if (!profile()->HasSessionService())
1690 return;
1691 SessionService* session_service = profile()->GetSessionService();
1692 if (session_service) {
1693 session_service->SetPinnedState(
1694 session_id(),
1695 GetTabContentsAt(index)->controller().session_id(),
1696 tabstrip_model_.IsTabPinned(index));
1697 }
1698}
1699
[email protected]36b6dcb2008-11-12 01:19:571700void Browser::TabStripEmpty() {
1701 // Close the frame after we return to the message loop (not immediately,
1702 // otherwise it will destroy this object before the stack has a chance to
1703 // cleanly unwind.)
1704 // Note: This will be called several times if TabStripEmpty is called several
1705 // times. This is because it does not close the window if tabs are
1706 // still present.
1707 // NOTE: If you change to be immediate (no invokeLater) then you'll need to
1708 // update BrowserList::CloseAllBrowsers.
1709 MessageLoop::current()->PostTask(FROM_HERE,
1710 method_factory_.NewRunnableMethod(&Browser::CloseFrame));
1711}
1712
1713///////////////////////////////////////////////////////////////////////////////
[email protected]e0c7c262009-04-23 23:09:431714// Browser, PageNavigator implementation:
1715void Browser::OpenURL(const GURL& url, const GURL& referrer,
1716 WindowOpenDisposition disposition,
1717 PageTransition::Type transition) {
1718 OpenURLFromTab(NULL, url, referrer, disposition, transition);
1719}
1720
1721///////////////////////////////////////////////////////////////////////////////
[email protected]36b6dcb2008-11-12 01:19:571722// Browser, TabContentsDelegate implementation:
initial.commit09911bf2008-07-26 23:55:291723
1724void Browser::OpenURLFromTab(TabContents* source,
[email protected]1f7d7e92009-06-02 20:55:041725 const GURL& url,
1726 const GURL& referrer,
initial.commit09911bf2008-07-26 23:55:291727 WindowOpenDisposition disposition,
[email protected]e38f40152008-09-12 23:08:301728 PageTransition::Type transition) {
[email protected]1f7d7e92009-06-02 20:55:041729 OpenURLAtIndex(source, url, referrer, disposition, transition, -1, false);
initial.commit09911bf2008-07-26 23:55:291730}
1731
1732void Browser::NavigationStateChanged(const TabContents* source,
1733 unsigned changed_flags) {
initial.commit09911bf2008-07-26 23:55:291734 // Only update the UI when something visible has changed.
[email protected]e83f1682008-09-07 23:57:401735 if (changed_flags)
initial.commit09911bf2008-07-26 23:55:291736 ScheduleUIUpdate(source, changed_flags);
1737
[email protected]84214982008-12-10 18:49:101738 // We don't schedule updates to commands since they will only change once per
1739 // navigation, so we don't have to worry about flickering.
[email protected]e83f1682008-09-07 23:57:401740 if (changed_flags & TabContents::INVALIDATE_URL)
[email protected]84214982008-12-10 18:49:101741 UpdateCommandsForTabState();
initial.commit09911bf2008-07-26 23:55:291742}
1743
initial.commit09911bf2008-07-26 23:55:291744void Browser::AddNewContents(TabContents* source,
1745 TabContents* new_contents,
1746 WindowOpenDisposition disposition,
1747 const gfx::Rect& initial_pos,
1748 bool user_gesture) {
1749 DCHECK(disposition != SAVE_TO_DISK); // No code for this yet
[email protected]b680ad22009-04-15 23:19:421750 DCHECK(disposition != CURRENT_TAB); // Can't create a new contents for the
1751 // current tab.
initial.commit09911bf2008-07-26 23:55:291752
1753 // If this is an application we can only have one tab so we need to process
[email protected]ebdcf9742009-01-23 05:25:281754 // this in tabbed browser window.
1755 if (tabstrip_model_.count() > 0 &&
initial.commit09911bf2008-07-26 23:55:291756 disposition != NEW_WINDOW && disposition != NEW_POPUP &&
[email protected]299dabd2008-11-19 02:27:161757 type_ != TYPE_NORMAL) {
initial.commit09911bf2008-07-26 23:55:291758 Browser* b = GetOrCreateTabbedBrowser();
1759 DCHECK(b);
1760 PageTransition::Type transition = PageTransition::LINK;
1761 // If we were called from an "installed webapp" we want to emulate the code
1762 // that is run from browser_init.cc for links from external applications.
1763 // This means we need to open the tab with the START PAGE transition.
1764 // AddNewContents doesn't support this but the TabStripModel's
1765 // AddTabContents method does.
[email protected]d5fbc002009-02-27 22:12:581766 if (type_ & TYPE_APP)
initial.commit09911bf2008-07-26 23:55:291767 transition = PageTransition::START_PAGE;
[email protected]4d34e2e2009-05-26 22:55:281768 b->tabstrip_model()->AddTabContents(new_contents, -1, false, transition,
1769 true);
[email protected]ebdcf9742009-01-23 05:25:281770 b->window()->Show();
initial.commit09911bf2008-07-26 23:55:291771 return;
1772 }
1773
1774 if (disposition == NEW_POPUP) {
1775 BuildPopupWindow(source, new_contents, initial_pos);
1776 } else if (disposition == NEW_WINDOW) {
[email protected]15952e462008-11-14 00:29:051777 Browser* browser = Browser::Create(profile_);
1778 browser->AddNewContents(source, new_contents, NEW_FOREGROUND_TAB,
1779 initial_pos, user_gesture);
1780 browser->window()->Show();
initial.commit09911bf2008-07-26 23:55:291781 } else if (disposition != SUPPRESS_OPEN) {
[email protected]4d34e2e2009-05-26 22:55:281782 tabstrip_model_.AddTabContents(new_contents, -1, false,
1783 PageTransition::LINK,
initial.commit09911bf2008-07-26 23:55:291784 disposition == NEW_FOREGROUND_TAB);
1785 }
1786}
1787
initial.commit09911bf2008-07-26 23:55:291788void Browser::ActivateContents(TabContents* contents) {
1789 tabstrip_model_.SelectTabContentsAt(
1790 tabstrip_model_.GetIndexOfTabContents(contents), false);
[email protected]f3e99e32008-07-30 04:48:391791 window_->Activate();
initial.commit09911bf2008-07-26 23:55:291792}
1793
initial.commit09911bf2008-07-26 23:55:291794void Browser::LoadingStateChanged(TabContents* source) {
[email protected]afb73882008-11-14 22:40:441795 window_->UpdateLoadingAnimations(tabstrip_model_.TabsAreLoading());
[email protected]f3e99e32008-07-30 04:48:391796 window_->UpdateTitleBar();
initial.commit09911bf2008-07-26 23:55:291797
initial.commit09911bf2008-07-26 23:55:291798 if (source == GetSelectedTabContents()) {
[email protected]c3989812009-04-15 18:08:491799 UpdateStopGoState(source->is_loading(), false);
[email protected]be3877f2009-01-14 15:51:101800 if (GetStatusBubble())
1801 GetStatusBubble()->SetStatus(GetSelectedTabContents()->GetStatusText());
initial.commit09911bf2008-07-26 23:55:291802 }
1803}
1804
1805void Browser::CloseContents(TabContents* source) {
[email protected]04b4a6c2008-08-02 00:44:471806 if (is_attempting_to_close_browser_) {
1807 // If we're trying to close the browser, just clear the state related to
[email protected]adf650f2008-12-09 16:10:061808 // waiting for unload to fire. Don't actually try to close the tab as it
[email protected]04b4a6c2008-08-02 00:44:471809 // will go down the slow shutdown path instead of the fast path of killing
1810 // all the renderer processes.
[email protected]8a2ce5a2008-08-11 23:43:081811 ClearUnloadState(source);
[email protected]04b4a6c2008-08-02 00:44:471812 return;
1813 }
1814
initial.commit09911bf2008-07-26 23:55:291815 int index = tabstrip_model_.GetIndexOfTabContents(source);
1816 if (index == TabStripModel::kNoTab) {
1817 NOTREACHED() << "CloseContents called for tab not in our strip";
1818 return;
1819 }
1820 tabstrip_model_.CloseTabContentsAt(index);
1821}
1822
[email protected]15e8abe2008-08-20 22:40:401823void Browser::MoveContents(TabContents* source, const gfx::Rect& pos) {
[email protected]d5fbc002009-02-27 22:12:581824 if ((type() & TYPE_POPUP) == 0) {
initial.commit09911bf2008-07-26 23:55:291825 NOTREACHED() << "moving invalid browser type";
1826 return;
1827 }
[email protected]2d46c842008-11-14 19:24:311828 window_->SetBounds(pos);
initial.commit09911bf2008-07-26 23:55:291829}
1830
[email protected]b6c874582009-05-08 19:38:311831void Browser::DetachContents(TabContents* source) {
1832 int index = tabstrip_model_.GetIndexOfTabContents(source);
1833 if (index >= 0)
1834 tabstrip_model_.DetachTabContentsAt(index);
1835}
1836
initial.commit09911bf2008-07-26 23:55:291837bool Browser::IsPopup(TabContents* source) {
1838 // A non-tabbed BROWSER is an unconstrained popup.
[email protected]d5fbc002009-02-27 22:12:581839 return (type() & TYPE_POPUP);
initial.commit09911bf2008-07-26 23:55:291840}
1841
[email protected]36b6dcb2008-11-12 01:19:571842void Browser::ToolbarSizeChanged(TabContents* source, bool is_animating) {
1843 if (source == GetSelectedTabContents() || source == NULL) {
1844 // This will refresh the shelf if needed.
1845 window_->SelectedTabToolbarSizeChanged(is_animating);
1846 }
1847}
1848
1849void Browser::URLStarredChanged(TabContents* source, bool starred) {
1850 if (source == GetSelectedTabContents())
[email protected]b7ca4e62009-01-23 20:37:291851 window_->SetStarredState(starred);
[email protected]36b6dcb2008-11-12 01:19:571852}
1853
[email protected]b6406032009-03-19 15:10:151854void Browser::ContentsMouseEvent(TabContents* source, bool motion) {
[email protected]be3877f2009-01-14 15:51:101855 if (!GetStatusBubble())
1856 return;
1857
[email protected]36b6dcb2008-11-12 01:19:571858 if (source == GetSelectedTabContents()) {
[email protected]b6406032009-03-19 15:10:151859 if (motion) {
[email protected]36b6dcb2008-11-12 01:19:571860 GetStatusBubble()->MouseMoved();
[email protected]b6406032009-03-19 15:10:151861 } else {
[email protected]36b6dcb2008-11-12 01:19:571862 GetStatusBubble()->SetURL(GURL(), std::wstring());
1863 }
1864 }
1865}
1866
1867void Browser::UpdateTargetURL(TabContents* source, const GURL& url) {
[email protected]be3877f2009-01-14 15:51:101868 if (!GetStatusBubble())
1869 return;
1870
[email protected]36b6dcb2008-11-12 01:19:571871 if (source == GetSelectedTabContents()) {
1872 PrefService* prefs = profile_->GetPrefs();
1873 GetStatusBubble()->SetURL(url, prefs->GetString(prefs::kAcceptLanguages));
1874 }
1875}
1876
[email protected]3a6a3b62009-05-27 21:36:201877void Browser::UpdateDownloadShelfVisibility(bool visible) {
1878 GetStatusBubble()->UpdateDownloadShelfVisibility(visible);
1879}
1880
[email protected]36b6dcb2008-11-12 01:19:571881void Browser::ContentsZoomChange(bool zoom_in) {
[email protected]1fc025202009-01-20 23:03:141882 ExecuteCommand(zoom_in ? IDC_ZOOM_PLUS : IDC_ZOOM_MINUS);
[email protected]36b6dcb2008-11-12 01:19:571883}
1884
[email protected]7e383692009-06-12 19:14:541885void Browser::TabContentsFocused(TabContents* tab_content) {
1886 window_->TabContentsFocused(tab_content);
1887}
1888
[email protected]36b6dcb2008-11-12 01:19:571889bool Browser::IsApplication() const {
[email protected]d5fbc002009-02-27 22:12:581890 return (type_ & TYPE_APP) != 0;
[email protected]36b6dcb2008-11-12 01:19:571891}
1892
1893void Browser::ConvertContentsToApplication(TabContents* contents) {
[email protected]ce3fa3c2009-04-20 19:55:571894 const GURL& url = contents->controller().GetActiveEntry()->url();
[email protected]0303f31c2009-02-02 06:42:051895 std::wstring app_name = ComputeApplicationNameFromURL(url);
[email protected]36b6dcb2008-11-12 01:19:571896 RegisterAppPrefs(app_name);
1897
[email protected]b6c874582009-05-08 19:38:311898 DetachContents(contents);
[email protected]d5fbc002009-02-27 22:12:581899 Browser* browser = Browser::CreateForApp(app_name, profile_, false);
[email protected]15952e462008-11-14 00:29:051900 browser->tabstrip_model()->AppendTabContents(contents, true);
[email protected]80d96fa2009-06-10 22:34:511901 browser->GetSelectedTabContents()->render_view_host()->SetRendererPrefs(
1902 browser->GetSelectedTabContents()->delegate()->GetRendererPrefs());
[email protected]15952e462008-11-14 00:29:051903 browser->window()->Show();
[email protected]36b6dcb2008-11-12 01:19:571904}
1905
[email protected]36b6dcb2008-11-12 01:19:571906bool Browser::ShouldDisplayURLField() {
1907 return !IsApplication();
1908}
1909
1910void Browser::BeforeUnloadFired(TabContents* tab,
1911 bool proceed,
1912 bool* proceed_to_fire_unload) {
1913 if (!is_attempting_to_close_browser_) {
1914 *proceed_to_fire_unload = proceed;
1915 return;
1916 }
1917
1918 if (!proceed) {
1919 CancelWindowClose();
1920 *proceed_to_fire_unload = false;
1921 return;
1922 }
1923
[email protected]06b42f032008-12-03 18:43:051924 if (RemoveFromSet(&tabs_needing_before_unload_fired_, tab)) {
[email protected]2d46c842008-11-14 19:24:311925 // Now that beforeunload has fired, put the tab on the queue to fire
1926 // unload.
[email protected]06b42f032008-12-03 18:43:051927 tabs_needing_unload_fired_.insert(tab);
[email protected]36b6dcb2008-11-12 01:19:571928 ProcessPendingTabs();
[email protected]adf650f2008-12-09 16:10:061929 // We want to handle firing the unload event ourselves since we want to
[email protected]36b6dcb2008-11-12 01:19:571930 // fire all the beforeunload events before attempting to fire the unload
1931 // events should the user cancel closing the browser.
1932 *proceed_to_fire_unload = false;
1933 return;
1934 }
1935
1936 *proceed_to_fire_unload = true;
1937}
1938
[email protected]f21c613a2009-02-12 14:46:171939gfx::Rect Browser::GetRootWindowResizerRect() const {
1940 return window_->GetRootWindowResizerRect();
1941}
1942
[email protected]4acc19a62009-04-03 03:05:111943void Browser::ShowHtmlDialog(HtmlDialogUIDelegate* delegate,
[email protected]322f3ff2009-05-22 16:19:541944 gfx::NativeWindow parent_window) {
[email protected]2d46c842008-11-14 19:24:311945 window_->ShowHTMLDialog(delegate, parent_window);
initial.commit09911bf2008-07-26 23:55:291946}
1947
[email protected]4bcefee2009-01-29 15:57:571948void Browser::SetFocusToLocationBar() {
[email protected]1a380622009-02-17 17:33:131949 // Two differences between this and FocusLocationBar():
1950 // (1) This doesn't get recorded in user metrics, since it's called
1951 // internally.
1952 // (2) This checks whether the location bar can be focused, and if not, clears
1953 // the focus. FocusLocationBar() is only reached when the location bar is
1954 // focusable, but this may be reached at other times, e.g. while in
1955 // fullscreen mode, where we need to leave focus in a consistent state.
1956 window_->SetFocusToLocationBar();
[email protected]4bcefee2009-01-29 15:57:571957}
1958
[email protected]7d5925a2009-03-03 02:59:121959void Browser::RenderWidgetShowing() {
1960 window_->DisableInactiveFrame();
1961}
[email protected]a239c3f2009-02-17 22:13:191962
[email protected]0a2aeb82009-05-15 21:52:481963int Browser::GetExtraRenderViewHeight() const {
1964 return window_->GetExtraRenderViewHeight();
1965}
1966
[email protected]d0cc9fb52009-06-23 02:26:161967void Browser::OnStartDownload(DownloadItem* download) {
1968 if (!window())
1969 return;
1970
1971 // GetDownloadShelf creates the download shelf if it was not yet created.
1972 window()->GetDownloadShelf()->AddDownload(new DownloadItemModel(download));
1973
1974// TODO(port): port for mac.
1975#if defined(OS_WIN) || defined(OS_LINUX)
1976 // Don't show the animation for "Save file" downloads.
1977 if (download->total_bytes() > 0) {
1978 TabContents* current_tab = GetSelectedTabContents();
1979 // We make this check for the case of minimized windows, unit tests, etc.
1980 if (platform_util::IsVisible(current_tab->GetNativeView()) &&
1981 Animation::ShouldRenderRichAnimation())
1982 DownloadStartedAnimation::Show(current_tab);
1983 }
1984#endif
1985}
1986
1987void Browser::ConfirmAddSearchProvider(const TemplateURL* template_url,
1988 Profile* profile) {
1989 window()->ConfirmAddSearchProvider(template_url, profile);
1990}
1991
[email protected]4d677202009-07-19 07:37:121992void Browser::ShowPageInfo(gfx::NativeView parent,
1993 Profile* profile,
1994 const GURL& url,
1995 const NavigationEntry::SSLStatus& ssl,
1996 bool show_history) {
1997 window()->ShowPageInfo(parent, profile, url, ssl, show_history);
1998}
1999
[email protected]36b6dcb2008-11-12 01:19:572000///////////////////////////////////////////////////////////////////////////////
2001// Browser, SelectFileDialog::Listener implementation:
2002
[email protected]561abe62009-04-06 18:08:342003void Browser::FileSelected(const FilePath& path, int index, void* params) {
[email protected]72cbd322009-04-07 10:17:122004 GURL file_url = net::FilePathToFileURL(path);
[email protected]36b6dcb2008-11-12 01:19:572005 if (!file_url.is_empty())
2006 OpenURL(file_url, GURL(), CURRENT_TAB, PageTransition::TYPED);
2007}
2008
[email protected]a239c3f2009-02-17 22:13:192009
[email protected]36b6dcb2008-11-12 01:19:572010///////////////////////////////////////////////////////////////////////////////
2011// Browser, NotificationObserver implementation:
2012
initial.commit09911bf2008-07-26 23:55:292013void Browser::Observe(NotificationType type,
2014 const NotificationSource& source,
2015 const NotificationDetails& details) {
[email protected]bfd04a62009-02-01 18:16:562016 switch (type.value) {
[email protected]57c6a652009-05-04 07:58:342017 case NotificationType::TAB_CONTENTS_DISCONNECTED:
[email protected]e83f1682008-09-07 23:57:402018 if (is_attempting_to_close_browser_) {
2019 // Need to do this asynchronously as it will close the tab, which is
2020 // currently on the call stack above us.
2021 MessageLoop::current()->PostTask(FROM_HERE,
2022 method_factory_.NewRunnableMethod(&Browser::ClearUnloadState,
2023 Source<TabContents>(source).ptr()));
2024 }
2025 break;
2026
[email protected]b4a19ea2009-03-17 10:08:242027 case NotificationType::SSL_VISIBLE_STATE_CHANGED:
[email protected]e83f1682008-09-07 23:57:402028 // When the current tab's SSL state changes, we need to update the URL
[email protected]90e8d062008-09-08 02:26:322029 // bar to reflect the new state. Note that it's possible for the selected
2030 // tab contents to be NULL. This is because we listen for all sources
2031 // (NavigationControllers) for convenience, so the notification could
2032 // actually be for a different window while we're doing asynchronous
2033 // closing of this one.
2034 if (GetSelectedTabContents() &&
[email protected]ce3fa3c2009-04-20 19:55:572035 &GetSelectedTabContents()->controller() ==
[email protected]e83f1682008-09-07 23:57:402036 Source<NavigationController>(source).ptr())
[email protected]36b6dcb2008-11-12 01:19:572037 UpdateToolbar(false);
[email protected]e83f1682008-09-07 23:57:402038 break;
2039
[email protected]894bb502009-05-21 22:39:572040 case NotificationType::EXTENSION_UNLOADED: {
2041 // Close any tabs from the unloaded extension.
2042 Extension* extension = Details<Extension>(details).ptr();
2043 for (int i = 0; i < tabstrip_model_.count(); i++) {
2044 TabContents* tc = tabstrip_model_.GetTabContentsAt(i);
2045 if (tc->GetURL().SchemeIs(chrome::kExtensionScheme) &&
2046 tc->GetURL().host() == extension->id()) {
2047 CloseTabContents(tc);
2048 return;
2049 }
2050 }
2051 break;
2052 }
2053
[email protected]e001d412009-06-26 20:53:252054 case NotificationType::BROWSER_THEME_CHANGED:
2055 window()->UserChangedTheme();
2056 break;
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);
[email protected]e662ade2009-06-08 18:20:142098 command_updater_.UpdateCommandEnabled(IDC_PRINT, true);
[email protected]1fc025202009-01-20 23:03:142099 command_updater_.UpdateCommandEnabled(IDC_ENCODING_AUTO_DETECT, true);
2100 command_updater_.UpdateCommandEnabled(IDC_ENCODING_UTF8, true);
2101 command_updater_.UpdateCommandEnabled(IDC_ENCODING_UTF16LE, true);
2102 command_updater_.UpdateCommandEnabled(IDC_ENCODING_ISO88591, true);
2103 command_updater_.UpdateCommandEnabled(IDC_ENCODING_WINDOWS1252, true);
2104 command_updater_.UpdateCommandEnabled(IDC_ENCODING_GBK, true);
2105 command_updater_.UpdateCommandEnabled(IDC_ENCODING_GB18030, true);
2106 command_updater_.UpdateCommandEnabled(IDC_ENCODING_BIG5HKSCS, true);
2107 command_updater_.UpdateCommandEnabled(IDC_ENCODING_BIG5, true);
2108 command_updater_.UpdateCommandEnabled(IDC_ENCODING_THAI, true);
2109 command_updater_.UpdateCommandEnabled(IDC_ENCODING_KOREAN, true);
2110 command_updater_.UpdateCommandEnabled(IDC_ENCODING_SHIFTJIS, true);
2111 command_updater_.UpdateCommandEnabled(IDC_ENCODING_ISO2022JP, true);
2112 command_updater_.UpdateCommandEnabled(IDC_ENCODING_EUCJP, true);
2113 command_updater_.UpdateCommandEnabled(IDC_ENCODING_ISO885915, true);
2114 command_updater_.UpdateCommandEnabled(IDC_ENCODING_MACINTOSH, true);
2115 command_updater_.UpdateCommandEnabled(IDC_ENCODING_ISO88592, true);
2116 command_updater_.UpdateCommandEnabled(IDC_ENCODING_WINDOWS1250, true);
2117 command_updater_.UpdateCommandEnabled(IDC_ENCODING_ISO88595, true);
2118 command_updater_.UpdateCommandEnabled(IDC_ENCODING_WINDOWS1251, true);
2119 command_updater_.UpdateCommandEnabled(IDC_ENCODING_KOI8R, true);
2120 command_updater_.UpdateCommandEnabled(IDC_ENCODING_KOI8U, true);
2121 command_updater_.UpdateCommandEnabled(IDC_ENCODING_ISO88597, true);
2122 command_updater_.UpdateCommandEnabled(IDC_ENCODING_WINDOWS1253, true);
2123 command_updater_.UpdateCommandEnabled(IDC_ENCODING_ISO88594, true);
2124 command_updater_.UpdateCommandEnabled(IDC_ENCODING_ISO885913, true);
2125 command_updater_.UpdateCommandEnabled(IDC_ENCODING_WINDOWS1257, true);
2126 command_updater_.UpdateCommandEnabled(IDC_ENCODING_ISO88593, true);
2127 command_updater_.UpdateCommandEnabled(IDC_ENCODING_ISO885910, true);
2128 command_updater_.UpdateCommandEnabled(IDC_ENCODING_ISO885914, true);
2129 command_updater_.UpdateCommandEnabled(IDC_ENCODING_ISO885916, true);
2130 command_updater_.UpdateCommandEnabled(IDC_ENCODING_WINDOWS1254, true);
2131 command_updater_.UpdateCommandEnabled(IDC_ENCODING_ISO88596, true);
2132 command_updater_.UpdateCommandEnabled(IDC_ENCODING_WINDOWS1256, true);
2133 command_updater_.UpdateCommandEnabled(IDC_ENCODING_ISO88598, true);
[email protected]e13271f2009-03-07 00:26:002134 command_updater_.UpdateCommandEnabled(IDC_ENCODING_ISO88598I, true);
[email protected]1fc025202009-01-20 23:03:142135 command_updater_.UpdateCommandEnabled(IDC_ENCODING_WINDOWS1255, true);
2136 command_updater_.UpdateCommandEnabled(IDC_ENCODING_WINDOWS1258, true);
[email protected]84214982008-12-10 18:49:102137
2138 // Clipboard commands
[email protected]1fc025202009-01-20 23:03:142139 command_updater_.UpdateCommandEnabled(IDC_CUT, true);
2140 command_updater_.UpdateCommandEnabled(IDC_COPY, true);
[email protected]1fc025202009-01-20 23:03:142141 command_updater_.UpdateCommandEnabled(IDC_PASTE, true);
[email protected]84214982008-12-10 18:49:102142
[email protected]63b02932009-06-05 09:40:512143 // Find-in-page
2144 command_updater_.UpdateCommandEnabled(IDC_FIND, true);
2145 command_updater_.UpdateCommandEnabled(IDC_FIND_NEXT, true);
2146 command_updater_.UpdateCommandEnabled(IDC_FIND_PREVIOUS, true);
2147
2148 // Zoom
2149 command_updater_.UpdateCommandEnabled(IDC_ZOOM_MENU, true);
2150 command_updater_.UpdateCommandEnabled(IDC_ZOOM_PLUS, true);
2151 command_updater_.UpdateCommandEnabled(IDC_ZOOM_NORMAL, true);
2152 command_updater_.UpdateCommandEnabled(IDC_ZOOM_MINUS, true);
2153
[email protected]84214982008-12-10 18:49:102154 // Show various bits of UI
[email protected]1fc025202009-01-20 23:03:142155 command_updater_.UpdateCommandEnabled(IDC_OPEN_FILE, true);
2156 command_updater_.UpdateCommandEnabled(IDC_CREATE_SHORTCUTS, false);
[email protected]e662ade2009-06-08 18:20:142157 command_updater_.UpdateCommandEnabled(IDC_JS_CONSOLE, true);
[email protected]1fc025202009-01-20 23:03:142158 command_updater_.UpdateCommandEnabled(IDC_TASK_MANAGER, true);
2159 command_updater_.UpdateCommandEnabled(IDC_SELECT_PROFILE, true);
2160 command_updater_.UpdateCommandEnabled(IDC_SHOW_HISTORY, true);
2161 command_updater_.UpdateCommandEnabled(IDC_SHOW_BOOKMARK_MANAGER, true);
2162 command_updater_.UpdateCommandEnabled(IDC_SHOW_DOWNLOADS, true);
2163 command_updater_.UpdateCommandEnabled(IDC_HELP_PAGE, true);
[email protected]16779842009-07-08 23:45:292164#if defined(OS_CHROMEOS)
[email protected]be715072009-07-07 15:43:202165 command_updater_.UpdateCommandEnabled(IDC_CONTROL_PANEL, true);
2166#endif
[email protected]64ff7942008-12-17 18:11:232167
2168 // Initialize other commands based on the window type.
2169 {
2170 bool normal_window = type() == TYPE_NORMAL;
2171
2172 // Navigation commands
[email protected]1fc025202009-01-20 23:03:142173 command_updater_.UpdateCommandEnabled(IDC_HOME, normal_window);
[email protected]64ff7942008-12-17 18:11:232174
2175 // Window management commands
[email protected]1fc025202009-01-20 23:03:142176 command_updater_.UpdateCommandEnabled(IDC_SELECT_NEXT_TAB, normal_window);
2177 command_updater_.UpdateCommandEnabled(IDC_SELECT_PREVIOUS_TAB,
2178 normal_window);
2179 command_updater_.UpdateCommandEnabled(IDC_SELECT_TAB_0, normal_window);
2180 command_updater_.UpdateCommandEnabled(IDC_SELECT_TAB_1, normal_window);
2181 command_updater_.UpdateCommandEnabled(IDC_SELECT_TAB_2, normal_window);
2182 command_updater_.UpdateCommandEnabled(IDC_SELECT_TAB_3, normal_window);
2183 command_updater_.UpdateCommandEnabled(IDC_SELECT_TAB_4, normal_window);
2184 command_updater_.UpdateCommandEnabled(IDC_SELECT_TAB_5, normal_window);
2185 command_updater_.UpdateCommandEnabled(IDC_SELECT_TAB_6, normal_window);
2186 command_updater_.UpdateCommandEnabled(IDC_SELECT_TAB_7, normal_window);
2187 command_updater_.UpdateCommandEnabled(IDC_SELECT_LAST_TAB, normal_window);
2188 command_updater_.UpdateCommandEnabled(IDC_RESTORE_TAB,
[email protected]64ff7942008-12-17 18:11:232189 normal_window && !profile_->IsOffTheRecord());
[email protected]e662ade2009-06-08 18:20:142190
2191 // Page-related commands
[email protected]63b02932009-06-05 09:40:512192 command_updater_.UpdateCommandEnabled(IDC_STAR, normal_window);
[email protected]e662ade2009-06-08 18:20:142193
2194 // Clipboard commands
[email protected]63b02932009-06-05 09:40:512195 command_updater_.UpdateCommandEnabled(IDC_COPY_URL, normal_window);
[email protected]d5c99b172009-02-25 17:09:212196
2197 // Show various bits of UI
[email protected]7fd4cc32009-04-15 23:17:372198 command_updater_.UpdateCommandEnabled(IDC_CLEAR_BROWSING_DATA,
2199 normal_window);
[email protected]64ff7942008-12-17 18:11:232200 }
[email protected]9282cea2009-02-18 18:49:002201
2202 // Initialize other commands whose state changes based on fullscreen mode.
2203 UpdateCommandsForFullscreenMode(false);
[email protected]36b6dcb2008-11-12 01:19:572204}
2205
[email protected]84214982008-12-10 18:49:102206void Browser::UpdateCommandsForTabState() {
[email protected]c7c42332008-11-15 01:10:542207 TabContents* current_tab = GetSelectedTabContents();
[email protected]64ff7942008-12-17 18:11:232208 if (!current_tab) // May be NULL during tab restore.
[email protected]d8375fd2008-11-25 22:45:392209 return;
[email protected]d8375fd2008-11-25 22:45:392210
[email protected]84214982008-12-10 18:49:102211 // Navigation commands
[email protected]ce3fa3c2009-04-20 19:55:572212 NavigationController& nc = current_tab->controller();
2213 command_updater_.UpdateCommandEnabled(IDC_BACK, nc.CanGoBack());
2214 command_updater_.UpdateCommandEnabled(IDC_FORWARD, nc.CanGoForward());
initial.commit09911bf2008-07-26 23:55:292215
[email protected]84214982008-12-10 18:49:102216 // Window management commands
[email protected]1fc025202009-01-20 23:03:142217 command_updater_.UpdateCommandEnabled(IDC_DUPLICATE_TAB,
[email protected]63b02932009-06-05 09:40:512218 !(type() & TYPE_APP) && CanDuplicateContentsAt(selected_index()));
[email protected]84214982008-12-10 18:49:102219
[email protected]57c6a652009-05-04 07:58:342220 // Current navigation entry, may be NULL.
2221 NavigationEntry* active_entry = current_tab->controller().GetActiveEntry();
[email protected]2bfd94d2009-04-29 20:32:032222 bool is_source_viewable =
[email protected]2bfd94d2009-04-29 20:32:032223 net::IsSupportedNonImageMimeType(
[email protected]57c6a652009-05-04 07:58:342224 current_tab->contents_mime_type().c_str());
[email protected]84214982008-12-10 18:49:102225
[email protected]57c6a652009-05-04 07:58:342226 // Page-related commands
[email protected]57c6a652009-05-04 07:58:342227 window_->SetStarredState(current_tab->is_starred());
2228 // View-source should not be enabled if already in view-source mode or
2229 // the source is not viewable.
2230 command_updater_.UpdateCommandEnabled(IDC_VIEW_SOURCE,
2231 active_entry && !active_entry->IsViewSourceMode() &&
2232 is_source_viewable);
[email protected]57c6a652009-05-04 07:58:342233 command_updater_.UpdateCommandEnabled(IDC_SAVE_PAGE,
2234 SavePackage::IsSavableURL(current_tab->GetURL()));
2235 command_updater_.UpdateCommandEnabled(IDC_ENCODING_MENU,
2236 SavePackage::IsSavableContents(current_tab->contents_mime_type()) &&
2237 SavePackage::IsSavableURL(current_tab->GetURL()));
[email protected]6de74452009-02-25 18:04:592238
[email protected]57c6a652009-05-04 07:58:342239 // Show various bits of UI
[email protected]57c6a652009-05-04 07:58:342240 command_updater_.UpdateCommandEnabled(IDC_CREATE_SHORTCUTS,
2241 !current_tab->GetFavIcon().isNull());
initial.commit09911bf2008-07-26 23:55:292242}
2243
[email protected]9282cea2009-02-18 18:49:002244void Browser::UpdateCommandsForFullscreenMode(bool is_fullscreen) {
2245 const bool show_main_ui = (type() == TYPE_NORMAL) && !is_fullscreen;
2246
2247 // Navigation commands
2248 command_updater_.UpdateCommandEnabled(IDC_OPEN_CURRENT_URL, show_main_ui);
2249
2250 // Window management commands
2251 command_updater_.UpdateCommandEnabled(IDC_PROFILE_MENU, show_main_ui);
2252 command_updater_.UpdateCommandEnabled(IDC_SHOW_AS_TAB,
[email protected]d5fbc002009-02-27 22:12:582253 (type() & TYPE_POPUP) && !is_fullscreen);
[email protected]9282cea2009-02-18 18:49:002254
2255 // Focus various bits of UI
2256 command_updater_.UpdateCommandEnabled(IDC_FOCUS_TOOLBAR, show_main_ui);
2257 command_updater_.UpdateCommandEnabled(IDC_FOCUS_LOCATION, show_main_ui);
2258 command_updater_.UpdateCommandEnabled(IDC_FOCUS_SEARCH, show_main_ui);
2259
2260 // Show various bits of UI
2261 command_updater_.UpdateCommandEnabled(IDC_DEVELOPER_MENU, show_main_ui);
[email protected]9282cea2009-02-18 18:49:002262 command_updater_.UpdateCommandEnabled(IDC_NEW_PROFILE, show_main_ui);
2263 command_updater_.UpdateCommandEnabled(IDC_REPORT_BUG, show_main_ui);
2264 command_updater_.UpdateCommandEnabled(IDC_SHOW_BOOKMARK_BAR, show_main_ui);
[email protected]9282cea2009-02-18 18:49:002265 command_updater_.UpdateCommandEnabled(IDC_IMPORT_SETTINGS, show_main_ui);
2266 command_updater_.UpdateCommandEnabled(IDC_OPTIONS, show_main_ui);
2267 command_updater_.UpdateCommandEnabled(IDC_EDIT_SEARCH_ENGINES, show_main_ui);
2268 command_updater_.UpdateCommandEnabled(IDC_VIEW_PASSWORDS, show_main_ui);
2269 command_updater_.UpdateCommandEnabled(IDC_ABOUT, show_main_ui);
2270}
2271
[email protected]c3989812009-04-15 18:08:492272void Browser::UpdateStopGoState(bool is_loading, bool force) {
2273 window_->UpdateStopGoState(is_loading, force);
[email protected]1fc025202009-01-20 23:03:142274 command_updater_.UpdateCommandEnabled(IDC_GO, !is_loading);
2275 command_updater_.UpdateCommandEnabled(IDC_STOP, is_loading);
[email protected]64ff7942008-12-17 18:11:232276}
2277
[email protected]d938aed92009-01-22 19:49:332278
[email protected]36b6dcb2008-11-12 01:19:572279///////////////////////////////////////////////////////////////////////////////
2280// Browser, UI update coalescing and handling (private):
2281
2282void Browser::UpdateToolbar(bool should_restore_state) {
2283 window_->UpdateToolbar(GetSelectedTabContents(), should_restore_state);
initial.commit09911bf2008-07-26 23:55:292284}
2285
[email protected]36b6dcb2008-11-12 01:19:572286void Browser::ScheduleUIUpdate(const TabContents* source,
2287 unsigned changed_flags) {
[email protected]2b4355c2009-04-04 17:55:462288 // Do some synchronous updates.
[email protected]36b6dcb2008-11-12 01:19:572289 if (changed_flags & TabContents::INVALIDATE_URL &&
2290 source == GetSelectedTabContents()) {
2291 // Only update the URL for the current tab. Note that we do not update
2292 // the navigation commands since those would have already been updated
2293 // synchronously by NavigationStateChanged.
2294 UpdateToolbar(false);
[email protected]36b6dcb2008-11-12 01:19:572295 }
[email protected]2b4355c2009-04-04 17:55:462296 if (changed_flags & TabContents::INVALIDATE_LOAD && source) {
2297 // Update the loading state synchronously. This is so the throbber will
2298 // immediately start/stop, which gives a more snappy feel. We want to do
2299 // this for any tab so they start & stop quickly, but the source can be
2300 // NULL, so we have to check for that.
2301 tabstrip_model_.UpdateTabContentsStateAt(
[email protected]902cdf772009-05-06 15:08:122302 tabstrip_model_.GetIndexOfController(&source->controller()), true);
[email protected]2b4355c2009-04-04 17:55:462303 }
2304
2305 // If the only updates were synchronously handled above, we're done.
2306 if (changed_flags ==
2307 (TabContents::INVALIDATE_URL | TabContents::INVALIDATE_LOAD))
2308 return;
[email protected]36b6dcb2008-11-12 01:19:572309
2310 // Save the dirty bits.
2311 scheduled_updates_.push_back(UIUpdate(source, changed_flags));
2312
2313 if (chrome_updater_factory_.empty()) {
2314 // No task currently scheduled, start another.
2315 MessageLoop::current()->PostDelayedTask(FROM_HERE,
2316 chrome_updater_factory_.NewRunnableMethod(
2317 &Browser::ProcessPendingUIUpdates),
2318 kUIUpdateCoalescingTimeMS);
2319 }
2320}
2321
2322void Browser::ProcessPendingUIUpdates() {
2323#ifndef NDEBUG
2324 // Validate that all tabs we have pending updates for exist. This is scary
2325 // because the pending list must be kept in sync with any detached or
2326 // deleted tabs. This code does not dereference any TabContents pointers.
2327 for (size_t i = 0; i < scheduled_updates_.size(); i++) {
2328 bool found = false;
2329 for (int tab = 0; tab < tab_count(); tab++) {
[email protected]ce3fa3c2009-04-20 19:55:572330 if (&GetTabContentsAt(tab)->controller() ==
2331 &scheduled_updates_[i].source->controller()) {
[email protected]36b6dcb2008-11-12 01:19:572332 found = true;
2333 break;
2334 }
2335 }
2336 DCHECK(found);
2337 }
2338#endif
2339
2340 chrome_updater_factory_.RevokeAll();
2341
[email protected]2d46c842008-11-14 19:24:312342 // We could have many updates for the same thing in the queue. This map
2343 // tracks the bits of the stuff we've already updated for each TabContents so
2344 // we don't update again.
[email protected]36b6dcb2008-11-12 01:19:572345 typedef std::map<const TabContents*, unsigned> UpdateTracker;
2346 UpdateTracker updated_stuff;
2347
2348 for (size_t i = 0; i < scheduled_updates_.size(); i++) {
2349 // Do not dereference |contents|, it may be out-of-date!
2350 const TabContents* contents = scheduled_updates_[i].source;
2351 unsigned flags = scheduled_updates_[i].changed_flags;
2352
2353 // Remove any bits we have already updated, and save the new bits.
2354 UpdateTracker::iterator updated = updated_stuff.find(contents);
2355 if (updated != updated_stuff.end()) {
2356 // Turn off bits already set.
2357 flags &= ~updated->second;
2358 if (!flags)
2359 continue;
2360
2361 updated->second |= flags;
2362 } else {
2363 updated_stuff[contents] = flags;
2364 }
2365
[email protected]f7f3a5f2009-05-01 22:02:342366 if (flags & TabContents::INVALIDATE_PAGE_ACTIONS)
2367 window()->GetLocationBar()->UpdatePageActions();
2368
[email protected]36b6dcb2008-11-12 01:19:572369 // Updating the URL happens synchronously in ScheduleUIUpdate.
[email protected]ba8c48212009-05-12 21:20:402370 TabContents* selected_tab = GetSelectedTabContents();
[email protected]4d34e2e2009-05-26 22:55:282371 if (selected_tab &&
2372 flags & TabContents::INVALIDATE_LOAD && GetStatusBubble()) {
[email protected]ba8c48212009-05-12 21:20:402373 GetStatusBubble()->SetStatus(selected_tab->GetStatusText());
[email protected]4d34e2e2009-05-26 22:55:282374 }
[email protected]36b6dcb2008-11-12 01:19:572375
[email protected]c9cd2222009-05-06 05:16:502376 if (flags & TabContents::INVALIDATE_TAB) {
[email protected]36b6dcb2008-11-12 01:19:572377 tabstrip_model_.UpdateTabContentsStateAt(
[email protected]902cdf772009-05-06 15:08:122378 tabstrip_model_.GetIndexOfController(&contents->controller()), false);
[email protected]36b6dcb2008-11-12 01:19:572379 window_->UpdateTitleBar();
2380
[email protected]ba8c48212009-05-12 21:20:402381 if (selected_tab && contents == selected_tab) {
[email protected]1fc025202009-01-20 23:03:142382 command_updater_.UpdateCommandEnabled(IDC_CREATE_SHORTCUTS,
[email protected]ba8c48212009-05-12 21:20:402383 !selected_tab->GetFavIcon().isNull());
[email protected]36b6dcb2008-11-12 01:19:572384 }
2385 }
2386
2387 // We don't need to process INVALIDATE_STATE, since that's not visible.
2388 }
2389
2390 scheduled_updates_.clear();
2391}
2392
2393void Browser::RemoveScheduledUpdatesFor(TabContents* contents) {
2394 if (!contents)
2395 return;
2396
2397 // Remove any pending UI updates for the detached tab.
2398 UpdateVector::iterator cur_update = scheduled_updates_.begin();
2399 while (cur_update != scheduled_updates_.end()) {
2400 if (cur_update->source == contents) {
2401 cur_update = scheduled_updates_.erase(cur_update);
2402 } else {
2403 ++cur_update;
initial.commit09911bf2008-07-26 23:55:292404 }
2405 }
2406}
2407
[email protected]d938aed92009-01-22 19:49:332408
[email protected]36b6dcb2008-11-12 01:19:572409///////////////////////////////////////////////////////////////////////////////
2410// Browser, Getters for UI (private):
initial.commit09911bf2008-07-26 23:55:292411
[email protected]36b6dcb2008-11-12 01:19:572412StatusBubble* Browser::GetStatusBubble() {
2413 return window_->GetStatusBubble();
initial.commit09911bf2008-07-26 23:55:292414}
2415
[email protected]36b6dcb2008-11-12 01:19:572416///////////////////////////////////////////////////////////////////////////////
2417// Browser, Session restore functions (private):
initial.commit09911bf2008-07-26 23:55:292418
2419void Browser::SyncHistoryWithTabs(int index) {
2420 if (!profile()->HasSessionService())
2421 return;
2422 SessionService* session_service = profile()->GetSessionService();
2423 if (session_service) {
2424 for (int i = index; i < tab_count(); ++i) {
2425 TabContents* contents = GetTabContentsAt(i);
2426 if (contents) {
2427 session_service->SetTabIndexInWindow(
[email protected]ce3fa3c2009-04-20 19:55:572428 session_id(), contents->controller().session_id(), i);
[email protected]5c0e6482009-07-14 20:20:092429 session_service->SetPinnedState(session_id(),
2430 contents->controller().session_id(),
2431 tabstrip_model_.IsTabPinned(i));
initial.commit09911bf2008-07-26 23:55:292432 }
2433 }
2434 }
2435}
2436
[email protected]ce3fa3c2009-04-20 19:55:572437TabContents* Browser::BuildRestoredTab(
[email protected]36b6dcb2008-11-12 01:19:572438 const std::vector<TabNavigation>& navigations,
2439 int selected_navigation) {
2440 if (!navigations.empty()) {
2441 DCHECK(selected_navigation >= 0 &&
2442 selected_navigation < static_cast<int>(navigations.size()));
[email protected]36b6dcb2008-11-12 01:19:572443 // Create a NavigationController. This constructor creates the appropriate
2444 // set of TabContents.
[email protected]57c6a652009-05-04 07:58:342445 TabContents* new_tab = new TabContents(profile_, NULL,
[email protected]ce3fa3c2009-04-20 19:55:572446 MSG_ROUTING_NONE, NULL);
2447 new_tab->controller().RestoreFromState(navigations, selected_navigation);
2448 return new_tab;
[email protected]36b6dcb2008-11-12 01:19:572449 } else {
2450 // No navigations. Create a tab with about:blank.
[email protected]ce3fa3c2009-04-20 19:55:572451 return CreateTabContentsForURL(GURL("about:blank"), GURL(), profile_,
2452 PageTransition::START_PAGE, false, NULL);
initial.commit09911bf2008-07-26 23:55:292453 }
2454}
2455
[email protected]36b6dcb2008-11-12 01:19:572456///////////////////////////////////////////////////////////////////////////////
2457// Browser, OnBeforeUnload handling (private):
initial.commit09911bf2008-07-26 23:55:292458
[email protected]04b4a6c2008-08-02 00:44:472459void Browser::ProcessPendingTabs() {
2460 DCHECK(is_attempting_to_close_browser_);
initial.commit09911bf2008-07-26 23:55:292461
[email protected]04b4a6c2008-08-02 00:44:472462 if (HasCompletedUnloadProcessing()) {
2463 // We've finished all the unload events and can proceed to close the
2464 // browser.
2465 OnWindowClosing();
initial.commit09911bf2008-07-26 23:55:292466 return;
2467 }
2468
[email protected]04b4a6c2008-08-02 00:44:472469 // Process beforeunload tabs first. When that queue is empty, process
2470 // unload tabs.
[email protected]04b4a6c2008-08-02 00:44:472471 if (!tabs_needing_before_unload_fired_.empty()) {
[email protected]06b42f032008-12-03 18:43:052472 TabContents* tab = *(tabs_needing_before_unload_fired_.begin());
[email protected]22484622009-06-10 21:17:242473 // Null check render_view_host here as this gets called on a PostTask and
2474 // the tab's render_view_host may have been nulled out.
2475 if (tab->render_view_host()) {
2476 tab->render_view_host()->FirePageBeforeUnload();
2477 } else {
2478 ClearUnloadState(tab);
2479 }
[email protected]04b4a6c2008-08-02 00:44:472480 } else if (!tabs_needing_unload_fired_.empty()) {
initial.commit09911bf2008-07-26 23:55:292481 // We've finished firing all beforeunload events and can proceed with unload
2482 // events.
2483 // TODO(ojan): We should add a call to browser_shutdown::OnShutdownStarting
2484 // somewhere around here so that we have accurate measurements of shutdown
2485 // time.
[email protected]04b4a6c2008-08-02 00:44:472486 // TODO(ojan): We can probably fire all the unload events in parallel and
2487 // get a perf benefit from that in the cases where the tab hangs in it's
2488 // unload handler or takes a long time to page in.
[email protected]06b42f032008-12-03 18:43:052489 TabContents* tab = *(tabs_needing_unload_fired_.begin());
[email protected]22484622009-06-10 21:17:242490 // Null check render_view_host here as this gets called on a PostTask and
2491 // the tab's render_view_host may have been nulled out.
2492 if (tab->render_view_host()) {
2493 tab->render_view_host()->FirePageUnload();
2494 } else {
2495 ClearUnloadState(tab);
2496 }
initial.commit09911bf2008-07-26 23:55:292497 } else {
[email protected]04b4a6c2008-08-02 00:44:472498 NOTREACHED();
initial.commit09911bf2008-07-26 23:55:292499 }
2500}
2501
[email protected]d043c2cc2009-03-25 18:30:452502bool Browser::HasCompletedUnloadProcessing() const {
[email protected]04b4a6c2008-08-02 00:44:472503 return is_attempting_to_close_browser_ &&
2504 tabs_needing_before_unload_fired_.empty() &&
2505 tabs_needing_unload_fired_.empty();
2506}
2507
2508void Browser::CancelWindowClose() {
2509 DCHECK(is_attempting_to_close_browser_);
2510 // Only cancelling beforeunload should be able to cancel the window's close.
2511 // So there had better be a tab that we think needs beforeunload fired.
2512 DCHECK(!tabs_needing_before_unload_fired_.empty());
2513
[email protected]8f673f3a2008-08-05 22:34:282514 tabs_needing_before_unload_fired_.clear();
2515 tabs_needing_unload_fired_.clear();
[email protected]04b4a6c2008-08-02 00:44:472516 is_attempting_to_close_browser_ = false;
2517}
2518
[email protected]06b42f032008-12-03 18:43:052519bool Browser::RemoveFromSet(UnloadListenerSet* set, TabContents* tab) {
[email protected]04b4a6c2008-08-02 00:44:472520 DCHECK(is_attempting_to_close_browser_);
2521
[email protected]06b42f032008-12-03 18:43:052522 UnloadListenerSet::iterator iter = std::find(set->begin(), set->end(), tab);
2523 if (iter != set->end()) {
2524 set->erase(iter);
2525 return true;
[email protected]04b4a6c2008-08-02 00:44:472526 }
2527 return false;
2528}
initial.commit09911bf2008-07-26 23:55:292529
[email protected]36b6dcb2008-11-12 01:19:572530void Browser::ClearUnloadState(TabContents* tab) {
2531 DCHECK(is_attempting_to_close_browser_);
[email protected]06b42f032008-12-03 18:43:052532 RemoveFromSet(&tabs_needing_before_unload_fired_, tab);
2533 RemoveFromSet(&tabs_needing_unload_fired_, tab);
[email protected]36b6dcb2008-11-12 01:19:572534 ProcessPendingTabs();
initial.commit09911bf2008-07-26 23:55:292535}
2536
[email protected]f7454892009-01-29 19:24:212537
[email protected]36b6dcb2008-11-12 01:19:572538///////////////////////////////////////////////////////////////////////////////
[email protected]69444cc2009-04-09 20:40:062539// Browser, In-progress download termination handling (private):
2540
2541bool Browser::CanCloseWithInProgressDownloads() {
2542 if (cancel_download_confirmation_state_ != NOT_PROMPTED) {
2543 // This should probably not happen.
2544 DCHECK(cancel_download_confirmation_state_ != WAITING_FOR_RESPONSE);
2545 return true;
2546 }
2547
2548 // If there are no download in-progress, our job is done.
2549 DownloadManager* download_manager = profile_->GetDownloadManager();
2550 if (!download_manager || download_manager->in_progress_count() == 0)
2551 return true;
2552
2553 // Let's figure out if we are the last window for our profile.
2554 // Note that we cannot just use BrowserList::GetBrowserCount as browser
2555 // windows closing is delayed and the returned count might include windows
2556 // that are being closed.
2557 int count = 0;
2558 for (BrowserList::const_iterator iter = BrowserList::begin();
2559 iter != BrowserList::end(); ++iter) {
2560 // Don't count this browser window or any other in the process of closing.
2561 if (*iter == this || (*iter)->is_attempting_to_close_browser_)
2562 continue;
2563
2564 // We test the original profile, because an incognito browser window keeps
2565 // the original profile alive (and its DownloadManager).
2566 // We also need to test explicitly the profile directly so that 2 incognito
2567 // profiles count as a match.
2568 if ((*iter)->profile() == profile() ||
2569 (*iter)->profile()->GetOriginalProfile() == profile())
2570 count++;
2571 }
2572 if (count > 0)
2573 return true;
2574
2575 cancel_download_confirmation_state_ = WAITING_FOR_RESPONSE;
2576 window_->ConfirmBrowserCloseWithPendingDownloads();
2577
2578 // Return false so the browser does not close. We'll close if the user
2579 // confirms in the dialog.
2580 return false;
2581}
2582
2583///////////////////////////////////////////////////////////////////////////////
[email protected]36b6dcb2008-11-12 01:19:572584// Browser, Assorted utility functions (private):
initial.commit09911bf2008-07-26 23:55:292585
initial.commit09911bf2008-07-26 23:55:292586Browser* Browser::GetOrCreateTabbedBrowser() {
2587 Browser* browser = BrowserList::FindBrowserWithType(
[email protected]299dabd2008-11-19 02:27:162588 profile_, TYPE_NORMAL);
[email protected]15952e462008-11-14 00:29:052589 if (!browser)
2590 browser = Browser::Create(profile_);
initial.commit09911bf2008-07-26 23:55:292591 return browser;
2592}
2593
[email protected]1f7d7e92009-06-02 20:55:042594void Browser::OpenURLAtIndex(TabContents* source,
2595 const GURL& url,
2596 const GURL& referrer,
2597 WindowOpenDisposition disposition,
2598 PageTransition::Type transition,
2599 int index,
2600 bool force_index) {
2601 // TODO(beng): Move all this code into a separate helper that has unit tests.
2602
2603 // No code for these yet
2604 DCHECK((disposition != NEW_POPUP) && (disposition != SAVE_TO_DISK));
2605
2606 TabContents* current_tab = source ? source : GetSelectedTabContents();
2607 bool source_tab_was_frontmost = (current_tab == GetSelectedTabContents());
2608 TabContents* new_contents = NULL;
2609
2610 // If the URL is part of the same web site, then load it in the same
2611 // SiteInstance (and thus the same process). This is an optimization to
2612 // reduce process overhead; it is not necessary for compatibility. (That is,
2613 // the new tab will not have script connections to the previous tab, so it
2614 // does not need to be part of the same SiteInstance or BrowsingInstance.)
2615 // Default to loading in a new SiteInstance and BrowsingInstance.
2616 // TODO(creis): should this apply to applications?
2617 SiteInstance* instance = NULL;
2618 // Don't use this logic when "--process-per-tab" is specified.
2619 if (!CommandLine::ForCurrentProcess()->HasSwitch(switches::kProcessPerTab)) {
2620 if (current_tab) {
2621 const GURL& current_url = current_tab->GetURL();
2622 if (SiteInstance::IsSameWebSite(current_url, url))
2623 instance = current_tab->GetSiteInstance();
2624 }
2625 }
2626
2627 // If this is not a normal window (such as a popup or an application), we can
2628 // only have one tab so a new tab always goes into a tabbed browser window.
2629 if (disposition != NEW_WINDOW && type_ != TYPE_NORMAL) {
2630 // If the disposition is OFF_THE_RECORD we don't want to create a new
2631 // browser that will itself create another OTR browser. This will result in
2632 // a browser leak (and crash below because no tab is created or selected).
2633 if (disposition == OFF_THE_RECORD) {
2634 OpenURLOffTheRecord(profile_, url);
2635 return;
2636 }
2637
2638 Browser* b = GetOrCreateTabbedBrowser();
2639 DCHECK(b);
2640
2641 // If we have just created a new browser window, make sure we select the
2642 // tab.
2643 if (b->tab_count() == 0 && disposition == NEW_BACKGROUND_TAB)
2644 disposition = NEW_FOREGROUND_TAB;
2645
2646 b->OpenURL(url, referrer, disposition, transition);
2647 b->window()->Show();
2648 return;
2649 }
2650
2651 if (profile_->IsOffTheRecord() && disposition == OFF_THE_RECORD)
2652 disposition = NEW_FOREGROUND_TAB;
2653
2654 if (disposition == SINGLETON_TAB) {
2655 ShowSingleDOMUITab(url);
2656 return;
2657 } else if (disposition == NEW_WINDOW) {
2658 Browser* browser = Browser::Create(profile_);
2659 new_contents = browser->AddTabWithURL(url, referrer, transition, true,
2660 index, force_index, instance);
2661 browser->window()->Show();
2662 } else if ((disposition == CURRENT_TAB) && current_tab) {
2663 tabstrip_model_.TabNavigating(current_tab, transition);
2664
2665 current_tab->controller().LoadURL(url, referrer, transition);
2666 new_contents = current_tab;
2667 if (GetStatusBubble())
2668 GetStatusBubble()->Hide();
2669
2670 // Update the location bar. This is synchronous. We specfically don't update
2671 // the load state since the load hasn't started yet and updating it will put
2672 // it out of sync with the actual state like whether we're displaying a
2673 // favicon, which controls the throbber. If we updated it here, the throbber
2674 // will show the default favicon for a split second when navigating away
2675 // from the new tab page.
2676 ScheduleUIUpdate(current_tab, TabContents::INVALIDATE_URL);
2677 } else if (disposition == OFF_THE_RECORD) {
2678 OpenURLOffTheRecord(profile_, url);
2679 return;
2680 } else if (disposition != SUPPRESS_OPEN) {
2681 new_contents = AddTabWithURL(url, referrer, transition,
2682 disposition != NEW_BACKGROUND_TAB, index, force_index, instance);
2683 }
2684
2685 if (disposition != NEW_BACKGROUND_TAB && source_tab_was_frontmost) {
2686 // Give the focus to the newly navigated tab, if the source tab was
2687 // front-most.
2688 new_contents->Focus();
2689 }
2690}
2691
initial.commit09911bf2008-07-26 23:55:292692void Browser::BuildPopupWindow(TabContents* source,
2693 TabContents* new_contents,
2694 const gfx::Rect& initial_pos) {
[email protected]9f5b80a2009-04-08 01:26:072695 BuildPopupWindowHelper(source, new_contents, initial_pos,
2696 (type_ & TYPE_APP) ? TYPE_APP_POPUP : TYPE_POPUP,
2697 profile_, false);
2698}
2699
2700void Browser::BuildPopupWindowHelper(TabContents* source,
2701 TabContents* new_contents,
2702 const gfx::Rect& initial_pos,
2703 Browser::Type browser_type,
2704 Profile* profile,
2705 bool start_restored) {
2706 Browser* browser = new Browser(browser_type, profile);
[email protected]15952e462008-11-14 00:29:052707 browser->set_override_bounds(initial_pos);
[email protected]9f5b80a2009-04-08 01:26:072708
2709 if (start_restored)
2710 browser->set_maximized_state(MAXIMIZED_STATE_UNMAXIMIZED);
2711
[email protected]15952e462008-11-14 00:29:052712 browser->CreateBrowserWindow();
[email protected]6b2ee922009-04-30 20:40:532713 browser->tabstrip_model()->AppendTabContents(new_contents, true);
[email protected]2f69fb52008-12-12 18:50:392714 browser->window()->Show();
initial.commit09911bf2008-07-26 23:55:292715}
2716
[email protected]d043c2cc2009-03-25 18:30:452717GURL Browser::GetHomePage() const {
[email protected]15952e462008-11-14 00:29:052718 if (profile_->GetPrefs()->GetBoolean(prefs::kHomePageIsNewTabPage))
[email protected]b689fce72009-03-17 22:45:342719 return GURL(chrome::kChromeUINewTabURL);
[email protected]15952e462008-11-14 00:29:052720 GURL home_page = GURL(URLFixerUpper::FixupURL(
[email protected]a239c3f2009-02-17 22:13:192721 WideToUTF8(profile_->GetPrefs()->GetString(prefs::kHomePage)),
2722 std::string()));
[email protected]15952e462008-11-14 00:29:052723 if (!home_page.is_valid())
[email protected]b689fce72009-03-17 22:45:342724 return GURL(chrome::kChromeUINewTabURL);
[email protected]15952e462008-11-14 00:29:052725 return home_page;
[email protected]36b6dcb2008-11-12 01:19:572726}
initial.commit09911bf2008-07-26 23:55:292727
[email protected]4f3dc372009-02-24 00:10:292728void Browser::FindInPage(bool find_next, bool forward_direction) {
[email protected]4801ecc2009-04-05 04:52:582729 ShowFindBar();
[email protected]4f3dc372009-02-24 00:10:292730 if (find_next) {
[email protected]57c6a652009-05-04 07:58:342731 GetSelectedTabContents()->StartFinding(string16(),
[email protected]e491f1c2009-05-22 20:28:122732 forward_direction,
2733 false); // Not case sensitive.
[email protected]4f3dc372009-02-24 00:10:292734 }
[email protected]fbd77592008-11-12 20:50:272735}
[email protected]cb17f7f2009-02-06 18:14:482736
[email protected]36b6dcb2008-11-12 01:19:572737void Browser::CloseFrame() {
2738 window_->Close();
initial.commit09911bf2008-07-26 23:55:292739}
2740
2741// static
2742std::wstring Browser::ComputeApplicationNameFromURL(const GURL& url) {
2743 std::string t;
2744 t.append(url.host());
2745 t.append("_");
2746 t.append(url.path());
2747 return UTF8ToWide(t);
2748}
2749
2750// static
initial.commit09911bf2008-07-26 23:55:292751void Browser::RegisterAppPrefs(const std::wstring& app_name) {
2752 // A set of apps that we've already started.
2753 static std::set<std::wstring>* g_app_names = NULL;
2754
2755 if (!g_app_names)
2756 g_app_names = new std::set<std::wstring>;
2757
2758 // Only register once for each app name.
2759 if (g_app_names->find(app_name) != g_app_names->end())
2760 return;
2761 g_app_names->insert(app_name);
2762
2763 // We need to register the window position pref.
2764 std::wstring window_pref(prefs::kBrowserWindowPlacement);
2765 window_pref.append(L"_");
2766 window_pref.append(app_name);
2767 PrefService* prefs = g_browser_process->local_state();
2768 DCHECK(prefs);
2769
2770 prefs->RegisterDictionaryPref(window_pref.c_str());
2771}
[email protected]5c238752009-06-13 10:29:072772
2773///////////////////////////////////////////////////////////////////////////////
2774// BrowserToolbarModel (private):
2775
2776NavigationController* Browser::BrowserToolbarModel::GetNavigationController() {
2777 // This |current_tab| can be NULL during the initialization of the
2778 // toolbar during window creation (i.e. before any tabs have been added
2779 // to the window).
2780 TabContents* current_tab = browser_->GetSelectedTabContents();
2781 return current_tab ? &current_tab->controller() : NULL;
2782}