blob: a23d2ae489bbb72b9b18adcfd834ec4770c81cd9 [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();
initial.commit09911bf2008-07-26 23:55:29205}
206
207Browser::~Browser() {
208 // The tab strip should be empty at this point.
209 DCHECK(tabstrip_model_.empty());
210 tabstrip_model_.RemoveObserver(this);
211
212 BrowserList::RemoveBrowser(this);
213
[email protected]fbc947b2009-06-19 13:28:24214#if defined(OS_WIN) || defined(OS_LINUX)
initial.commit09911bf2008-07-26 23:55:29215 if (!BrowserList::HasBrowserWithProfile(profile_)) {
216 // We're the last browser window with this profile. We need to nuke the
217 // TabRestoreService, which will start the shutdown of the
218 // NavigationControllers and allow for proper shutdown. If we don't do this
219 // chrome won't shutdown cleanly, and may end up crashing when some
220 // thread tries to use the IO thread (or another thread) that is no longer
221 // valid.
[email protected]fbc947b2009-06-19 13:28:24222 // This isn't a valid assumption for Mac OS, as it stays running after
223 // the last browser has closed. The Mac equivalent is in its app
224 // controller.
initial.commit09911bf2008-07-26 23:55:29225 profile_->ResetTabRestoreService();
226 }
[email protected]fbc947b2009-06-19 13:28:24227#endif
initial.commit09911bf2008-07-26 23:55:29228
229 SessionService* session_service = profile_->GetSessionService();
230 if (session_service)
231 session_service->WindowClosed(session_id_);
232
[email protected]d8375fd2008-11-25 22:45:39233 TabRestoreService* tab_restore_service = profile()->GetTabRestoreService();
234 if (tab_restore_service)
235 tab_restore_service->BrowserClosed(this);
236
initial.commit09911bf2008-07-26 23:55:29237 if (profile_->IsOffTheRecord() &&
238 !BrowserList::IsOffTheRecordSessionActive()) {
[email protected]860f55492009-03-27 19:50:59239 // An off-the-record profile is no longer needed, this indirectly
240 // frees its cache and cookies.
241 profile_->GetOriginalProfile()->DestroyOffTheRecordProfile();
initial.commit09911bf2008-07-26 23:55:29242 }
243
244 // There may be pending file dialogs, we need to tell them that we've gone
245 // away so they don't try and call back to us.
246 if (select_file_dialog_.get())
247 select_file_dialog_->ListenerDestroyed();
248}
249
[email protected]15952e462008-11-14 00:29:05250// static
251Browser* Browser::Create(Profile* profile) {
[email protected]299dabd2008-11-19 02:27:16252 Browser* browser = new Browser(TYPE_NORMAL, profile);
[email protected]15952e462008-11-14 00:29:05253 browser->CreateBrowserWindow();
254 return browser;
255}
[email protected]6104acf2008-11-11 22:27:34256
[email protected]15952e462008-11-14 00:29:05257// static
258Browser* Browser::CreateForPopup(Profile* profile) {
[email protected]299dabd2008-11-19 02:27:16259 Browser* browser = new Browser(TYPE_POPUP, profile);
[email protected]15952e462008-11-14 00:29:05260 browser->CreateBrowserWindow();
261 return browser;
262}
263
264// static
265Browser* Browser::CreateForApp(const std::wstring& app_name,
[email protected]d5fbc002009-02-27 22:12:58266 Profile* profile, bool is_popup) {
267 Browser* browser = new Browser(is_popup? TYPE_APP_POPUP : TYPE_APP, profile);
[email protected]15952e462008-11-14 00:29:05268 browser->app_name_ = app_name;
269 browser->CreateBrowserWindow();
270 return browser;
271}
272
273void Browser::CreateBrowserWindow() {
274 DCHECK(!window_);
275 window_ = BrowserWindow::CreateBrowserWindow(this);
276
277 // Show the First Run information bubble if we've been told to.
278 PrefService* local_state = g_browser_process->local_state();
[email protected]be3877f2009-01-14 15:51:10279 if (!local_state)
280 return;
[email protected]15952e462008-11-14 00:29:05281 if (local_state->IsPrefRegistered(prefs::kShouldShowFirstRunBubble) &&
282 local_state->GetBoolean(prefs::kShouldShowFirstRunBubble)) {
[email protected]b1390d02009-05-19 23:50:37283 bool show_OEM_bubble = (local_state->
284 IsPrefRegistered(prefs::kShouldUseOEMFirstRunBubble) &&
285 local_state->GetBoolean(prefs::kShouldUseOEMFirstRunBubble));
[email protected]15952e462008-11-14 00:29:05286 // Reset the preference so we don't show the bubble for subsequent windows.
287 local_state->ClearPref(prefs::kShouldShowFirstRunBubble);
[email protected]b1390d02009-05-19 23:50:37288 window_->GetLocationBar()->ShowFirstRunBubble(show_OEM_bubble);
initial.commit09911bf2008-07-26 23:55:29289 }
[email protected]4801ecc2009-04-05 04:52:58290
[email protected]d87301172009-05-31 04:28:18291#if !(defined(OS_LINUX) && defined(TOOLKIT_VIEWS))
[email protected]4801ecc2009-04-05 04:52:58292 FindBar* find_bar = BrowserWindow::CreateFindBar(this);
293 find_bar_controller_.reset(new FindBarController(find_bar));
294 find_bar->SetFindBarController(find_bar_controller_.get());
[email protected]21230ca2009-05-30 08:27:29295#endif
initial.commit09911bf2008-07-26 23:55:29296}
297
[email protected]36b6dcb2008-11-12 01:19:57298///////////////////////////////////////////////////////////////////////////////
[email protected]5c238752009-06-13 10:29:07299// Getters & Setters
300
301const std::vector<std::wstring>& Browser::user_data_dir_profiles() const {
302 return g_browser_process->user_data_dir_profiles();
303}
304
305void Browser::set_user_data_dir_profiles(
306 const std::vector<std::wstring>& profiles) {
307 g_browser_process->user_data_dir_profiles() = profiles;
308}
309
310///////////////////////////////////////////////////////////////////////////////
[email protected]36b6dcb2008-11-12 01:19:57311// Browser, Creation Helpers:
312
313// static
[email protected]15952e462008-11-14 00:29:05314void Browser::OpenEmptyWindow(Profile* profile) {
315 Browser* browser = Browser::Create(profile);
[email protected]36b6dcb2008-11-12 01:19:57316 browser->AddBlankTab(true);
[email protected]15952e462008-11-14 00:29:05317 browser->window()->Show();
initial.commit09911bf2008-07-26 23:55:29318}
319
[email protected]36b6dcb2008-11-12 01:19:57320// static
[email protected]fbc947b2009-06-19 13:28:24321void Browser::OpenWindowWithRestoredTabs(Profile* profile) {
322 TabRestoreService* service = profile->GetTabRestoreService();
323 if (service)
324 service->RestoreMostRecentEntry(NULL);
325}
326
327// static
[email protected]36b6dcb2008-11-12 01:19:57328void Browser::OpenURLOffTheRecord(Profile* profile, const GURL& url) {
329 Profile* off_the_record_profile = profile->GetOffTheRecordProfile();
330 Browser* browser = BrowserList::FindBrowserWithType(
[email protected]15952e462008-11-14 00:29:05331 off_the_record_profile,
[email protected]299dabd2008-11-19 02:27:16332 TYPE_NORMAL);
[email protected]15952e462008-11-14 00:29:05333 if (!browser)
334 browser = Browser::Create(off_the_record_profile);
[email protected]36b6dcb2008-11-12 01:19:57335 // TODO(eroman): should we have referrer here?
[email protected]5a4940be2009-05-06 06:44:39336 browser->AddTabWithURL(url, GURL(), PageTransition::LINK, true, -1, false,
337 NULL);
[email protected]15952e462008-11-14 00:29:05338 browser->window()->Show();
[email protected]2baf83d2008-07-30 05:58:17339}
340
[email protected]36b6dcb2008-11-12 01:19:57341// static
[email protected]0303f31c2009-02-02 06:42:05342void Browser::OpenApplicationWindow(Profile* profile, const GURL& url) {
343 std::wstring app_name = ComputeApplicationNameFromURL(url);
[email protected]36b6dcb2008-11-12 01:19:57344 RegisterAppPrefs(app_name);
[email protected]15952e462008-11-14 00:29:05345
[email protected]d5fbc002009-02-27 22:12:58346 Browser* browser = Browser::CreateForApp(app_name, profile, false);
[email protected]22735af62009-04-07 21:09:58347 browser->AddTabWithURL(url, GURL(), PageTransition::START_PAGE, true, -1,
[email protected]5a4940be2009-05-06 06:44:39348 false, NULL);
[email protected]840b1512009-07-21 16:53:46349
[email protected]3df2aaf2009-07-25 00:24:57350#if defined(OS_WIN)
351 // Set the app user model id for this application to that of the application
352 // name. See http://crbug.com/7028.
353 win_util::SetAppIdForWindow(app_name, browser->window()->GetNativeHandle());
354#endif
355
[email protected]840b1512009-07-21 16:53:46356 TabContents* tab_contents = browser->GetSelectedTabContents();
357 tab_contents->GetMutableRendererPrefs()->can_accept_load_drops = false;
358 tab_contents->render_view_host()->SyncRendererPrefs();
[email protected]15952e462008-11-14 00:29:05359 browser->window()->Show();
[email protected]68f009f2009-02-26 19:43:35360 // TODO(jcampan): http://crbug.com/8123 we should not need to set the initial
361 // focus explicitly.
[email protected]840b1512009-07-21 16:53:46362 tab_contents->view()->SetInitialFocus();
[email protected]d6a3c772009-01-27 19:41:20363}
initial.commit09911bf2008-07-26 23:55:29364
[email protected]36b6dcb2008-11-12 01:19:57365///////////////////////////////////////////////////////////////////////////////
[email protected]36b6dcb2008-11-12 01:19:57366// Browser, State Storage and Retrieval for UI:
367
[email protected]bc9a5152008-11-15 00:32:04368std::wstring Browser::GetWindowPlacementKey() const {
[email protected]36b6dcb2008-11-12 01:19:57369 std::wstring name(prefs::kBrowserWindowPlacement);
370 if (!app_name_.empty()) {
371 name.append(L"_");
372 name.append(app_name_);
373 }
[email protected]bc9a5152008-11-15 00:32:04374 return name;
375}
[email protected]36b6dcb2008-11-12 01:19:57376
[email protected]bc9a5152008-11-15 00:32:04377bool Browser::ShouldSaveWindowPlacement() const {
378 // We don't save window position for popups.
[email protected]d5fbc002009-02-27 22:12:58379 return (type() & TYPE_POPUP) == 0;
[email protected]bc9a5152008-11-15 00:32:04380}
[email protected]36b6dcb2008-11-12 01:19:57381
[email protected]bc9a5152008-11-15 00:32:04382void Browser::SaveWindowPlacement(const gfx::Rect& bounds, bool maximized) {
383 // Save to the session storage service, used when reloading a past session.
384 // Note that we don't want to be the ones who cause lazy initialization of
385 // the session service. This function gets called during initial window
386 // showing, and we don't want to bring in the session service this early.
[email protected]36b6dcb2008-11-12 01:19:57387 if (profile()->HasSessionService()) {
388 SessionService* session_service = profile()->GetSessionService();
389 if (session_service)
390 session_service->SetWindowBounds(session_id_, bounds, maximized);
391 }
392}
393
[email protected]15952e462008-11-14 00:29:05394gfx::Rect Browser::GetSavedWindowBounds() const {
[email protected]bb975362009-01-21 01:00:22395 const CommandLine& parsed_command_line = *CommandLine::ForCurrentProcess();
[email protected]15952e462008-11-14 00:29:05396 bool record_mode = parsed_command_line.HasSwitch(switches::kRecordMode);
397 bool playback_mode = parsed_command_line.HasSwitch(switches::kPlaybackMode);
398 if (record_mode || playback_mode) {
399 // In playback/record mode we always fix the size of the browser and
400 // move it to (0,0). The reason for this is two reasons: First we want
401 // resize/moves in the playback to still work, and Second we want
402 // playbacks to work (as much as possible) on machines w/ different
403 // screen sizes.
404 return gfx::Rect(0, 0, 800, 600);
405 }
406
407 gfx::Rect restored_bounds = override_bounds_;
408 bool maximized;
[email protected]6dfed102009-04-28 03:09:53409 WindowSizer::GetBrowserWindowBounds(app_name_, restored_bounds, NULL,
[email protected]15952e462008-11-14 00:29:05410 &restored_bounds, &maximized);
411 return restored_bounds;
412}
413
414// TODO(beng): obtain maximized state some other way so we don't need to go
415// through all this hassle.
416bool Browser::GetSavedMaximizedState() const {
[email protected]bb975362009-01-21 01:00:22417 if (CommandLine::ForCurrentProcess()->HasSwitch(switches::kStartMaximized))
[email protected]15952e462008-11-14 00:29:05418 return true;
419
[email protected]2e716622009-03-09 21:11:01420 if (maximized_state_ == MAXIMIZED_STATE_MAXIMIZED)
421 return true;
422 if (maximized_state_ == MAXIMIZED_STATE_UNMAXIMIZED)
423 return false;
424
425 // An explicit maximized state was not set. Query the window sizer.
[email protected]15952e462008-11-14 00:29:05426 gfx::Rect restored_bounds;
[email protected]2e716622009-03-09 21:11:01427 bool maximized = false;
[email protected]6dfed102009-04-28 03:09:53428 WindowSizer::GetBrowserWindowBounds(app_name_, restored_bounds, NULL,
[email protected]15952e462008-11-14 00:29:05429 &restored_bounds, &maximized);
430 return maximized;
[email protected]36b6dcb2008-11-12 01:19:57431}
432
433SkBitmap Browser::GetCurrentPageIcon() const {
[email protected]ce5348a82008-12-18 18:36:23434 TabContents* contents = GetSelectedTabContents();
435 // |contents| can be NULL since GetCurrentPageIcon() is called by the window
436 // during the window's creation (before tabs have been added).
437 return contents ? contents->GetFavIcon() : SkBitmap();
[email protected]36b6dcb2008-11-12 01:19:57438}
439
[email protected]731f8a42009-07-20 22:07:32440string16 Browser::GetWindowTitleForCurrentTab() const {
[email protected]36b6dcb2008-11-12 01:19:57441 TabContents* contents = tabstrip_model_.GetSelectedTabContents();
[email protected]dda5dfa32009-07-10 00:33:29442 string16 title;
[email protected]c7c42332008-11-15 01:10:54443
[email protected]731f8a42009-07-20 22:07:32444 // |contents| can be NULL because GetWindowTitleForCurrentTab is called by the
445 // window during the window's creation (before tabs have been added).
[email protected]36b6dcb2008-11-12 01:19:57446 if (contents) {
[email protected]dda5dfa32009-07-10 00:33:29447 title = contents->GetTitle();
[email protected]36b6dcb2008-11-12 01:19:57448 FormatTitleForDisplay(&title);
449 }
450 if (title.empty())
[email protected]dda5dfa32009-07-10 00:33:29451 title = l10n_util::GetStringUTF16(IDS_TAB_UNTITLED_TITLE);
[email protected]36b6dcb2008-11-12 01:19:57452
[email protected]16779842009-07-08 23:45:29453#if defined(OS_MACOSX) || defined(OS_CHROMEOS)
[email protected]d904bc82009-07-07 00:41:04454 // On Mac, we don't want to suffix the page title with the application name.
455 return title;
456#elif defined(OS_WIN) || defined(OS_LINUX)
[email protected]edb5e6a2009-04-08 23:46:17457 int string_id = IDS_BROWSER_WINDOW_TITLE_FORMAT;
458 // Don't append the app name to window titles when we're not displaying a
459 // distributor logo for the frame.
460 if (!ShouldShowDistributorLogo())
461 string_id = IDS_BROWSER_WINDOW_TITLE_FORMAT_NO_LOGO;
[email protected]dda5dfa32009-07-10 00:33:29462 return l10n_util::GetStringFUTF16(string_id, title);
[email protected]57e68dba2009-05-15 21:30:50463#endif
[email protected]36b6dcb2008-11-12 01:19:57464}
465
466// static
[email protected]dda5dfa32009-07-10 00:33:29467void Browser::FormatTitleForDisplay(string16* title) {
[email protected]36b6dcb2008-11-12 01:19:57468 size_t current_index = 0;
469 size_t match_index;
470 while ((match_index = title->find(L'\n', current_index)) !=
471 std::wstring::npos) {
[email protected]dda5dfa32009-07-10 00:33:29472 title->replace(match_index, 1, EmptyString16());
[email protected]36b6dcb2008-11-12 01:19:57473 current_index = match_index;
474 }
475}
476
[email protected]edb5e6a2009-04-08 23:46:17477bool Browser::ShouldShowDistributorLogo() const {
478 // Don't show the distributor logo on app frames and app popups.
479 return !(type_ & TYPE_APP);
480}
[email protected]c61db1d2009-02-06 03:39:18481
[email protected]36b6dcb2008-11-12 01:19:57482///////////////////////////////////////////////////////////////////////////////
483// Browser, OnBeforeUnload handling:
484
485bool Browser::ShouldCloseWindow() {
[email protected]69444cc2009-04-09 20:40:06486 if (!CanCloseWithInProgressDownloads())
487 return false;
488
489 if (HasCompletedUnloadProcessing())
[email protected]36b6dcb2008-11-12 01:19:57490 return true;
[email protected]69444cc2009-04-09 20:40:06491
[email protected]36b6dcb2008-11-12 01:19:57492 is_attempting_to_close_browser_ = true;
493
494 for (int i = 0; i < tab_count(); ++i) {
[email protected]505323e22009-01-24 02:47:58495 TabContents* contents = GetTabContentsAt(i);
496 if (TabHasUnloadListener(contents))
497 tabs_needing_before_unload_fired_.insert(contents);
[email protected]36b6dcb2008-11-12 01:19:57498 }
499
500 if (tabs_needing_before_unload_fired_.empty())
501 return true;
502
503 ProcessPendingTabs();
504 return false;
505}
506
507void Browser::OnWindowClosing() {
508 if (!ShouldCloseWindow())
509 return;
510
[email protected]a239c3f2009-02-17 22:13:19511#if defined(OS_WIN) || defined(OS_LINUX)
512 // We don't want to do this on Mac since closing all windows isn't a sign
513 // that the app is shutting down.
[email protected]36b6dcb2008-11-12 01:19:57514 if (BrowserList::size() == 1)
515 browser_shutdown::OnShutdownStarting(browser_shutdown::WINDOW_CLOSE);
[email protected]a239c3f2009-02-17 22:13:19516#endif
[email protected]36b6dcb2008-11-12 01:19:57517
518 // Don't use HasSessionService here, we want to force creation of the
519 // session service so that user can restore what was open.
520 SessionService* session_service = profile()->GetSessionService();
521 if (session_service)
522 session_service->WindowClosing(session_id());
523
[email protected]d8375fd2008-11-25 22:45:39524 TabRestoreService* tab_restore_service = profile()->GetTabRestoreService();
525 if (tab_restore_service)
526 tab_restore_service->BrowserClosing(this);
527
[email protected]36b6dcb2008-11-12 01:19:57528 CloseAllTabs();
529}
530
[email protected]69444cc2009-04-09 20:40:06531////////////////////////////////////////////////////////////////////////////////
532// In-progress download termination handling:
533
534void Browser::InProgressDownloadResponse(bool cancel_downloads) {
535 if (cancel_downloads) {
536 cancel_download_confirmation_state_ = RESPONSE_RECEIVED;
537 CloseWindow();
538 return;
539 }
540
541 // Sets the confirmation state to NOT_PROMPTED so that if the user tries to
542 // close again we'll show the warning again.
543 cancel_download_confirmation_state_ = NOT_PROMPTED;
544
545 // Show the download page so the user can figure-out what downloads are still
546 // in-progress.
547 ShowDownloadsTab();
548}
549
550
551////////////////////////////////////////////////////////////////////////////////
[email protected]36b6dcb2008-11-12 01:19:57552// Browser, Tab adding/showing functions:
553
554TabContents* Browser::AddTabWithURL(
555 const GURL& url, const GURL& referrer, PageTransition::Type transition,
[email protected]5a4940be2009-05-06 06:44:39556 bool foreground, int index, bool force_index,
557 SiteInstance* instance) {
[email protected]22735af62009-04-07 21:09:58558 TabContents* contents = NULL;
559 if (type_ == TYPE_NORMAL || tabstrip_model()->empty()) {
560 GURL url_to_load = url;
561 if (url_to_load.is_empty())
562 url_to_load = GetHomePage();
563 contents = CreateTabContentsForURL(url_to_load, referrer, profile_,
564 transition, false, instance);
[email protected]5a4940be2009-05-06 06:44:39565 tabstrip_model_.AddTabContents(contents, index, force_index,
566 transition, foreground);
[email protected]22735af62009-04-07 21:09:58567 // By default, content believes it is not hidden. When adding contents
568 // in the background, tell it that it's hidden.
569 if (!foreground)
570 contents->WasHidden();
571 } else {
572 // We're in an app window or a popup window. Find an existing browser to
573 // open this URL in, creating one if none exists.
574 Browser* b = GetOrCreateTabbedBrowser();
575 contents = b->AddTabWithURL(url, referrer, transition, foreground, index,
[email protected]5a4940be2009-05-06 06:44:39576 force_index, instance);
[email protected]22735af62009-04-07 21:09:58577 b->window()->Show();
[email protected]36b6dcb2008-11-12 01:19:57578 }
[email protected]36b6dcb2008-11-12 01:19:57579 return contents;
580}
581
[email protected]ce3fa3c2009-04-20 19:55:57582// TODO(brettw) this should be just AddTab and it should take a TabContents.
[email protected]36b6dcb2008-11-12 01:19:57583TabContents* Browser::AddTabWithNavigationController(
584 NavigationController* ctrl, PageTransition::Type type) {
[email protected]7f0005a2009-04-15 03:25:11585 TabContents* tc = ctrl->tab_contents();
[email protected]5a4940be2009-05-06 06:44:39586 tabstrip_model_.AddTabContents(tc, -1, false, type, true);
[email protected]36b6dcb2008-11-12 01:19:57587 return tc;
588}
589
[email protected]e0c7c262009-04-23 23:09:43590void Browser::AddTabContents(TabContents* new_contents,
591 WindowOpenDisposition disposition,
592 const gfx::Rect& initial_pos,
593 bool user_gesture) {
594 AddNewContents(NULL, new_contents, disposition, initial_pos, user_gesture);
595}
596
597void Browser::CloseTabContents(TabContents* contents) {
598 CloseContents(contents);
599}
600
601void Browser::BrowserShowHtmlDialog(HtmlDialogUIDelegate* delegate,
[email protected]322f3ff2009-05-22 16:19:54602 gfx::NativeWindow parent_window) {
[email protected]e0c7c262009-04-23 23:09:43603 ShowHtmlDialog(delegate, parent_window);
604}
605
606void Browser::BrowserRenderWidgetShowing() {
607 RenderWidgetShowing();
608}
609
610void Browser::ToolbarSizeChanged(bool is_animating) {
611 ToolbarSizeChanged(NULL, is_animating);
612}
613
[email protected]ce3fa3c2009-04-20 19:55:57614TabContents* Browser::AddRestoredTab(
[email protected]36b6dcb2008-11-12 01:19:57615 const std::vector<TabNavigation>& navigations,
616 int tab_index,
617 int selected_navigation,
[email protected]5c0e6482009-07-14 20:20:09618 bool select,
619 bool pin) {
[email protected]57c6a652009-05-04 07:58:34620 TabContents* new_tab = new TabContents(profile(), NULL,
[email protected]ce3fa3c2009-04-20 19:55:57621 MSG_ROUTING_NONE, NULL);
622 new_tab->controller().RestoreFromState(navigations, selected_navigation);
[email protected]36b6dcb2008-11-12 01:19:57623
[email protected]5c0e6482009-07-14 20:20:09624 bool really_pin =
625 (pin && tab_index == tabstrip_model()->IndexOfFirstNonPinnedTab());
[email protected]ce3fa3c2009-04-20 19:55:57626 tabstrip_model_.InsertTabContentsAt(tab_index, new_tab, select, false);
[email protected]5c0e6482009-07-14 20:20:09627 if (really_pin)
628 tabstrip_model_.SetTabPinned(tab_index, true);
[email protected]77bc6732009-04-20 22:01:03629 if (select)
630 window_->Activate();
[email protected]36b6dcb2008-11-12 01:19:57631 if (profile_->HasSessionService()) {
632 SessionService* session_service = profile_->GetSessionService();
633 if (session_service)
[email protected]5c0e6482009-07-14 20:20:09634 session_service->TabRestored(&new_tab->controller(), really_pin);
[email protected]36b6dcb2008-11-12 01:19:57635 }
[email protected]ce3fa3c2009-04-20 19:55:57636 return new_tab;
[email protected]36b6dcb2008-11-12 01:19:57637}
638
639void Browser::ReplaceRestoredTab(
640 const std::vector<TabNavigation>& navigations,
641 int selected_navigation) {
[email protected]57c6a652009-05-04 07:58:34642 TabContents* replacement = new TabContents(profile(), NULL,
[email protected]ce3fa3c2009-04-20 19:55:57643 MSG_ROUTING_NONE, NULL);
644 replacement->controller().RestoreFromState(navigations, selected_navigation);
[email protected]36b6dcb2008-11-12 01:19:57645
646 tabstrip_model_.ReplaceNavigationControllerAt(
647 tabstrip_model_.selected_index(),
[email protected]ce3fa3c2009-04-20 19:55:57648 &replacement->controller());
[email protected]36b6dcb2008-11-12 01:19:57649}
650
[email protected]a8eff102009-04-14 15:23:43651bool Browser::CanRestoreTab() {
652 TabRestoreService* service = profile_->GetTabRestoreService();
653 return service && !service->entries().empty();
654}
655
[email protected]7a5f33d2009-03-03 04:35:36656void Browser::ShowSingleDOMUITab(const GURL& url) {
[email protected]b689fce72009-03-17 22:45:34657 // See if we already have a tab with the given URL and select it if so.
658 for (int i = 0; i < tabstrip_model_.count(); i++) {
659 TabContents* tc = tabstrip_model_.GetTabContentsAt(i);
660 if (tc->GetURL() == url) {
[email protected]36b6dcb2008-11-12 01:19:57661 tabstrip_model_.SelectTabContentsAt(i, false);
662 return;
663 }
664 }
[email protected]b689fce72009-03-17 22:45:34665
666 // Otherwise, just create a new tab.
[email protected]5a4940be2009-05-06 06:44:39667 AddTabWithURL(url, GURL(), PageTransition::AUTO_BOOKMARK, true, -1,
668 false, NULL);
[email protected]36b6dcb2008-11-12 01:19:57669}
[email protected]d938aed92009-01-22 19:49:33670
[email protected]ae2622c2009-07-30 23:47:58671void Browser::UpdateCommandsForFullscreenMode(bool is_fullscreen) {
672 const bool show_main_ui = (type() == TYPE_NORMAL) && !is_fullscreen;
673
674 // Navigation commands
675 command_updater_.UpdateCommandEnabled(IDC_OPEN_CURRENT_URL, show_main_ui);
676
677 // Window management commands
678 command_updater_.UpdateCommandEnabled(IDC_PROFILE_MENU, show_main_ui);
679 command_updater_.UpdateCommandEnabled(IDC_SHOW_AS_TAB,
680 (type() & TYPE_POPUP) && !is_fullscreen);
681
682 // Focus various bits of UI
683 command_updater_.UpdateCommandEnabled(IDC_FOCUS_TOOLBAR, show_main_ui);
684 command_updater_.UpdateCommandEnabled(IDC_FOCUS_LOCATION, show_main_ui);
685 command_updater_.UpdateCommandEnabled(IDC_FOCUS_SEARCH, show_main_ui);
686
687 // Show various bits of UI
688 command_updater_.UpdateCommandEnabled(IDC_DEVELOPER_MENU, show_main_ui);
689 command_updater_.UpdateCommandEnabled(IDC_NEW_PROFILE, show_main_ui);
690 command_updater_.UpdateCommandEnabled(IDC_REPORT_BUG, show_main_ui);
691 command_updater_.UpdateCommandEnabled(IDC_SHOW_BOOKMARK_BAR, show_main_ui);
692 command_updater_.UpdateCommandEnabled(IDC_IMPORT_SETTINGS, show_main_ui);
693 command_updater_.UpdateCommandEnabled(IDC_OPTIONS, show_main_ui);
694 command_updater_.UpdateCommandEnabled(IDC_EDIT_SEARCH_ENGINES, show_main_ui);
695 command_updater_.UpdateCommandEnabled(IDC_VIEW_PASSWORDS, show_main_ui);
696 command_updater_.UpdateCommandEnabled(IDC_ABOUT, show_main_ui);
697}
698
[email protected]36b6dcb2008-11-12 01:19:57699///////////////////////////////////////////////////////////////////////////////
700// Browser, Assorted browser commands:
701
[email protected]485fba42009-03-24 23:27:29702void Browser::GoBack(WindowOpenDisposition disposition) {
[email protected]fbd77592008-11-12 20:50:27703 UserMetrics::RecordAction(L"Back", profile_);
704
[email protected]36b6dcb2008-11-12 01:19:57705 // If we are showing an interstitial, just hide it.
706 TabContents* current_tab = GetSelectedTabContents();
[email protected]57c6a652009-05-04 07:58:34707 if (current_tab->interstitial_page()) {
[email protected]a3a1d142008-12-19 00:42:30708 // The GoBack() case is a special case when an interstitial is shown because
709 // the "previous" page is still available, just hidden by the interstitial.
710 // We treat the back as a "Don't proceed", this hides the interstitial and
711 // reveals the previous page.
[email protected]57c6a652009-05-04 07:58:34712 current_tab->interstitial_page()->DontProceed();
[email protected]c7c42332008-11-15 01:10:54713 return;
[email protected]36b6dcb2008-11-12 01:19:57714 }
[email protected]485fba42009-03-24 23:27:29715
[email protected]ce3fa3c2009-04-20 19:55:57716 if (current_tab->controller().CanGoBack()) {
717 NavigationController* controller = NULL;
718 if (disposition == NEW_FOREGROUND_TAB ||
719 disposition == NEW_BACKGROUND_TAB) {
[email protected]90ba8dd2009-04-25 19:43:52720 TabContents* cloned = GetSelectedTabContents()->Clone();
[email protected]5a4940be2009-05-06 06:44:39721 tabstrip_model_.AddTabContents(cloned, -1, false,
[email protected]90ba8dd2009-04-25 19:43:52722 PageTransition::LINK,
723 disposition == NEW_FOREGROUND_TAB);
724 controller = &cloned->controller();
[email protected]485fba42009-03-24 23:27:29725 } else {
726 // Default disposition is CURRENT_TAB.
[email protected]ce3fa3c2009-04-20 19:55:57727 controller = &current_tab->controller();
[email protected]485fba42009-03-24 23:27:29728 }
729 controller->GoBack();
730 }
[email protected]36b6dcb2008-11-12 01:19:57731}
732
[email protected]485fba42009-03-24 23:27:29733void Browser::GoForward(WindowOpenDisposition disp) {
[email protected]ce3fa3c2009-04-20 19:55:57734 // TODO(brettw) this is mostly duplicated from GoBack, these should have a
735 // common backend or something.
[email protected]fbd77592008-11-12 20:50:27736 UserMetrics::RecordAction(L"Forward", profile_);
[email protected]ce3fa3c2009-04-20 19:55:57737 if (GetSelectedTabContents()->controller().CanGoForward()) {
[email protected]485fba42009-03-24 23:27:29738 NavigationController* controller = 0;
739 if (disp == NEW_FOREGROUND_TAB || disp == NEW_BACKGROUND_TAB) {
[email protected]90ba8dd2009-04-25 19:43:52740 TabContents* cloned = GetSelectedTabContents()->Clone();
[email protected]5a4940be2009-05-06 06:44:39741 tabstrip_model_.AddTabContents(cloned, -1, false,
[email protected]90ba8dd2009-04-25 19:43:52742 PageTransition::LINK,
743 disp == NEW_FOREGROUND_TAB);
744 controller = &cloned->controller();
[email protected]485fba42009-03-24 23:27:29745 } else {
746 // Default disposition is CURRENT_TAB.
[email protected]ce3fa3c2009-04-20 19:55:57747 controller = &GetSelectedTabContents()->controller();
[email protected]485fba42009-03-24 23:27:29748 }
749 controller->GoForward();
750 }
[email protected]36b6dcb2008-11-12 01:19:57751}
752
753void Browser::Reload() {
[email protected]fbd77592008-11-12 20:50:27754 UserMetrics::RecordAction(L"Reload", profile_);
755
[email protected]36b6dcb2008-11-12 01:19:57756 // If we are showing an interstitial, treat this as an OpenURL.
757 TabContents* current_tab = GetSelectedTabContents();
758 if (current_tab) {
[email protected]57c6a652009-05-04 07:58:34759 if (current_tab->showing_interstitial_page()) {
[email protected]ce3fa3c2009-04-20 19:55:57760 NavigationEntry* entry = current_tab->controller().GetActiveEntry();
[email protected]36b6dcb2008-11-12 01:19:57761 DCHECK(entry); // Should exist if interstitial is showing.
762 OpenURL(entry->url(), GURL(), CURRENT_TAB, PageTransition::RELOAD);
763 return;
764 }
[email protected]36b6dcb2008-11-12 01:19:57765
[email protected]20142ba2009-05-04 16:58:47766 // As this is caused by a user action, give the focus to the page.
[email protected]9d8a4642009-07-29 17:25:30767 if (!current_tab->FocusLocationBarByDefault())
768 current_tab->Focus();
[email protected]ce3fa3c2009-04-20 19:55:57769 current_tab->controller().Reload(true);
[email protected]36b6dcb2008-11-12 01:19:57770 }
771}
772
[email protected]485fba42009-03-24 23:27:29773void Browser::Home(WindowOpenDisposition disposition) {
[email protected]fbd77592008-11-12 20:50:27774 UserMetrics::RecordAction(L"Home", profile_);
[email protected]485fba42009-03-24 23:27:29775 OpenURL(GetHomePage(), GURL(), disposition, PageTransition::AUTO_BOOKMARK);
[email protected]36b6dcb2008-11-12 01:19:57776}
777
[email protected]fbd77592008-11-12 20:50:27778void Browser::OpenCurrentURL() {
779 UserMetrics::RecordAction(L"LoadURL", profile_);
[email protected]7745b822009-01-27 20:15:35780 LocationBar* location_bar = window_->GetLocationBar();
[email protected]1f7d7e92009-06-02 20:55:04781 OpenURLAtIndex(NULL, GURL(WideToUTF8(location_bar->GetInputString())), GURL(),
782 location_bar->GetWindowOpenDisposition(),
783 location_bar->GetPageTransition(), -1, true);
[email protected]fbd77592008-11-12 20:50:27784}
785
[email protected]485fba42009-03-24 23:27:29786void Browser::Go(WindowOpenDisposition disposition) {
[email protected]84214982008-12-10 18:49:10787 UserMetrics::RecordAction(L"Go", profile_);
[email protected]485fba42009-03-24 23:27:29788 window_->GetLocationBar()->AcceptInputWithDisposition(disposition);
[email protected]84214982008-12-10 18:49:10789}
790
791void Browser::Stop() {
792 UserMetrics::RecordAction(L"Stop", profile_);
[email protected]0daf94732008-12-17 01:08:33793 GetSelectedTabContents()->Stop();
[email protected]84214982008-12-10 18:49:10794}
795
796void Browser::NewWindow() {
797 UserMetrics::RecordAction(L"NewWindow", profile_);
798 Browser::OpenEmptyWindow(profile_->GetOriginalProfile());
799}
800
801void Browser::NewIncognitoWindow() {
802 UserMetrics::RecordAction(L"NewIncognitoWindow", profile_);
803 Browser::OpenEmptyWindow(profile_->GetOffTheRecordProfile());
804}
805
806void Browser::NewProfileWindowByIndex(int index) {
[email protected]d938aed92009-01-22 19:49:33807#if defined(OS_WIN)
[email protected]ac926362009-02-26 01:33:18808 const CommandLine& command_line = *CommandLine::ForCurrentProcess();
809 if (!command_line.HasSwitch(switches::kEnableUserDataDirProfiles))
810 return;
[email protected]84214982008-12-10 18:49:10811 UserMetrics::RecordAction(L"NewProfileWindowByIndex", profile_);
812 UserDataManager::Get()->LaunchChromeForProfile(index);
[email protected]d938aed92009-01-22 19:49:33813#endif
[email protected]84214982008-12-10 18:49:10814}
815
816void Browser::CloseWindow() {
817 UserMetrics::RecordAction(L"CloseWindow", profile_);
818 window_->Close();
819}
820
[email protected]fbd77592008-11-12 20:50:27821void Browser::NewTab() {
822 UserMetrics::RecordAction(L"NewTab", profile_);
[email protected]299dabd2008-11-19 02:27:16823 if (type() == TYPE_NORMAL) {
[email protected]fbd77592008-11-12 20:50:27824 AddBlankTab(true);
825 } else {
826 Browser* b = GetOrCreateTabbedBrowser();
[email protected]fbd77592008-11-12 20:50:27827 b->AddBlankTab(true);
[email protected]15952e462008-11-14 00:29:05828 b->window()->Show();
[email protected]e54f30d2009-01-14 21:17:11829 // The call to AddBlankTab above did not set the focus to the tab as its
830 // window was not active, so we have to do it explicitly.
831 // See http://crbug.com/6380.
[email protected]57c6a652009-05-04 07:58:34832 b->GetSelectedTabContents()->view()->RestoreFocus();
[email protected]fbd77592008-11-12 20:50:27833 }
834}
835
836void Browser::CloseTab() {
837 UserMetrics::RecordAction(L"CloseTab_Accelerator", profile_);
838 tabstrip_model_.CloseTabContentsAt(tabstrip_model_.selected_index());
839}
840
[email protected]fbd77592008-11-12 20:50:27841void Browser::SelectNextTab() {
842 UserMetrics::RecordAction(L"SelectNextTab", profile_);
843 tabstrip_model_.SelectNextTab();
844}
845
846void Browser::SelectPreviousTab() {
847 UserMetrics::RecordAction(L"SelectPrevTab", profile_);
848 tabstrip_model_.SelectPreviousTab();
849}
850
851void Browser::SelectNumberedTab(int index) {
852 if (index < tab_count()) {
853 UserMetrics::RecordAction(L"SelectNumberedTab", profile_);
854 tabstrip_model_.SelectTabContentsAt(index, true);
855 }
856}
857
858void Browser::SelectLastTab() {
859 UserMetrics::RecordAction(L"SelectLastTab", profile_);
860 tabstrip_model_.SelectLastTab();
861}
862
863void Browser::DuplicateTab() {
864 UserMetrics::RecordAction(L"Duplicate", profile_);
865 DuplicateContentsAt(selected_index());
866}
867
868void Browser::RestoreTab() {
869 UserMetrics::RecordAction(L"RestoreTab", profile_);
870 TabRestoreService* service = profile_->GetTabRestoreService();
871 if (!service)
872 return;
873
[email protected]d8375fd2008-11-25 22:45:39874 service->RestoreMostRecentEntry(this);
[email protected]fbd77592008-11-12 20:50:27875}
876
877void Browser::ConvertPopupToTabbedBrowser() {
878 UserMetrics::RecordAction(L"ShowAsTab", profile_);
[email protected]fbd77592008-11-12 20:50:27879 int tab_strip_index = tabstrip_model_.selected_index();
880 TabContents* contents = tabstrip_model_.DetachTabContentsAt(tab_strip_index);
[email protected]15952e462008-11-14 00:29:05881 Browser* browser = Browser::Create(profile_);
882 browser->tabstrip_model()->AppendTabContents(contents, true);
883 browser->window()->Show();
[email protected]fbd77592008-11-12 20:50:27884}
885
[email protected]9282cea2009-02-18 18:49:00886void Browser::ToggleFullscreenMode() {
887 UserMetrics::RecordAction(L"ToggleFullscreen", profile_);
888 window_->SetFullscreen(!window_->IsFullscreen());
[email protected]ae2622c2009-07-30 23:47:58889 // On Linux, setting fullscreen mode is an async call to the X server, which
890 // may or may not support fullscreen mode.
891#if !defined(OS_LINUX)
[email protected]9282cea2009-02-18 18:49:00892 UpdateCommandsForFullscreenMode(window_->IsFullscreen());
[email protected]ae2622c2009-07-30 23:47:58893#endif
[email protected]9282cea2009-02-18 18:49:00894}
895
[email protected]fbd77592008-11-12 20:50:27896void Browser::Exit() {
897 UserMetrics::RecordAction(L"Exit", profile_);
898 BrowserList::CloseAllBrowsers(true);
899}
900
[email protected]36b6dcb2008-11-12 01:19:57901void Browser::BookmarkCurrentPage() {
[email protected]fbd77592008-11-12 20:50:27902 UserMetrics::RecordAction(L"Star", profile_);
903
[email protected]b7ca4e62009-01-23 20:37:29904 TabContents* contents = GetSelectedTabContents();
[email protected]85408b7c2009-06-03 19:11:54905 if (!contents->ShouldDisplayURL())
906 return;
907 const GURL& url = contents->GetURL();
908 if (url.is_empty() || !url.is_valid())
909 return;
910 std::wstring title = UTF16ToWideHack(contents->GetTitle());
911
[email protected]b7ca4e62009-01-23 20:37:29912 BookmarkModel* model = contents->profile()->GetBookmarkModel();
[email protected]36b6dcb2008-11-12 01:19:57913 if (!model || !model->IsLoaded())
914 return; // Ignore requests until bookmarks are loaded.
915
[email protected]c50d0d42009-03-03 17:37:44916 bool was_bookmarked = model->IsBookmarked(url);
[email protected]85408b7c2009-06-03 19:11:54917 model->SetURLStarred(url, title, true);
[email protected]5f2731c52009-02-28 00:41:27918 if (window_->IsActive()) {
919 // Only show the bubble if the window is active, otherwise we may get into
920 // weird situations were the bubble is deleted as soon as it is shown.
[email protected]c50d0d42009-03-03 17:37:44921 window_->ShowBookmarkBubble(url, was_bookmarked);
[email protected]5f2731c52009-02-28 00:41:27922 }
[email protected]36b6dcb2008-11-12 01:19:57923}
924
[email protected]40bdb6d92009-02-25 00:22:27925void Browser::SavePage() {
926 UserMetrics::RecordAction(L"SavePage", profile_);
[email protected]57c6a652009-05-04 07:58:34927 GetSelectedTabContents()->OnSavePage();
[email protected]40bdb6d92009-02-25 00:22:27928}
929
[email protected]fbd77592008-11-12 20:50:27930void Browser::ViewSource() {
931 UserMetrics::RecordAction(L"ViewSource", profile_);
[email protected]36b6dcb2008-11-12 01:19:57932
[email protected]36b6dcb2008-11-12 01:19:57933 TabContents* current_tab = GetSelectedTabContents();
[email protected]ce3fa3c2009-04-20 19:55:57934 NavigationEntry* entry = current_tab->controller().GetLastCommittedEntry();
[email protected]fbd77592008-11-12 20:50:27935 if (entry) {
936 GURL url("view-source:" + entry->url().spec());
[email protected]749eea042009-01-05 22:35:54937 OpenURL(url, GURL(), NEW_FOREGROUND_TAB, PageTransition::LINK);
[email protected]36b6dcb2008-11-12 01:19:57938 }
939}
initial.commit09911bf2008-07-26 23:55:29940
[email protected]4801ecc2009-04-05 04:52:58941void Browser::ShowFindBar() {
942 find_bar_controller_->Show();
943}
944
[email protected]a3e18c42009-03-04 23:36:05945bool Browser::SupportsWindowFeature(WindowFeature feature) const {
946 unsigned int features = FEATURE_INFOBAR | FEATURE_DOWNLOADSHELF;
[email protected]653c9ea2009-05-06 16:58:56947 if (type() == TYPE_NORMAL) {
948 features |= FEATURE_BOOKMARKBAR;
949 features |= FEATURE_EXTENSIONSHELF;
950 }
[email protected]a3e18c42009-03-04 23:36:05951 if (!window_ || !window_->IsFullscreen()) {
952 if (type() == TYPE_NORMAL)
953 features |= FEATURE_TABSTRIP | FEATURE_TOOLBAR;
954 else
955 features |= FEATURE_TITLEBAR;
956 if ((type() & Browser::TYPE_APP) == 0)
957 features |= FEATURE_LOCATIONBAR;
958 }
959 return !!(features & feature);
960}
961
[email protected]c61db1d2009-02-06 03:39:18962#if defined(OS_WIN)
963
[email protected]fbd77592008-11-12 20:50:27964void Browser::ClosePopups() {
965 UserMetrics::RecordAction(L"CloseAllSuppressedPopups", profile_);
966 GetSelectedTabContents()->CloseAllSuppressedPopups();
967}
initial.commit09911bf2008-07-26 23:55:29968
[email protected]fbd77592008-11-12 20:50:27969void Browser::Print() {
970 UserMetrics::RecordAction(L"PrintPreview", profile_);
[email protected]57c6a652009-05-04 07:58:34971 GetSelectedTabContents()->PrintPreview();
[email protected]fbd77592008-11-12 20:50:27972}
[email protected]40d59ce52009-03-06 23:20:14973#endif // #if defined(OS_WIN)
[email protected]fbd77592008-11-12 20:50:27974
[email protected]fbd77592008-11-12 20:50:27975void Browser::ToggleEncodingAutoDetect() {
976 UserMetrics::RecordAction(L"AutoDetectChange", profile_);
977 encoding_auto_detect_.SetValue(!encoding_auto_detect_.GetValue());
978 // Reload the page so we can try to auto-detect the charset.
979 Reload();
980}
981
982void Browser::OverrideEncoding(int encoding_id) {
983 UserMetrics::RecordAction(L"OverrideEncoding", profile_);
984 const std::wstring selected_encoding =
985 CharacterEncoding::GetCanonicalEncodingNameByCommandId(encoding_id);
[email protected]57c6a652009-05-04 07:58:34986 TabContents* contents = GetSelectedTabContents();
987 if (!selected_encoding.empty() && contents)
988 contents->override_encoding(selected_encoding);
[email protected]fbd77592008-11-12 20:50:27989 // Update the list of recently selected encodings.
990 std::wstring new_selected_encoding_list;
991 if (CharacterEncoding::UpdateRecentlySelectdEncoding(
992 profile_->GetPrefs()->GetString(prefs::kRecentlySelectedEncoding),
993 encoding_id,
994 &new_selected_encoding_list)) {
995 profile_->GetPrefs()->SetString(prefs::kRecentlySelectedEncoding,
996 new_selected_encoding_list);
997 }
[email protected]36b6dcb2008-11-12 01:19:57998}
999
[email protected]40d59ce52009-03-06 23:20:141000#if defined(OS_WIN)
[email protected]84214982008-12-10 18:49:101001// TODO(devint): http://b/issue?id=1117225 Cut, Copy, and Paste are always
1002// enabled in the page menu regardless of whether the command will do
1003// anything. When someone selects the menu item, we just act as if they hit
1004// the keyboard shortcut for the command by sending the associated key press
1005// to windows. The real fix to this bug is to disable the commands when they
1006// won't do anything. We'll need something like an overall clipboard command
1007// manager to do that.
1008
1009void Browser::Cut() {
1010 UserMetrics::RecordAction(L"Cut", profile_);
1011 ui_controls::SendKeyPress(L'X', true, false, false);
[email protected]36b6dcb2008-11-12 01:19:571012}
1013
[email protected]84214982008-12-10 18:49:101014void Browser::Copy() {
1015 UserMetrics::RecordAction(L"Copy", profile_);
1016 ui_controls::SendKeyPress(L'C', true, false, false);
[email protected]36b6dcb2008-11-12 01:19:571017}
1018
[email protected]84214982008-12-10 18:49:101019void Browser::CopyCurrentPageURL() {
1020 UserMetrics::RecordAction(L"CopyURLToClipBoard", profile_);
1021 std::string url = GetSelectedTabContents()->GetURL().spec();
1022
1023 if (!::OpenClipboard(NULL)) {
1024 NOTREACHED();
1025 return;
1026 }
1027
1028 if (::EmptyClipboard()) {
1029 HGLOBAL text = ::GlobalAlloc(GMEM_MOVEABLE, url.size() + 1);
1030 LPSTR ptr = static_cast<LPSTR>(::GlobalLock(text));
1031 memcpy(ptr, url.c_str(), url.size());
1032 ptr[url.size()] = '\0';
1033 ::GlobalUnlock(text);
1034
1035 ::SetClipboardData(CF_TEXT, text);
1036 }
1037
1038 if (!::CloseClipboard()) {
1039 NOTREACHED();
1040 }
[email protected]36b6dcb2008-11-12 01:19:571041}
1042
[email protected]84214982008-12-10 18:49:101043void Browser::Paste() {
1044 UserMetrics::RecordAction(L"Paste", profile_);
1045 ui_controls::SendKeyPress(L'V', true, false, false);
1046}
[email protected]31b1bc3a2009-03-10 19:26:191047#endif // #if defined(OS_WIN)
[email protected]84214982008-12-10 18:49:101048
1049void Browser::Find() {
1050 UserMetrics::RecordAction(L"Find", profile_);
[email protected]4f3dc372009-02-24 00:10:291051 FindInPage(false, false);
[email protected]84214982008-12-10 18:49:101052}
1053
1054void Browser::FindNext() {
1055 UserMetrics::RecordAction(L"FindNext", profile_);
[email protected]4f3dc372009-02-24 00:10:291056 FindInPage(true, true);
[email protected]84214982008-12-10 18:49:101057}
1058
1059void Browser::FindPrevious() {
1060 UserMetrics::RecordAction(L"FindPrevious", profile_);
[email protected]4f3dc372009-02-24 00:10:291061 FindInPage(true, false);
[email protected]84214982008-12-10 18:49:101062}
1063
1064void Browser::ZoomIn() {
1065 UserMetrics::RecordAction(L"ZoomPlus", profile_);
[email protected]57c6a652009-05-04 07:58:341066 GetSelectedTabContents()->render_view_host()->Zoom(PageZoom::LARGER);
[email protected]84214982008-12-10 18:49:101067}
1068
1069void Browser::ZoomReset() {
1070 UserMetrics::RecordAction(L"ZoomNormal", profile_);
[email protected]57c6a652009-05-04 07:58:341071 GetSelectedTabContents()->render_view_host()->Zoom(PageZoom::STANDARD);
[email protected]84214982008-12-10 18:49:101072}
1073
1074void Browser::ZoomOut() {
1075 UserMetrics::RecordAction(L"ZoomMinus", profile_);
[email protected]57c6a652009-05-04 07:58:341076 GetSelectedTabContents()->render_view_host()->Zoom(PageZoom::SMALLER);
[email protected]84214982008-12-10 18:49:101077}
1078
1079void Browser::FocusToolbar() {
1080 UserMetrics::RecordAction(L"FocusToolbar", profile_);
1081 window_->FocusToolbar();
1082}
1083
1084void Browser::FocusLocationBar() {
1085 UserMetrics::RecordAction(L"FocusLocation", profile_);
[email protected]d56bcd22009-03-16 19:51:561086 window_->SetFocusToLocationBar();
[email protected]84214982008-12-10 18:49:101087}
1088
1089void Browser::FocusSearch() {
1090 // TODO(beng): replace this with FocusLocationBar
1091 UserMetrics::RecordAction(L"FocusSearch", profile_);
[email protected]7745b822009-01-27 20:15:351092 window_->GetLocationBar()->FocusSearch();
[email protected]84214982008-12-10 18:49:101093}
1094
1095void Browser::OpenFile() {
1096 UserMetrics::RecordAction(L"OpenFile", profile_);
1097 if (!select_file_dialog_.get())
1098 select_file_dialog_ = SelectFileDialog::Create(this);
1099
1100 // TODO(beng): figure out how to juggle this.
[email protected]d56bcd22009-03-16 19:51:561101 gfx::NativeWindow parent_window = window_->GetNativeHandle();
[email protected]84214982008-12-10 18:49:101102 select_file_dialog_->SelectFile(SelectFileDialog::SELECT_OPEN_FILE,
[email protected]561abe62009-04-06 18:08:341103 string16(), FilePath(),
[email protected]b949f1112009-04-12 20:03:081104 NULL, 0, FILE_PATH_LITERAL(""),
[email protected]d56bcd22009-03-16 19:51:561105 parent_window, NULL);
[email protected]84214982008-12-10 18:49:101106}
1107
1108void Browser::OpenCreateShortcutsDialog() {
1109 UserMetrics::RecordAction(L"CreateShortcut", profile_);
[email protected]98f6e022009-06-05 22:49:531110#if defined(OS_WIN)
[email protected]57c6a652009-05-04 07:58:341111 GetSelectedTabContents()->CreateShortcut();
[email protected]98f6e022009-06-05 22:49:531112#else
1113 NOTIMPLEMENTED();
1114#endif
[email protected]36b6dcb2008-11-12 01:19:571115}
1116
[email protected]c630f162009-07-22 09:41:331117void Browser::ToggleDevToolsWindow() {
[email protected]fbd77592008-11-12 20:50:271118 UserMetrics::RecordAction(L"ShowJSConsole", profile_);
[email protected]3061ccf32009-07-13 14:17:491119 DevToolsManager::GetInstance()->ToggleDevToolsWindow(
[email protected]d9f9b792009-06-24 13:17:121120 GetSelectedTabContents()->render_view_host());
[email protected]fbd77592008-11-12 20:50:271121}
1122
[email protected]84214982008-12-10 18:49:101123void Browser::OpenTaskManager() {
1124 UserMetrics::RecordAction(L"TaskManager", profile_);
[email protected]8f90afd72009-06-22 22:44:381125 window_->ShowTaskManager();
[email protected]84214982008-12-10 18:49:101126}
1127
1128void Browser::OpenSelectProfileDialog() {
[email protected]12a6f0362009-03-09 19:37:361129 const CommandLine& command_line = *CommandLine::ForCurrentProcess();
1130 if (!command_line.HasSwitch(switches::kEnableUserDataDirProfiles))
1131 return;
[email protected]84214982008-12-10 18:49:101132 UserMetrics::RecordAction(L"SelectProfile", profile_);
[email protected]505323e22009-01-24 02:47:581133 window_->ShowSelectProfileDialog();
[email protected]84214982008-12-10 18:49:101134}
1135
1136void Browser::OpenNewProfileDialog() {
[email protected]ac926362009-02-26 01:33:181137 const CommandLine& command_line = *CommandLine::ForCurrentProcess();
1138 if (!command_line.HasSwitch(switches::kEnableUserDataDirProfiles))
1139 return;
[email protected]84214982008-12-10 18:49:101140 UserMetrics::RecordAction(L"CreateProfile", profile_);
[email protected]505323e22009-01-24 02:47:581141 window_->ShowNewProfileDialog();
[email protected]84214982008-12-10 18:49:101142}
1143
1144void Browser::OpenBugReportDialog() {
1145 UserMetrics::RecordAction(L"ReportBug", profile_);
1146 window_->ShowReportBugDialog();
1147}
[email protected]44b2c8852009-03-18 00:57:491148
[email protected]84214982008-12-10 18:49:101149void Browser::ToggleBookmarkBar() {
1150 UserMetrics::RecordAction(L"ShowBookmarksBar", profile_);
1151 window_->ToggleBookmarkBar();
1152}
1153
[email protected]84214982008-12-10 18:49:101154void Browser::OpenBookmarkManager() {
1155 UserMetrics::RecordAction(L"ShowBookmarkManager", profile_);
1156 window_->ShowBookmarkManager();
1157}
[email protected]8bf80e922009-03-09 20:56:361158
1159void Browser::ShowHistoryTab() {
1160 UserMetrics::RecordAction(L"ShowHistory", profile_);
[email protected]b689fce72009-03-17 22:45:341161 ShowSingleDOMUITab(GURL(chrome::kChromeUIHistoryURL));
[email protected]8bf80e922009-03-09 20:56:361162}
[email protected]84214982008-12-10 18:49:101163
1164void Browser::ShowDownloadsTab() {
1165 UserMetrics::RecordAction(L"ShowDownloads", profile_);
[email protected]b689fce72009-03-17 22:45:341166 ShowSingleDOMUITab(GURL(chrome::kChromeUIDownloadsURL));
[email protected]84214982008-12-10 18:49:101167}
1168
1169void Browser::OpenClearBrowsingDataDialog() {
1170 UserMetrics::RecordAction(L"ClearBrowsingData_ShowDlg", profile_);
1171 window_->ShowClearBrowsingDataDialog();
1172}
1173
[email protected]84214982008-12-10 18:49:101174void Browser::OpenOptionsDialog() {
1175 UserMetrics::RecordAction(L"ShowOptions", profile_);
1176 ShowOptionsWindow(OPTIONS_PAGE_DEFAULT, OPTIONS_GROUP_NONE, profile_);
1177}
1178
1179void Browser::OpenKeywordEditor() {
1180 UserMetrics::RecordAction(L"EditSearchEngines", profile_);
1181 window_->ShowSearchEnginesDialog();
[email protected]fbd77592008-11-12 20:50:271182}
1183
1184void Browser::OpenPasswordManager() {
[email protected]2d46c842008-11-14 19:24:311185 window_->ShowPasswordManager();
[email protected]fbd77592008-11-12 20:50:271186}
1187
[email protected]1bdf29e2009-05-11 23:45:251188void Browser::OpenImportSettingsDialog() {
1189 UserMetrics::RecordAction(L"Import_ShowDlg", profile_);
1190 window_->ShowImportDialog();
1191}
[email protected]1bdf29e2009-05-11 23:45:251192
[email protected]fbd77592008-11-12 20:50:271193void Browser::OpenAboutChromeDialog() {
1194 UserMetrics::RecordAction(L"AboutChrome", profile_);
[email protected]2d46c842008-11-14 19:24:311195 window_->ShowAboutChromeDialog();
[email protected]fbd77592008-11-12 20:50:271196}
1197
[email protected]fbd77592008-11-12 20:50:271198void Browser::OpenHelpTab() {
[email protected]40d59ce52009-03-06 23:20:141199 GURL help_url(WideToASCII(l10n_util::GetString(IDS_HELP_CONTENT_URL)));
[email protected]22735af62009-04-07 21:09:581200 AddTabWithURL(help_url, GURL(), PageTransition::AUTO_BOOKMARK, true, -1,
[email protected]5a4940be2009-05-06 06:44:391201 false, NULL);
[email protected]fbd77592008-11-12 20:50:271202}
1203
[email protected]16779842009-07-08 23:45:291204#if defined(OS_CHROMEOS)
[email protected]be715072009-07-07 15:43:201205void Browser::ShowControlPanel() {
1206 GURL url("http://localhost:8080");
1207 AddTabWithURL(url, GURL(), PageTransition::AUTO_BOOKMARK, true, -1,
1208 false, NULL);
1209}
1210#endif
1211
[email protected]36b6dcb2008-11-12 01:19:571212///////////////////////////////////////////////////////////////////////////////
1213
1214// static
1215void Browser::RegisterPrefs(PrefService* prefs) {
1216 prefs->RegisterDictionaryPref(prefs::kBrowserWindowPlacement);
1217 prefs->RegisterIntegerPref(prefs::kOptionsWindowLastTabIndex, 0);
[email protected]749380bb2009-07-20 08:57:551218 prefs->RegisterIntegerPref(prefs::kDevToolsSplitLocation, -1);
[email protected]36b6dcb2008-11-12 01:19:571219}
1220
1221// static
1222void Browser::RegisterUserPrefs(PrefService* prefs) {
1223 prefs->RegisterStringPref(prefs::kHomePage, L"chrome-internal:");
1224 prefs->RegisterBooleanPref(prefs::kHomePageIsNewTabPage, true);
1225 prefs->RegisterIntegerPref(prefs::kCookieBehavior,
1226 net::CookiePolicy::ALLOW_ALL_COOKIES);
1227 prefs->RegisterBooleanPref(prefs::kShowHomeButton, false);
[email protected]93a2c7242009-07-07 18:43:091228#if defined(OS_MACOSX)
1229 // This really belongs in platform code, but there's no good place to
1230 // initialize it between the time when the AppController is created
1231 // (where there's no profile) and the time the controller gets another
1232 // crack at the start of the main event loop. By that time, BrowserInit
1233 // has already created the browser window, and it's too late: we need the
1234 // pref to be already initialized. Doing it here also saves us from having
1235 // to hard-code pref registration in the several unit tests that use
1236 // this preference.
1237 prefs->RegisterBooleanPref(prefs::kShowPageOptionsButtons, false);
1238#endif
[email protected]36b6dcb2008-11-12 01:19:571239 prefs->RegisterStringPref(prefs::kRecentlySelectedEncoding, L"");
[email protected]36b6dcb2008-11-12 01:19:571240 prefs->RegisterBooleanPref(prefs::kDeleteBrowsingHistory, true);
1241 prefs->RegisterBooleanPref(prefs::kDeleteDownloadHistory, true);
1242 prefs->RegisterBooleanPref(prefs::kDeleteCache, true);
1243 prefs->RegisterBooleanPref(prefs::kDeleteCookies, true);
1244 prefs->RegisterBooleanPref(prefs::kDeletePasswords, false);
1245 prefs->RegisterBooleanPref(prefs::kDeleteFormData, true);
1246 prefs->RegisterIntegerPref(prefs::kDeleteTimePeriod, 0);
[email protected]48b47ffa2009-05-02 07:18:301247 prefs->RegisterBooleanPref(prefs::kCheckDefaultBrowser, true);
[email protected]e116a522009-06-04 20:10:311248 prefs->RegisterBooleanPref(prefs::kUseCustomChromeFrame, false);
[email protected]c8865482009-07-23 20:40:101249 prefs->RegisterBooleanPref(prefs::kShowOmniboxSearchHint, true);
[email protected]36b6dcb2008-11-12 01:19:571250}
1251
1252// static
1253Browser* Browser::GetBrowserForController(
1254 const NavigationController* controller, int* index_result) {
1255 BrowserList::const_iterator it;
1256 for (it = BrowserList::begin(); it != BrowserList::end(); ++it) {
[email protected]902cdf772009-05-06 15:08:121257 int index = (*it)->tabstrip_model_.GetIndexOfController(controller);
[email protected]36b6dcb2008-11-12 01:19:571258 if (index != TabStripModel::kNoTab) {
1259 if (index_result)
1260 *index_result = index;
1261 return *it;
1262 }
1263 }
1264
1265 return NULL;
1266}
1267
[email protected]485fba42009-03-24 23:27:291268void Browser::ExecuteCommandWithDisposition(
1269 int id, WindowOpenDisposition disposition) {
[email protected]1fc025202009-01-20 23:03:141270 // No commands are enabled if there is not yet any selected tab.
1271 // TODO(pkasting): It seems like we should not need this, because either
1272 // most/all commands should not have been enabled yet anyway or the ones that
1273 // are enabled should be global, or safe themselves against having no selected
1274 // tab. However, Ben says he tried removing this before and got lots of
1275 // crashes, e.g. from Windows sending WM_COMMANDs at random times during
1276 // window construction. This probably could use closer examination someday.
1277 if (!GetSelectedTabContents())
1278 return;
1279
1280 DCHECK(command_updater_.IsCommandEnabled(id)) << "Invalid/disabled command";
[email protected]36b6dcb2008-11-12 01:19:571281
[email protected]fbd77592008-11-12 20:50:271282 // The order of commands in this switch statement must match the function
1283 // declaration order in browser.h!
[email protected]36b6dcb2008-11-12 01:19:571284 switch (id) {
[email protected]84214982008-12-10 18:49:101285 // Navigation commands
[email protected]485fba42009-03-24 23:27:291286 case IDC_BACK: GoBack(disposition); break;
1287 case IDC_FORWARD: GoForward(disposition); break;
[email protected]cb525c82008-12-08 23:04:541288 case IDC_RELOAD: Reload(); break;
[email protected]485fba42009-03-24 23:27:291289 case IDC_HOME: Home(disposition); break;
[email protected]cb525c82008-12-08 23:04:541290 case IDC_OPEN_CURRENT_URL: OpenCurrentURL(); break;
[email protected]485fba42009-03-24 23:27:291291 case IDC_GO: Go(disposition); break;
[email protected]84214982008-12-10 18:49:101292 case IDC_STOP: Stop(); break;
[email protected]36b6dcb2008-11-12 01:19:571293
[email protected]84214982008-12-10 18:49:101294 // Window management commands
[email protected]cb525c82008-12-08 23:04:541295 case IDC_NEW_WINDOW: NewWindow(); break;
1296 case IDC_NEW_INCOGNITO_WINDOW: NewIncognitoWindow(); break;
[email protected]84214982008-12-10 18:49:101297 case IDC_NEW_WINDOW_PROFILE_0:
1298 case IDC_NEW_WINDOW_PROFILE_1:
1299 case IDC_NEW_WINDOW_PROFILE_2:
1300 case IDC_NEW_WINDOW_PROFILE_3:
1301 case IDC_NEW_WINDOW_PROFILE_4:
1302 case IDC_NEW_WINDOW_PROFILE_5:
1303 case IDC_NEW_WINDOW_PROFILE_6:
1304 case IDC_NEW_WINDOW_PROFILE_7:
[email protected]f21c613a2009-02-12 14:46:171305 case IDC_NEW_WINDOW_PROFILE_8:
[email protected]84214982008-12-10 18:49:101306 NewProfileWindowByIndex(id - IDC_NEW_WINDOW_PROFILE_0); break;
[email protected]cb525c82008-12-08 23:04:541307 case IDC_CLOSE_WINDOW: CloseWindow(); break;
[email protected]84214982008-12-10 18:49:101308 case IDC_NEW_TAB: NewTab(); break;
1309 case IDC_CLOSE_TAB: CloseTab(); break;
[email protected]cb525c82008-12-08 23:04:541310 case IDC_SELECT_NEXT_TAB: SelectNextTab(); break;
1311 case IDC_SELECT_PREVIOUS_TAB: SelectPreviousTab(); break;
[email protected]36b6dcb2008-11-12 01:19:571312 case IDC_SELECT_TAB_0:
1313 case IDC_SELECT_TAB_1:
1314 case IDC_SELECT_TAB_2:
1315 case IDC_SELECT_TAB_3:
1316 case IDC_SELECT_TAB_4:
1317 case IDC_SELECT_TAB_5:
1318 case IDC_SELECT_TAB_6:
[email protected]cb525c82008-12-08 23:04:541319 case IDC_SELECT_TAB_7: SelectNumberedTab(id - IDC_SELECT_TAB_0);
1320 break;
1321 case IDC_SELECT_LAST_TAB: SelectLastTab(); break;
1322 case IDC_DUPLICATE_TAB: DuplicateTab(); break;
1323 case IDC_RESTORE_TAB: RestoreTab(); break;
1324 case IDC_SHOW_AS_TAB: ConvertPopupToTabbedBrowser(); break;
[email protected]9282cea2009-02-18 18:49:001325 case IDC_FULLSCREEN: ToggleFullscreenMode(); break;
[email protected]cb525c82008-12-08 23:04:541326 case IDC_EXIT: Exit(); break;
[email protected]36b6dcb2008-11-12 01:19:571327
[email protected]84214982008-12-10 18:49:101328 // Page-related commands
[email protected]40bdb6d92009-02-25 00:22:271329 case IDC_SAVE_PAGE: SavePage(); break;
[email protected]cb525c82008-12-08 23:04:541330 case IDC_STAR: BookmarkCurrentPage(); break;
1331 case IDC_VIEW_SOURCE: ViewSource(); break;
[email protected]c61db1d2009-02-06 03:39:181332#if defined(OS_WIN)
[email protected]cb525c82008-12-08 23:04:541333 case IDC_CLOSE_POPUPS: ClosePopups(); break;
1334 case IDC_PRINT: Print(); break;
[email protected]40d59ce52009-03-06 23:20:141335#endif
[email protected]cb525c82008-12-08 23:04:541336 case IDC_ENCODING_AUTO_DETECT: ToggleEncodingAutoDetect(); break;
[email protected]36b6dcb2008-11-12 01:19:571337 case IDC_ENCODING_UTF8:
1338 case IDC_ENCODING_UTF16LE:
1339 case IDC_ENCODING_ISO88591:
1340 case IDC_ENCODING_WINDOWS1252:
[email protected]1c5bf632008-12-11 20:30:491341 case IDC_ENCODING_GBK:
[email protected]36b6dcb2008-11-12 01:19:571342 case IDC_ENCODING_GB18030:
1343 case IDC_ENCODING_BIG5HKSCS:
1344 case IDC_ENCODING_BIG5:
1345 case IDC_ENCODING_KOREAN:
1346 case IDC_ENCODING_SHIFTJIS:
1347 case IDC_ENCODING_ISO2022JP:
1348 case IDC_ENCODING_EUCJP:
1349 case IDC_ENCODING_THAI:
1350 case IDC_ENCODING_ISO885915:
1351 case IDC_ENCODING_MACINTOSH:
1352 case IDC_ENCODING_ISO88592:
1353 case IDC_ENCODING_WINDOWS1250:
1354 case IDC_ENCODING_ISO88595:
1355 case IDC_ENCODING_WINDOWS1251:
1356 case IDC_ENCODING_KOI8R:
1357 case IDC_ENCODING_KOI8U:
1358 case IDC_ENCODING_ISO88597:
1359 case IDC_ENCODING_WINDOWS1253:
1360 case IDC_ENCODING_ISO88594:
1361 case IDC_ENCODING_ISO885913:
1362 case IDC_ENCODING_WINDOWS1257:
1363 case IDC_ENCODING_ISO88593:
1364 case IDC_ENCODING_ISO885910:
1365 case IDC_ENCODING_ISO885914:
1366 case IDC_ENCODING_ISO885916:
[email protected]36b6dcb2008-11-12 01:19:571367 case IDC_ENCODING_WINDOWS1254:
1368 case IDC_ENCODING_ISO88596:
1369 case IDC_ENCODING_WINDOWS1256:
1370 case IDC_ENCODING_ISO88598:
[email protected]e13271f2009-03-07 00:26:001371 case IDC_ENCODING_ISO88598I:
[email protected]36b6dcb2008-11-12 01:19:571372 case IDC_ENCODING_WINDOWS1255:
[email protected]cb525c82008-12-08 23:04:541373 case IDC_ENCODING_WINDOWS1258: OverrideEncoding(id); break;
[email protected]36b6dcb2008-11-12 01:19:571374
[email protected]40d59ce52009-03-06 23:20:141375#if defined(OS_WIN)
[email protected]84214982008-12-10 18:49:101376 // Clipboard commands
1377 case IDC_CUT: Cut(); break;
1378 case IDC_COPY: Copy(); break;
1379 case IDC_COPY_URL: CopyCurrentPageURL(); break;
1380 case IDC_PASTE: Paste(); break;
[email protected]31b1bc3a2009-03-10 19:26:191381#endif
[email protected]84214982008-12-10 18:49:101382
1383 // Find-in-page
1384 case IDC_FIND: Find(); break;
1385 case IDC_FIND_NEXT: FindNext(); break;
1386 case IDC_FIND_PREVIOUS: FindPrevious(); break;
1387
1388 // Zoom
1389 case IDC_ZOOM_PLUS: ZoomIn(); break;
1390 case IDC_ZOOM_NORMAL: ZoomReset(); break;
1391 case IDC_ZOOM_MINUS: ZoomOut(); break;
1392
1393 // Focus various bits of UI
1394 case IDC_FOCUS_TOOLBAR: FocusToolbar(); break;
1395 case IDC_FOCUS_LOCATION: FocusLocationBar(); break;
1396 case IDC_FOCUS_SEARCH: FocusSearch(); break;
1397
1398 // Show various bits of UI
1399 case IDC_OPEN_FILE: OpenFile(); break;
1400 case IDC_CREATE_SHORTCUTS: OpenCreateShortcutsDialog(); break;
[email protected]c630f162009-07-22 09:41:331401 case IDC_DEV_TOOLS: ToggleDevToolsWindow(); break;
[email protected]cb525c82008-12-08 23:04:541402 case IDC_TASK_MANAGER: OpenTaskManager(); break;
[email protected]cb525c82008-12-08 23:04:541403 case IDC_SELECT_PROFILE: OpenSelectProfileDialog(); break;
1404 case IDC_NEW_PROFILE: OpenNewProfileDialog(); break;
[email protected]84214982008-12-10 18:49:101405 case IDC_REPORT_BUG: OpenBugReportDialog(); break;
[email protected]44b2c8852009-03-18 00:57:491406
[email protected]84214982008-12-10 18:49:101407 case IDC_SHOW_BOOKMARK_BAR: ToggleBookmarkBar(); break;
[email protected]44b2c8852009-03-18 00:57:491408
[email protected]84214982008-12-10 18:49:101409 case IDC_SHOW_BOOKMARK_MANAGER: OpenBookmarkManager(); break;
[email protected]8bf80e922009-03-09 20:56:361410 case IDC_SHOW_HISTORY: ShowHistoryTab(); break;
[email protected]84214982008-12-10 18:49:101411 case IDC_SHOW_DOWNLOADS: ShowDownloadsTab(); break;
[email protected]8bf80e922009-03-09 20:56:361412#if defined(OS_WIN)
[email protected]026e34a2009-02-06 00:06:121413#ifdef CHROME_PERSONALIZATION
1414 case IDC_P13N_INFO:
1415 Personalization::HandleMenuItemClick(profile()); break;
1416#endif
[email protected]0e3e3e32009-05-14 01:00:531417#endif
[email protected]84214982008-12-10 18:49:101418 case IDC_OPTIONS: OpenOptionsDialog(); break;
1419 case IDC_EDIT_SEARCH_ENGINES: OpenKeywordEditor(); break;
1420 case IDC_VIEW_PASSWORDS: OpenPasswordManager(); break;
[email protected]25364e12009-05-22 01:37:191421 case IDC_CLEAR_BROWSING_DATA: OpenClearBrowsingDataDialog(); break;
[email protected]1bdf29e2009-05-11 23:45:251422 case IDC_IMPORT_SETTINGS: OpenImportSettingsDialog(); break;
[email protected]4dbac172009-04-24 20:23:491423 case IDC_ABOUT: OpenAboutChromeDialog(); break;
[email protected]40d59ce52009-03-06 23:20:141424 case IDC_HELP_PAGE: OpenHelpTab(); break;
[email protected]16779842009-07-08 23:45:291425#if defined(OS_CHROMEOS)
[email protected]be715072009-07-07 15:43:201426 case IDC_CONTROL_PANEL: ShowControlPanel(); break;
1427#endif
[email protected]d938aed92009-01-22 19:49:331428
[email protected]36b6dcb2008-11-12 01:19:571429 default:
[email protected]84214982008-12-10 18:49:101430 LOG(WARNING) << "Received Unimplemented Command: " << id;
[email protected]fbd77592008-11-12 20:50:271431 break;
[email protected]36b6dcb2008-11-12 01:19:571432 }
1433}
1434
1435///////////////////////////////////////////////////////////////////////////////
[email protected]485fba42009-03-24 23:27:291436// Browser, CommandUpdater::CommandUpdaterDelegate implementation:
1437
1438void Browser::ExecuteCommand(int id) {
1439 ExecuteCommandWithDisposition(id, CURRENT_TAB);
1440}
1441
1442///////////////////////////////////////////////////////////////////////////////
[email protected]36b6dcb2008-11-12 01:19:571443// Browser, TabStripModelDelegate implementation:
1444
[email protected]22735af62009-04-07 21:09:581445TabContents* Browser::AddBlankTab(bool foreground) {
1446 return AddBlankTabAt(-1, foreground);
1447}
1448
1449TabContents* Browser::AddBlankTabAt(int index, bool foreground) {
1450 return AddTabWithURL(GURL(chrome::kChromeUINewTabURL), GURL(),
[email protected]5a4940be2009-05-06 06:44:391451 PageTransition::TYPED, foreground, index, false, NULL);
[email protected]15952e462008-11-14 00:29:051452}
1453
[email protected]3d1104f2009-03-26 15:30:281454Browser* Browser::CreateNewStripWithContents(TabContents* detached_contents,
1455 const gfx::Rect& window_bounds,
1456 const DockInfo& dock_info) {
[email protected]299dabd2008-11-19 02:27:161457 DCHECK(type_ == TYPE_NORMAL);
[email protected]adf650f2008-12-09 16:10:061458
[email protected]5e495462008-11-20 23:07:411459 gfx::Rect new_window_bounds = window_bounds;
1460 bool maximize = false;
1461 if (dock_info.GetNewWindowBounds(&new_window_bounds, &maximize))
1462 dock_info.AdjustOtherWindowBounds();
1463
[email protected]36b6dcb2008-11-12 01:19:571464 // Create an empty new browser window the same size as the old one.
[email protected]299dabd2008-11-19 02:27:161465 Browser* browser = new Browser(TYPE_NORMAL, profile_);
[email protected]5e495462008-11-20 23:07:411466 browser->set_override_bounds(new_window_bounds);
[email protected]2e716622009-03-09 21:11:011467 browser->set_maximized_state(
1468 maximize ? MAXIMIZED_STATE_MAXIMIZED : MAXIMIZED_STATE_UNMAXIMIZED);
[email protected]15952e462008-11-14 00:29:051469 browser->CreateBrowserWindow();
1470 browser->tabstrip_model()->AppendTabContents(detached_contents, true);
[email protected]159f7762008-12-19 14:58:271471 // Make sure the loading state is updated correctly, otherwise the throbber
1472 // won't start if the page is loading.
1473 browser->LoadingStateChanged(detached_contents);
[email protected]3d1104f2009-03-26 15:30:281474 return browser;
[email protected]36b6dcb2008-11-12 01:19:571475}
1476
[email protected]7c0560f2009-07-07 18:44:311477void Browser::ContinueDraggingDetachedTab(TabContents* contents,
1478 const gfx::Rect& window_bounds,
1479 const gfx::Rect& tab_bounds) {
1480 Browser* browser = new Browser(TYPE_NORMAL, profile_);
1481 browser->set_override_bounds(window_bounds);
1482 browser->CreateBrowserWindow();
1483 browser->tabstrip_model()->AppendTabContents(contents, true);
1484 browser->LoadingStateChanged(contents);
1485 browser->window()->Show();
1486 browser->window()->ContinueDraggingDetachedTab(tab_bounds);
1487}
1488
[email protected]36b6dcb2008-11-12 01:19:571489int Browser::GetDragActions() const {
[email protected]d54f6a002009-03-18 17:17:251490 return TAB_TEAROFF_ACTION | (tab_count() > 1 ? TAB_MOVE_ACTION : 0);
[email protected]36b6dcb2008-11-12 01:19:571491}
1492
1493TabContents* Browser::CreateTabContentsForURL(
1494 const GURL& url, const GURL& referrer, Profile* profile,
1495 PageTransition::Type transition, bool defer_load,
1496 SiteInstance* instance) const {
[email protected]57c6a652009-05-04 07:58:341497 TabContents* contents = new TabContents(profile, instance,
[email protected]9423d9412009-04-14 22:13:551498 MSG_ROUTING_NONE, NULL);
[email protected]36b6dcb2008-11-12 01:19:571499
[email protected]a17a0342009-07-29 23:12:271500 // Ensure that the new TabContentsView begins at the same size as the
1501 // previous TabContentsView if it existed. Otherwise, the initial WebKit
1502 // layout will be performed based on a width of 0 pixels, causing a
1503 // very long, narrow, inaccurate layout. Because some scripts on pages (as
1504 // well as WebKit's anchor link location calculation) are run on the initial
1505 // layout and not recalculated later, we need to ensure the first layout is
1506 // performed with sane view dimensions even when we're opening a new
1507 // background tab.
1508 if (TabContents* old_contents = tabstrip_model_.GetSelectedTabContents())
1509 contents->view()->SizeContents(old_contents->view()->GetContainerSize());
1510
[email protected]36b6dcb2008-11-12 01:19:571511 if (!defer_load) {
1512 // Load the initial URL before adding the new tab contents to the tab strip
1513 // so that the tab contents has navigation state.
[email protected]ce3fa3c2009-04-20 19:55:571514 contents->controller().LoadURL(url, referrer, transition);
[email protected]36b6dcb2008-11-12 01:19:571515 }
1516
1517 return contents;
1518}
1519
1520bool Browser::CanDuplicateContentsAt(int index) {
[email protected]ce3fa3c2009-04-20 19:55:571521 NavigationController& nc = GetTabContentsAt(index)->controller();
1522 return nc.tab_contents() && nc.GetLastCommittedEntry();
[email protected]36b6dcb2008-11-12 01:19:571523}
1524
1525void Browser::DuplicateContentsAt(int index) {
1526 TabContents* contents = GetTabContentsAt(index);
1527 TabContents* new_contents = NULL;
1528 DCHECK(contents);
[email protected]5c0e6482009-07-14 20:20:091529 bool pinned = false;
[email protected]36b6dcb2008-11-12 01:19:571530
[email protected]299dabd2008-11-19 02:27:161531 if (type_ == TYPE_NORMAL) {
[email protected]36b6dcb2008-11-12 01:19:571532 // If this is a tabbed browser, just create a duplicate tab inside the same
1533 // window next to the tab being duplicated.
[email protected]ce3fa3c2009-04-20 19:55:571534 new_contents = contents->Clone();
[email protected]5c0e6482009-07-14 20:20:091535 // Make sure we force the index, otherwise the duplicate tab may appear at
1536 // the wrong location.
1537 tabstrip_model_.AddTabContents(new_contents, index + 1, true,
[email protected]36b6dcb2008-11-12 01:19:571538 PageTransition::LINK, true);
[email protected]5c0e6482009-07-14 20:20:091539 if (tabstrip_model_.IsTabPinned(index)) {
1540 pinned = true;
1541 tabstrip_model_.SetTabPinned(index + 1, true);
1542 }
[email protected]36b6dcb2008-11-12 01:19:571543 } else {
[email protected]15952e462008-11-14 00:29:051544 Browser* browser = NULL;
[email protected]d5fbc002009-02-27 22:12:581545 if (type_ & TYPE_APP) {
1546 browser = Browser::CreateForApp(app_name_, profile_, type_ & TYPE_POPUP);
[email protected]299dabd2008-11-19 02:27:161547 } else if (type_ == TYPE_POPUP) {
[email protected]15952e462008-11-14 00:29:051548 browser = Browser::CreateForPopup(profile_);
1549 }
[email protected]36b6dcb2008-11-12 01:19:571550
[email protected]b1fed962008-12-18 00:54:081551 // Preserve the size of the original window. The new window has already
1552 // been given an offset by the OS, so we shouldn't copy the old bounds.
1553 BrowserWindow* new_window = browser->window();
[email protected]dae12ee62009-07-29 20:02:051554 new_window->SetBounds(gfx::Rect(new_window->GetRestoredBounds().origin(),
1555 window()->GetRestoredBounds().size()));
[email protected]b1fed962008-12-18 00:54:081556
[email protected]36b6dcb2008-11-12 01:19:571557 // We need to show the browser now. Otherwise ContainerWin assumes the
1558 // TabContents is invisible and won't size it.
[email protected]15952e462008-11-14 00:29:051559 browser->window()->Show();
[email protected]36b6dcb2008-11-12 01:19:571560
1561 // The page transition below is only for the purpose of inserting the tab.
[email protected]15952e462008-11-14 00:29:051562 new_contents = browser->AddTabWithNavigationController(
[email protected]ce3fa3c2009-04-20 19:55:571563 &contents->Clone()->controller(),
[email protected]36b6dcb2008-11-12 01:19:571564 PageTransition::LINK);
[email protected]36b6dcb2008-11-12 01:19:571565 }
1566
1567 if (profile_->HasSessionService()) {
1568 SessionService* session_service = profile_->GetSessionService();
1569 if (session_service)
[email protected]5c0e6482009-07-14 20:20:091570 session_service->TabRestored(&new_contents->controller(), pinned);
[email protected]36b6dcb2008-11-12 01:19:571571 }
1572}
1573
[email protected]36b6dcb2008-11-12 01:19:571574void Browser::CloseFrameAfterDragSession() {
[email protected]9aefecc92009-06-10 21:31:321575#if defined(OS_WIN) || defined(OS_LINUX)
[email protected]36b6dcb2008-11-12 01:19:571576 // This is scheduled to run after we return to the message loop because
1577 // otherwise the frame will think the drag session is still active and ignore
1578 // the request.
[email protected]d6a3c772009-01-27 19:41:201579 // TODO(port): figure out what is required here in a cross-platform world
[email protected]36b6dcb2008-11-12 01:19:571580 MessageLoop::current()->PostTask(FROM_HERE,
1581 method_factory_.NewRunnableMethod(&Browser::CloseFrame));
[email protected]d6a3c772009-01-27 19:41:201582#endif
initial.commit09911bf2008-07-26 23:55:291583}
1584
[email protected]505323e22009-01-24 02:47:581585void Browser::CreateHistoricalTab(TabContents* contents) {
1586 // We don't create historical tabs for incognito windows or windows without
1587 // profiles.
1588 if (!profile() || profile()->IsOffTheRecord() ||
1589 !profile()->GetTabRestoreService()) {
1590 return;
1591 }
1592
1593 // We only create historical tab entries for normal tabbed browser windows.
1594 if (type() == TYPE_NORMAL) {
1595 profile()->GetTabRestoreService()->CreateHistoricalTab(
[email protected]ce3fa3c2009-04-20 19:55:571596 &contents->controller());
[email protected]505323e22009-01-24 02:47:581597 }
1598}
1599
1600bool Browser::RunUnloadListenerBeforeClosing(TabContents* contents) {
[email protected]57c6a652009-05-04 07:58:341601 // If the TabContents is not connected yet, then there's no unload
1602 // handler we can fire even if the TabContents has an unload listener.
1603 // One case where we hit this is in a tab that has an infinite loop
1604 // before load.
1605 if (TabHasUnloadListener(contents)) {
1606 // If the page has unload listeners, then we tell the renderer to fire
1607 // them. Once they have fired, we'll get a message back saying whether
1608 // to proceed closing the page or not, which sends us back to this method
1609 // with the HasUnloadListener bit cleared.
[email protected]ae23c272009-07-27 20:15:401610 contents->render_view_host()->FirePageBeforeUnload(false);
[email protected]57c6a652009-05-04 07:58:341611 return true;
[email protected]505323e22009-01-24 02:47:581612 }
1613 return false;
1614}
1615
[email protected]940ccb22009-04-30 17:11:101616bool Browser::CanCloseContentsAt(int index) {
1617 if (tabstrip_model_.count() > 1)
1618 return true;
1619 // We are closing the last tab for this browser. Make sure to check for
1620 // in-progress downloads.
1621 // Note that the next call when it returns false will ask the user for
1622 // confirmation before closing the browser if the user decides so.
1623 return CanCloseWithInProgressDownloads();
1624}
[email protected]d6a3c772009-01-27 19:41:201625
[email protected]2d46c842008-11-14 19:24:311626///////////////////////////////////////////////////////////////////////////////
[email protected]36b6dcb2008-11-12 01:19:571627// Browser, TabStripModelObserver implementation:
1628
1629void Browser::TabInsertedAt(TabContents* contents,
1630 int index,
1631 bool foreground) {
1632 contents->set_delegate(this);
[email protected]ce3fa3c2009-04-20 19:55:571633 contents->controller().SetWindowID(session_id());
[email protected]36b6dcb2008-11-12 01:19:571634
1635 SyncHistoryWithTabs(tabstrip_model_.GetIndexOfTabContents(contents));
1636
[email protected]159f7762008-12-19 14:58:271637 // Make sure the loading state is updated correctly, otherwise the throbber
1638 // won't start if the page is loading.
1639 LoadingStateChanged(contents);
1640
[email protected]36b6dcb2008-11-12 01:19:571641 // If the tab crashes in the beforeunload or unload handler, it won't be
1642 // able to ack. But we know we can close it.
[email protected]0cb94102009-05-22 19:51:211643 registrar_.Add(this, NotificationType::TAB_CONTENTS_DISCONNECTED,
1644 Source<TabContents>(contents));
[email protected]36b6dcb2008-11-12 01:19:571645}
1646
1647void Browser::TabClosingAt(TabContents* contents, int index) {
[email protected]bfd04a62009-02-01 18:16:561648 NotificationService::current()->Notify(
1649 NotificationType::TAB_CLOSING,
[email protected]ce3fa3c2009-04-20 19:55:571650 Source<NavigationController>(&contents->controller()),
[email protected]bfd04a62009-02-01 18:16:561651 NotificationService::NoDetails());
[email protected]36b6dcb2008-11-12 01:19:571652
1653 // Sever the TabContents' connection back to us.
1654 contents->set_delegate(NULL);
1655}
1656
1657void Browser::TabDetachedAt(TabContents* contents, int index) {
[email protected]aacfcc72009-05-27 19:39:541658 // Save what the user's currently typing.
1659 window_->GetLocationBar()->SaveStateToContents(contents);
1660
[email protected]36b6dcb2008-11-12 01:19:571661 contents->set_delegate(NULL);
1662 if (!tabstrip_model_.closing_all())
1663 SyncHistoryWithTabs(0);
1664
1665 RemoveScheduledUpdatesFor(contents);
1666
[email protected]4801ecc2009-04-05 04:52:581667 if (find_bar_controller_.get() && index == tabstrip_model_.selected_index())
[email protected]57c6a652009-05-04 07:58:341668 find_bar_controller_->ChangeTabContents(NULL);
[email protected]4801ecc2009-04-05 04:52:581669
[email protected]0cb94102009-05-22 19:51:211670 registrar_.Remove(this, NotificationType::TAB_CONTENTS_DISCONNECTED,
1671 Source<TabContents>(contents));
[email protected]36b6dcb2008-11-12 01:19:571672}
1673
[email protected]85ff2c42009-05-29 21:22:031674void Browser::TabDeselectedAt(TabContents* contents, int index) {
1675 // Save what the user's currently typing, so it can be restored when we
1676 // switch back to this tab.
1677 window_->GetLocationBar()->SaveStateToContents(contents);
1678}
1679
[email protected]36b6dcb2008-11-12 01:19:571680void Browser::TabSelectedAt(TabContents* old_contents,
1681 TabContents* new_contents,
1682 int index,
1683 bool user_gesture) {
1684 DCHECK(old_contents != new_contents);
1685
1686 // If we have any update pending, do it now.
1687 if (!chrome_updater_factory_.empty() && old_contents)
1688 ProcessPendingUIUpdates();
1689
[email protected]36b6dcb2008-11-12 01:19:571690 // Propagate the profile to the location bar.
1691 UpdateToolbar(true);
1692
[email protected]64ff7942008-12-17 18:11:231693 // Update stop/go state.
[email protected]c3989812009-04-15 18:08:491694 UpdateStopGoState(new_contents->is_loading(), true);
[email protected]36b6dcb2008-11-12 01:19:571695
[email protected]84214982008-12-10 18:49:101696 // Update commands to reflect current state.
1697 UpdateCommandsForTabState();
[email protected]36b6dcb2008-11-12 01:19:571698
1699 // Reset the status bubble.
[email protected]be3877f2009-01-14 15:51:101700 StatusBubble* status_bubble = GetStatusBubble();
1701 if (status_bubble) {
1702 status_bubble->Hide();
[email protected]36b6dcb2008-11-12 01:19:571703
[email protected]be3877f2009-01-14 15:51:101704 // Show the loading state (if any).
1705 status_bubble->SetStatus(GetSelectedTabContents()->GetStatusText());
1706 }
[email protected]36b6dcb2008-11-12 01:19:571707
[email protected]4801ecc2009-04-05 04:52:581708 if (find_bar_controller_.get()) {
[email protected]57c6a652009-05-04 07:58:341709 find_bar_controller_->ChangeTabContents(new_contents);
[email protected]4801ecc2009-04-05 04:52:581710 find_bar_controller_->find_bar()->MoveWindowIfNecessary(gfx::Rect(),
1711 true);
1712 }
1713
[email protected]36b6dcb2008-11-12 01:19:571714 // Update sessions. Don't force creation of sessions. If sessions doesn't
1715 // exist, the change will be picked up by sessions when created.
1716 if (profile_->HasSessionService()) {
1717 SessionService* session_service = profile_->GetSessionService();
1718 if (session_service && !tabstrip_model_.closing_all()) {
[email protected]2d46c842008-11-14 19:24:311719 session_service->SetSelectedTabInWindow(
1720 session_id(), tabstrip_model_.selected_index());
[email protected]36b6dcb2008-11-12 01:19:571721 }
1722 }
1723}
1724
1725void Browser::TabMoved(TabContents* contents,
1726 int from_index,
[email protected]c8db09162009-07-13 23:48:481727 int to_index,
1728 bool pinned_state_changed) {
[email protected]36b6dcb2008-11-12 01:19:571729 DCHECK(from_index >= 0 && to_index >= 0);
1730 // Notify the history service.
1731 SyncHistoryWithTabs(std::min(from_index, to_index));
1732}
1733
[email protected]5c0e6482009-07-14 20:20:091734void Browser::TabPinnedStateChanged(TabContents* contents, int index) {
1735 if (!profile()->HasSessionService())
1736 return;
1737 SessionService* session_service = profile()->GetSessionService();
1738 if (session_service) {
1739 session_service->SetPinnedState(
1740 session_id(),
1741 GetTabContentsAt(index)->controller().session_id(),
1742 tabstrip_model_.IsTabPinned(index));
1743 }
1744}
1745
[email protected]36b6dcb2008-11-12 01:19:571746void Browser::TabStripEmpty() {
1747 // Close the frame after we return to the message loop (not immediately,
1748 // otherwise it will destroy this object before the stack has a chance to
1749 // cleanly unwind.)
1750 // Note: This will be called several times if TabStripEmpty is called several
1751 // times. This is because it does not close the window if tabs are
1752 // still present.
1753 // NOTE: If you change to be immediate (no invokeLater) then you'll need to
1754 // update BrowserList::CloseAllBrowsers.
1755 MessageLoop::current()->PostTask(FROM_HERE,
1756 method_factory_.NewRunnableMethod(&Browser::CloseFrame));
1757}
1758
1759///////////////////////////////////////////////////////////////////////////////
[email protected]e0c7c262009-04-23 23:09:431760// Browser, PageNavigator implementation:
1761void Browser::OpenURL(const GURL& url, const GURL& referrer,
1762 WindowOpenDisposition disposition,
1763 PageTransition::Type transition) {
1764 OpenURLFromTab(NULL, url, referrer, disposition, transition);
1765}
1766
1767///////////////////////////////////////////////////////////////////////////////
[email protected]36b6dcb2008-11-12 01:19:571768// Browser, TabContentsDelegate implementation:
initial.commit09911bf2008-07-26 23:55:291769
1770void Browser::OpenURLFromTab(TabContents* source,
[email protected]1f7d7e92009-06-02 20:55:041771 const GURL& url,
1772 const GURL& referrer,
initial.commit09911bf2008-07-26 23:55:291773 WindowOpenDisposition disposition,
[email protected]e38f40152008-09-12 23:08:301774 PageTransition::Type transition) {
[email protected]1f7d7e92009-06-02 20:55:041775 OpenURLAtIndex(source, url, referrer, disposition, transition, -1, false);
initial.commit09911bf2008-07-26 23:55:291776}
1777
1778void Browser::NavigationStateChanged(const TabContents* source,
1779 unsigned changed_flags) {
initial.commit09911bf2008-07-26 23:55:291780 // Only update the UI when something visible has changed.
[email protected]e83f1682008-09-07 23:57:401781 if (changed_flags)
initial.commit09911bf2008-07-26 23:55:291782 ScheduleUIUpdate(source, changed_flags);
1783
[email protected]84214982008-12-10 18:49:101784 // We don't schedule updates to commands since they will only change once per
1785 // navigation, so we don't have to worry about flickering.
[email protected]e83f1682008-09-07 23:57:401786 if (changed_flags & TabContents::INVALIDATE_URL)
[email protected]84214982008-12-10 18:49:101787 UpdateCommandsForTabState();
initial.commit09911bf2008-07-26 23:55:291788}
1789
initial.commit09911bf2008-07-26 23:55:291790void Browser::AddNewContents(TabContents* source,
1791 TabContents* new_contents,
1792 WindowOpenDisposition disposition,
1793 const gfx::Rect& initial_pos,
1794 bool user_gesture) {
1795 DCHECK(disposition != SAVE_TO_DISK); // No code for this yet
[email protected]b680ad22009-04-15 23:19:421796 DCHECK(disposition != CURRENT_TAB); // Can't create a new contents for the
1797 // current tab.
initial.commit09911bf2008-07-26 23:55:291798
1799 // If this is an application we can only have one tab so we need to process
[email protected]ebdcf9742009-01-23 05:25:281800 // this in tabbed browser window.
1801 if (tabstrip_model_.count() > 0 &&
initial.commit09911bf2008-07-26 23:55:291802 disposition != NEW_WINDOW && disposition != NEW_POPUP &&
[email protected]299dabd2008-11-19 02:27:161803 type_ != TYPE_NORMAL) {
initial.commit09911bf2008-07-26 23:55:291804 Browser* b = GetOrCreateTabbedBrowser();
1805 DCHECK(b);
1806 PageTransition::Type transition = PageTransition::LINK;
1807 // If we were called from an "installed webapp" we want to emulate the code
1808 // that is run from browser_init.cc for links from external applications.
1809 // This means we need to open the tab with the START PAGE transition.
1810 // AddNewContents doesn't support this but the TabStripModel's
1811 // AddTabContents method does.
[email protected]d5fbc002009-02-27 22:12:581812 if (type_ & TYPE_APP)
initial.commit09911bf2008-07-26 23:55:291813 transition = PageTransition::START_PAGE;
[email protected]4d34e2e2009-05-26 22:55:281814 b->tabstrip_model()->AddTabContents(new_contents, -1, false, transition,
1815 true);
[email protected]ebdcf9742009-01-23 05:25:281816 b->window()->Show();
initial.commit09911bf2008-07-26 23:55:291817 return;
1818 }
1819
1820 if (disposition == NEW_POPUP) {
1821 BuildPopupWindow(source, new_contents, initial_pos);
1822 } else if (disposition == NEW_WINDOW) {
[email protected]15952e462008-11-14 00:29:051823 Browser* browser = Browser::Create(profile_);
1824 browser->AddNewContents(source, new_contents, NEW_FOREGROUND_TAB,
1825 initial_pos, user_gesture);
1826 browser->window()->Show();
initial.commit09911bf2008-07-26 23:55:291827 } else if (disposition != SUPPRESS_OPEN) {
[email protected]4d34e2e2009-05-26 22:55:281828 tabstrip_model_.AddTabContents(new_contents, -1, false,
1829 PageTransition::LINK,
initial.commit09911bf2008-07-26 23:55:291830 disposition == NEW_FOREGROUND_TAB);
1831 }
1832}
1833
initial.commit09911bf2008-07-26 23:55:291834void Browser::ActivateContents(TabContents* contents) {
1835 tabstrip_model_.SelectTabContentsAt(
1836 tabstrip_model_.GetIndexOfTabContents(contents), false);
[email protected]f3e99e32008-07-30 04:48:391837 window_->Activate();
initial.commit09911bf2008-07-26 23:55:291838}
1839
initial.commit09911bf2008-07-26 23:55:291840void Browser::LoadingStateChanged(TabContents* source) {
[email protected]afb73882008-11-14 22:40:441841 window_->UpdateLoadingAnimations(tabstrip_model_.TabsAreLoading());
[email protected]f3e99e32008-07-30 04:48:391842 window_->UpdateTitleBar();
initial.commit09911bf2008-07-26 23:55:291843
initial.commit09911bf2008-07-26 23:55:291844 if (source == GetSelectedTabContents()) {
[email protected]c3989812009-04-15 18:08:491845 UpdateStopGoState(source->is_loading(), false);
[email protected]be3877f2009-01-14 15:51:101846 if (GetStatusBubble())
1847 GetStatusBubble()->SetStatus(GetSelectedTabContents()->GetStatusText());
initial.commit09911bf2008-07-26 23:55:291848 }
1849}
1850
1851void Browser::CloseContents(TabContents* source) {
[email protected]04b4a6c2008-08-02 00:44:471852 if (is_attempting_to_close_browser_) {
1853 // If we're trying to close the browser, just clear the state related to
[email protected]adf650f2008-12-09 16:10:061854 // waiting for unload to fire. Don't actually try to close the tab as it
[email protected]04b4a6c2008-08-02 00:44:471855 // will go down the slow shutdown path instead of the fast path of killing
1856 // all the renderer processes.
[email protected]8a2ce5a2008-08-11 23:43:081857 ClearUnloadState(source);
[email protected]04b4a6c2008-08-02 00:44:471858 return;
1859 }
1860
initial.commit09911bf2008-07-26 23:55:291861 int index = tabstrip_model_.GetIndexOfTabContents(source);
1862 if (index == TabStripModel::kNoTab) {
1863 NOTREACHED() << "CloseContents called for tab not in our strip";
1864 return;
1865 }
1866 tabstrip_model_.CloseTabContentsAt(index);
1867}
1868
[email protected]15e8abe2008-08-20 22:40:401869void Browser::MoveContents(TabContents* source, const gfx::Rect& pos) {
[email protected]d5fbc002009-02-27 22:12:581870 if ((type() & TYPE_POPUP) == 0) {
initial.commit09911bf2008-07-26 23:55:291871 NOTREACHED() << "moving invalid browser type";
1872 return;
1873 }
[email protected]2d46c842008-11-14 19:24:311874 window_->SetBounds(pos);
initial.commit09911bf2008-07-26 23:55:291875}
1876
[email protected]b6c874582009-05-08 19:38:311877void Browser::DetachContents(TabContents* source) {
1878 int index = tabstrip_model_.GetIndexOfTabContents(source);
1879 if (index >= 0)
1880 tabstrip_model_.DetachTabContentsAt(index);
1881}
1882
initial.commit09911bf2008-07-26 23:55:291883bool Browser::IsPopup(TabContents* source) {
1884 // A non-tabbed BROWSER is an unconstrained popup.
[email protected]d5fbc002009-02-27 22:12:581885 return (type() & TYPE_POPUP);
initial.commit09911bf2008-07-26 23:55:291886}
1887
[email protected]36b6dcb2008-11-12 01:19:571888void Browser::ToolbarSizeChanged(TabContents* source, bool is_animating) {
1889 if (source == GetSelectedTabContents() || source == NULL) {
1890 // This will refresh the shelf if needed.
1891 window_->SelectedTabToolbarSizeChanged(is_animating);
1892 }
1893}
1894
1895void Browser::URLStarredChanged(TabContents* source, bool starred) {
1896 if (source == GetSelectedTabContents())
[email protected]b7ca4e62009-01-23 20:37:291897 window_->SetStarredState(starred);
[email protected]36b6dcb2008-11-12 01:19:571898}
1899
[email protected]b6406032009-03-19 15:10:151900void Browser::ContentsMouseEvent(TabContents* source, bool motion) {
[email protected]be3877f2009-01-14 15:51:101901 if (!GetStatusBubble())
1902 return;
1903
[email protected]36b6dcb2008-11-12 01:19:571904 if (source == GetSelectedTabContents()) {
[email protected]b6406032009-03-19 15:10:151905 if (motion) {
[email protected]36b6dcb2008-11-12 01:19:571906 GetStatusBubble()->MouseMoved();
[email protected]b6406032009-03-19 15:10:151907 } else {
[email protected]36b6dcb2008-11-12 01:19:571908 GetStatusBubble()->SetURL(GURL(), std::wstring());
1909 }
1910 }
1911}
1912
1913void Browser::UpdateTargetURL(TabContents* source, const GURL& url) {
[email protected]be3877f2009-01-14 15:51:101914 if (!GetStatusBubble())
1915 return;
1916
[email protected]36b6dcb2008-11-12 01:19:571917 if (source == GetSelectedTabContents()) {
1918 PrefService* prefs = profile_->GetPrefs();
1919 GetStatusBubble()->SetURL(url, prefs->GetString(prefs::kAcceptLanguages));
1920 }
1921}
1922
[email protected]3a6a3b62009-05-27 21:36:201923void Browser::UpdateDownloadShelfVisibility(bool visible) {
[email protected]9b032bf2009-07-21 17:34:231924 if (GetStatusBubble())
1925 GetStatusBubble()->UpdateDownloadShelfVisibility(visible);
[email protected]3a6a3b62009-05-27 21:36:201926}
1927
[email protected]36b6dcb2008-11-12 01:19:571928void Browser::ContentsZoomChange(bool zoom_in) {
[email protected]1fc025202009-01-20 23:03:141929 ExecuteCommand(zoom_in ? IDC_ZOOM_PLUS : IDC_ZOOM_MINUS);
[email protected]36b6dcb2008-11-12 01:19:571930}
1931
[email protected]7e383692009-06-12 19:14:541932void Browser::TabContentsFocused(TabContents* tab_content) {
1933 window_->TabContentsFocused(tab_content);
1934}
1935
[email protected]36b6dcb2008-11-12 01:19:571936bool Browser::IsApplication() const {
[email protected]d5fbc002009-02-27 22:12:581937 return (type_ & TYPE_APP) != 0;
[email protected]36b6dcb2008-11-12 01:19:571938}
1939
1940void Browser::ConvertContentsToApplication(TabContents* contents) {
[email protected]ce3fa3c2009-04-20 19:55:571941 const GURL& url = contents->controller().GetActiveEntry()->url();
[email protected]0303f31c2009-02-02 06:42:051942 std::wstring app_name = ComputeApplicationNameFromURL(url);
[email protected]36b6dcb2008-11-12 01:19:571943 RegisterAppPrefs(app_name);
1944
[email protected]b6c874582009-05-08 19:38:311945 DetachContents(contents);
[email protected]d5fbc002009-02-27 22:12:581946 Browser* browser = Browser::CreateForApp(app_name, profile_, false);
[email protected]15952e462008-11-14 00:29:051947 browser->tabstrip_model()->AppendTabContents(contents, true);
[email protected]840b1512009-07-21 16:53:461948 TabContents* tab_contents = browser->GetSelectedTabContents();
1949 tab_contents->GetMutableRendererPrefs()->can_accept_load_drops = false;
1950 tab_contents->render_view_host()->SyncRendererPrefs();
[email protected]15952e462008-11-14 00:29:051951 browser->window()->Show();
[email protected]36b6dcb2008-11-12 01:19:571952}
1953
[email protected]36b6dcb2008-11-12 01:19:571954bool Browser::ShouldDisplayURLField() {
1955 return !IsApplication();
1956}
1957
1958void Browser::BeforeUnloadFired(TabContents* tab,
1959 bool proceed,
1960 bool* proceed_to_fire_unload) {
1961 if (!is_attempting_to_close_browser_) {
1962 *proceed_to_fire_unload = proceed;
1963 return;
1964 }
1965
1966 if (!proceed) {
1967 CancelWindowClose();
1968 *proceed_to_fire_unload = false;
1969 return;
1970 }
1971
[email protected]06b42f032008-12-03 18:43:051972 if (RemoveFromSet(&tabs_needing_before_unload_fired_, tab)) {
[email protected]2d46c842008-11-14 19:24:311973 // Now that beforeunload has fired, put the tab on the queue to fire
1974 // unload.
[email protected]06b42f032008-12-03 18:43:051975 tabs_needing_unload_fired_.insert(tab);
[email protected]36b6dcb2008-11-12 01:19:571976 ProcessPendingTabs();
[email protected]adf650f2008-12-09 16:10:061977 // We want to handle firing the unload event ourselves since we want to
[email protected]36b6dcb2008-11-12 01:19:571978 // fire all the beforeunload events before attempting to fire the unload
1979 // events should the user cancel closing the browser.
1980 *proceed_to_fire_unload = false;
1981 return;
1982 }
1983
1984 *proceed_to_fire_unload = true;
1985}
1986
[email protected]f21c613a2009-02-12 14:46:171987gfx::Rect Browser::GetRootWindowResizerRect() const {
1988 return window_->GetRootWindowResizerRect();
1989}
1990
[email protected]4acc19a62009-04-03 03:05:111991void Browser::ShowHtmlDialog(HtmlDialogUIDelegate* delegate,
[email protected]322f3ff2009-05-22 16:19:541992 gfx::NativeWindow parent_window) {
[email protected]2d46c842008-11-14 19:24:311993 window_->ShowHTMLDialog(delegate, parent_window);
initial.commit09911bf2008-07-26 23:55:291994}
1995
[email protected]4bcefee2009-01-29 15:57:571996void Browser::SetFocusToLocationBar() {
[email protected]1a380622009-02-17 17:33:131997 // Two differences between this and FocusLocationBar():
1998 // (1) This doesn't get recorded in user metrics, since it's called
1999 // internally.
2000 // (2) This checks whether the location bar can be focused, and if not, clears
2001 // the focus. FocusLocationBar() is only reached when the location bar is
2002 // focusable, but this may be reached at other times, e.g. while in
2003 // fullscreen mode, where we need to leave focus in a consistent state.
2004 window_->SetFocusToLocationBar();
[email protected]4bcefee2009-01-29 15:57:572005}
2006
[email protected]7d5925a2009-03-03 02:59:122007void Browser::RenderWidgetShowing() {
2008 window_->DisableInactiveFrame();
2009}
[email protected]a239c3f2009-02-17 22:13:192010
[email protected]0a2aeb82009-05-15 21:52:482011int Browser::GetExtraRenderViewHeight() const {
2012 return window_->GetExtraRenderViewHeight();
2013}
2014
[email protected]d0cc9fb52009-06-23 02:26:162015void Browser::OnStartDownload(DownloadItem* download) {
2016 if (!window())
2017 return;
2018
2019 // GetDownloadShelf creates the download shelf if it was not yet created.
2020 window()->GetDownloadShelf()->AddDownload(new DownloadItemModel(download));
2021
2022// TODO(port): port for mac.
2023#if defined(OS_WIN) || defined(OS_LINUX)
2024 // Don't show the animation for "Save file" downloads.
2025 if (download->total_bytes() > 0) {
2026 TabContents* current_tab = GetSelectedTabContents();
2027 // We make this check for the case of minimized windows, unit tests, etc.
2028 if (platform_util::IsVisible(current_tab->GetNativeView()) &&
2029 Animation::ShouldRenderRichAnimation())
2030 DownloadStartedAnimation::Show(current_tab);
2031 }
2032#endif
2033}
2034
2035void Browser::ConfirmAddSearchProvider(const TemplateURL* template_url,
2036 Profile* profile) {
2037 window()->ConfirmAddSearchProvider(template_url, profile);
2038}
2039
[email protected]bb678332009-07-21 00:15:502040void Browser::ShowPageInfo(Profile* profile,
[email protected]4d677202009-07-19 07:37:122041 const GURL& url,
2042 const NavigationEntry::SSLStatus& ssl,
2043 bool show_history) {
[email protected]bb678332009-07-21 00:15:502044 window()->ShowPageInfo(profile, url, ssl, show_history);
[email protected]4d677202009-07-19 07:37:122045}
2046
[email protected]36b6dcb2008-11-12 01:19:572047///////////////////////////////////////////////////////////////////////////////
2048// Browser, SelectFileDialog::Listener implementation:
2049
[email protected]561abe62009-04-06 18:08:342050void Browser::FileSelected(const FilePath& path, int index, void* params) {
[email protected]72cbd322009-04-07 10:17:122051 GURL file_url = net::FilePathToFileURL(path);
[email protected]36b6dcb2008-11-12 01:19:572052 if (!file_url.is_empty())
2053 OpenURL(file_url, GURL(), CURRENT_TAB, PageTransition::TYPED);
2054}
2055
[email protected]a239c3f2009-02-17 22:13:192056
[email protected]36b6dcb2008-11-12 01:19:572057///////////////////////////////////////////////////////////////////////////////
2058// Browser, NotificationObserver implementation:
2059
initial.commit09911bf2008-07-26 23:55:292060void Browser::Observe(NotificationType type,
2061 const NotificationSource& source,
2062 const NotificationDetails& details) {
[email protected]bfd04a62009-02-01 18:16:562063 switch (type.value) {
[email protected]57c6a652009-05-04 07:58:342064 case NotificationType::TAB_CONTENTS_DISCONNECTED:
[email protected]e83f1682008-09-07 23:57:402065 if (is_attempting_to_close_browser_) {
2066 // Need to do this asynchronously as it will close the tab, which is
2067 // currently on the call stack above us.
2068 MessageLoop::current()->PostTask(FROM_HERE,
2069 method_factory_.NewRunnableMethod(&Browser::ClearUnloadState,
2070 Source<TabContents>(source).ptr()));
2071 }
2072 break;
2073
[email protected]b4a19ea2009-03-17 10:08:242074 case NotificationType::SSL_VISIBLE_STATE_CHANGED:
[email protected]e83f1682008-09-07 23:57:402075 // When the current tab's SSL state changes, we need to update the URL
[email protected]90e8d062008-09-08 02:26:322076 // bar to reflect the new state. Note that it's possible for the selected
2077 // tab contents to be NULL. This is because we listen for all sources
2078 // (NavigationControllers) for convenience, so the notification could
2079 // actually be for a different window while we're doing asynchronous
2080 // closing of this one.
2081 if (GetSelectedTabContents() &&
[email protected]ce3fa3c2009-04-20 19:55:572082 &GetSelectedTabContents()->controller() ==
[email protected]e83f1682008-09-07 23:57:402083 Source<NavigationController>(source).ptr())
[email protected]36b6dcb2008-11-12 01:19:572084 UpdateToolbar(false);
[email protected]e83f1682008-09-07 23:57:402085 break;
2086
[email protected]894bb502009-05-21 22:39:572087 case NotificationType::EXTENSION_UNLOADED: {
2088 // Close any tabs from the unloaded extension.
2089 Extension* extension = Details<Extension>(details).ptr();
2090 for (int i = 0; i < tabstrip_model_.count(); i++) {
2091 TabContents* tc = tabstrip_model_.GetTabContentsAt(i);
2092 if (tc->GetURL().SchemeIs(chrome::kExtensionScheme) &&
2093 tc->GetURL().host() == extension->id()) {
2094 CloseTabContents(tc);
2095 return;
2096 }
2097 }
2098 break;
2099 }
2100
[email protected]e001d412009-06-26 20:53:252101 case NotificationType::BROWSER_THEME_CHANGED:
2102 window()->UserChangedTheme();
2103 break;
2104
[email protected]e83f1682008-09-07 23:57:402105 default:
2106 NOTREACHED() << "Got a notification we didn't register for.";
initial.commit09911bf2008-07-26 23:55:292107 }
2108}
2109
[email protected]88d74942009-01-21 22:04:442110
[email protected]36b6dcb2008-11-12 01:19:572111///////////////////////////////////////////////////////////////////////////////
2112// Browser, Command and state updating (private):
2113
2114void Browser::InitCommandState() {
2115 // All browser commands whose state isn't set automagically some other way
2116 // (like Back & Forward with initial page load) must have their state
2117 // initialized here, otherwise they will be forever disabled.
2118
[email protected]84214982008-12-10 18:49:102119 // Navigation commands
[email protected]1fc025202009-01-20 23:03:142120 command_updater_.UpdateCommandEnabled(IDC_RELOAD, true);
[email protected]84214982008-12-10 18:49:102121
2122 // Window management commands
[email protected]1fc025202009-01-20 23:03:142123 command_updater_.UpdateCommandEnabled(IDC_NEW_WINDOW, true);
2124 command_updater_.UpdateCommandEnabled(IDC_NEW_INCOGNITO_WINDOW, true);
[email protected]84214982008-12-10 18:49:102125 // TODO(pkasting): Perhaps the code that populates this submenu should do
2126 // this?
[email protected]1fc025202009-01-20 23:03:142127 command_updater_.UpdateCommandEnabled(IDC_NEW_WINDOW_PROFILE_0, true);
2128 command_updater_.UpdateCommandEnabled(IDC_NEW_WINDOW_PROFILE_1, true);
2129 command_updater_.UpdateCommandEnabled(IDC_NEW_WINDOW_PROFILE_2, true);
2130 command_updater_.UpdateCommandEnabled(IDC_NEW_WINDOW_PROFILE_3, true);
2131 command_updater_.UpdateCommandEnabled(IDC_NEW_WINDOW_PROFILE_4, true);
2132 command_updater_.UpdateCommandEnabled(IDC_NEW_WINDOW_PROFILE_5, true);
2133 command_updater_.UpdateCommandEnabled(IDC_NEW_WINDOW_PROFILE_6, true);
2134 command_updater_.UpdateCommandEnabled(IDC_NEW_WINDOW_PROFILE_7, true);
2135 command_updater_.UpdateCommandEnabled(IDC_NEW_WINDOW_PROFILE_8, true);
2136 command_updater_.UpdateCommandEnabled(IDC_CLOSE_WINDOW, true);
2137 command_updater_.UpdateCommandEnabled(IDC_NEW_TAB, true);
2138 command_updater_.UpdateCommandEnabled(IDC_CLOSE_TAB, true);
2139 command_updater_.UpdateCommandEnabled(IDC_DUPLICATE_TAB, true);
[email protected]9282cea2009-02-18 18:49:002140 command_updater_.UpdateCommandEnabled(IDC_FULLSCREEN, true);
[email protected]1fc025202009-01-20 23:03:142141 command_updater_.UpdateCommandEnabled(IDC_EXIT, true);
[email protected]84214982008-12-10 18:49:102142
2143 // Page-related commands
[email protected]1fc025202009-01-20 23:03:142144 command_updater_.UpdateCommandEnabled(IDC_CLOSE_POPUPS, true);
[email protected]e662ade2009-06-08 18:20:142145 command_updater_.UpdateCommandEnabled(IDC_PRINT, true);
[email protected]1fc025202009-01-20 23:03:142146 command_updater_.UpdateCommandEnabled(IDC_ENCODING_AUTO_DETECT, true);
2147 command_updater_.UpdateCommandEnabled(IDC_ENCODING_UTF8, true);
2148 command_updater_.UpdateCommandEnabled(IDC_ENCODING_UTF16LE, true);
2149 command_updater_.UpdateCommandEnabled(IDC_ENCODING_ISO88591, true);
2150 command_updater_.UpdateCommandEnabled(IDC_ENCODING_WINDOWS1252, true);
2151 command_updater_.UpdateCommandEnabled(IDC_ENCODING_GBK, true);
2152 command_updater_.UpdateCommandEnabled(IDC_ENCODING_GB18030, true);
2153 command_updater_.UpdateCommandEnabled(IDC_ENCODING_BIG5HKSCS, true);
2154 command_updater_.UpdateCommandEnabled(IDC_ENCODING_BIG5, true);
2155 command_updater_.UpdateCommandEnabled(IDC_ENCODING_THAI, true);
2156 command_updater_.UpdateCommandEnabled(IDC_ENCODING_KOREAN, true);
2157 command_updater_.UpdateCommandEnabled(IDC_ENCODING_SHIFTJIS, true);
2158 command_updater_.UpdateCommandEnabled(IDC_ENCODING_ISO2022JP, true);
2159 command_updater_.UpdateCommandEnabled(IDC_ENCODING_EUCJP, true);
2160 command_updater_.UpdateCommandEnabled(IDC_ENCODING_ISO885915, true);
2161 command_updater_.UpdateCommandEnabled(IDC_ENCODING_MACINTOSH, true);
2162 command_updater_.UpdateCommandEnabled(IDC_ENCODING_ISO88592, true);
2163 command_updater_.UpdateCommandEnabled(IDC_ENCODING_WINDOWS1250, true);
2164 command_updater_.UpdateCommandEnabled(IDC_ENCODING_ISO88595, true);
2165 command_updater_.UpdateCommandEnabled(IDC_ENCODING_WINDOWS1251, true);
2166 command_updater_.UpdateCommandEnabled(IDC_ENCODING_KOI8R, true);
2167 command_updater_.UpdateCommandEnabled(IDC_ENCODING_KOI8U, true);
2168 command_updater_.UpdateCommandEnabled(IDC_ENCODING_ISO88597, true);
2169 command_updater_.UpdateCommandEnabled(IDC_ENCODING_WINDOWS1253, true);
2170 command_updater_.UpdateCommandEnabled(IDC_ENCODING_ISO88594, true);
2171 command_updater_.UpdateCommandEnabled(IDC_ENCODING_ISO885913, true);
2172 command_updater_.UpdateCommandEnabled(IDC_ENCODING_WINDOWS1257, true);
2173 command_updater_.UpdateCommandEnabled(IDC_ENCODING_ISO88593, true);
2174 command_updater_.UpdateCommandEnabled(IDC_ENCODING_ISO885910, true);
2175 command_updater_.UpdateCommandEnabled(IDC_ENCODING_ISO885914, true);
2176 command_updater_.UpdateCommandEnabled(IDC_ENCODING_ISO885916, true);
2177 command_updater_.UpdateCommandEnabled(IDC_ENCODING_WINDOWS1254, true);
2178 command_updater_.UpdateCommandEnabled(IDC_ENCODING_ISO88596, true);
2179 command_updater_.UpdateCommandEnabled(IDC_ENCODING_WINDOWS1256, true);
2180 command_updater_.UpdateCommandEnabled(IDC_ENCODING_ISO88598, true);
[email protected]e13271f2009-03-07 00:26:002181 command_updater_.UpdateCommandEnabled(IDC_ENCODING_ISO88598I, true);
[email protected]1fc025202009-01-20 23:03:142182 command_updater_.UpdateCommandEnabled(IDC_ENCODING_WINDOWS1255, true);
2183 command_updater_.UpdateCommandEnabled(IDC_ENCODING_WINDOWS1258, true);
[email protected]84214982008-12-10 18:49:102184
2185 // Clipboard commands
[email protected]1fc025202009-01-20 23:03:142186 command_updater_.UpdateCommandEnabled(IDC_CUT, true);
2187 command_updater_.UpdateCommandEnabled(IDC_COPY, true);
[email protected]1fc025202009-01-20 23:03:142188 command_updater_.UpdateCommandEnabled(IDC_PASTE, true);
[email protected]84214982008-12-10 18:49:102189
[email protected]63b02932009-06-05 09:40:512190 // Find-in-page
2191 command_updater_.UpdateCommandEnabled(IDC_FIND, true);
2192 command_updater_.UpdateCommandEnabled(IDC_FIND_NEXT, true);
2193 command_updater_.UpdateCommandEnabled(IDC_FIND_PREVIOUS, true);
2194
2195 // Zoom
2196 command_updater_.UpdateCommandEnabled(IDC_ZOOM_MENU, true);
2197 command_updater_.UpdateCommandEnabled(IDC_ZOOM_PLUS, true);
2198 command_updater_.UpdateCommandEnabled(IDC_ZOOM_NORMAL, true);
2199 command_updater_.UpdateCommandEnabled(IDC_ZOOM_MINUS, true);
2200
[email protected]84214982008-12-10 18:49:102201 // Show various bits of UI
[email protected]1fc025202009-01-20 23:03:142202 command_updater_.UpdateCommandEnabled(IDC_OPEN_FILE, true);
2203 command_updater_.UpdateCommandEnabled(IDC_CREATE_SHORTCUTS, false);
[email protected]c630f162009-07-22 09:41:332204 command_updater_.UpdateCommandEnabled(IDC_DEV_TOOLS, true);
[email protected]1fc025202009-01-20 23:03:142205 command_updater_.UpdateCommandEnabled(IDC_TASK_MANAGER, true);
2206 command_updater_.UpdateCommandEnabled(IDC_SELECT_PROFILE, true);
2207 command_updater_.UpdateCommandEnabled(IDC_SHOW_HISTORY, true);
2208 command_updater_.UpdateCommandEnabled(IDC_SHOW_BOOKMARK_MANAGER, true);
2209 command_updater_.UpdateCommandEnabled(IDC_SHOW_DOWNLOADS, true);
2210 command_updater_.UpdateCommandEnabled(IDC_HELP_PAGE, true);
[email protected]16779842009-07-08 23:45:292211#if defined(OS_CHROMEOS)
[email protected]be715072009-07-07 15:43:202212 command_updater_.UpdateCommandEnabled(IDC_CONTROL_PANEL, true);
2213#endif
[email protected]64ff7942008-12-17 18:11:232214
2215 // Initialize other commands based on the window type.
2216 {
2217 bool normal_window = type() == TYPE_NORMAL;
2218
2219 // Navigation commands
[email protected]1fc025202009-01-20 23:03:142220 command_updater_.UpdateCommandEnabled(IDC_HOME, normal_window);
[email protected]64ff7942008-12-17 18:11:232221
2222 // Window management commands
[email protected]1fc025202009-01-20 23:03:142223 command_updater_.UpdateCommandEnabled(IDC_SELECT_NEXT_TAB, normal_window);
2224 command_updater_.UpdateCommandEnabled(IDC_SELECT_PREVIOUS_TAB,
2225 normal_window);
2226 command_updater_.UpdateCommandEnabled(IDC_SELECT_TAB_0, normal_window);
2227 command_updater_.UpdateCommandEnabled(IDC_SELECT_TAB_1, normal_window);
2228 command_updater_.UpdateCommandEnabled(IDC_SELECT_TAB_2, normal_window);
2229 command_updater_.UpdateCommandEnabled(IDC_SELECT_TAB_3, normal_window);
2230 command_updater_.UpdateCommandEnabled(IDC_SELECT_TAB_4, normal_window);
2231 command_updater_.UpdateCommandEnabled(IDC_SELECT_TAB_5, normal_window);
2232 command_updater_.UpdateCommandEnabled(IDC_SELECT_TAB_6, normal_window);
2233 command_updater_.UpdateCommandEnabled(IDC_SELECT_TAB_7, normal_window);
2234 command_updater_.UpdateCommandEnabled(IDC_SELECT_LAST_TAB, normal_window);
2235 command_updater_.UpdateCommandEnabled(IDC_RESTORE_TAB,
[email protected]64ff7942008-12-17 18:11:232236 normal_window && !profile_->IsOffTheRecord());
[email protected]e662ade2009-06-08 18:20:142237
2238 // Page-related commands
[email protected]63b02932009-06-05 09:40:512239 command_updater_.UpdateCommandEnabled(IDC_STAR, normal_window);
[email protected]e662ade2009-06-08 18:20:142240
2241 // Clipboard commands
[email protected]63b02932009-06-05 09:40:512242 command_updater_.UpdateCommandEnabled(IDC_COPY_URL, normal_window);
[email protected]d5c99b172009-02-25 17:09:212243
2244 // Show various bits of UI
[email protected]7fd4cc32009-04-15 23:17:372245 command_updater_.UpdateCommandEnabled(IDC_CLEAR_BROWSING_DATA,
2246 normal_window);
[email protected]64ff7942008-12-17 18:11:232247 }
[email protected]9282cea2009-02-18 18:49:002248
2249 // Initialize other commands whose state changes based on fullscreen mode.
2250 UpdateCommandsForFullscreenMode(false);
[email protected]36b6dcb2008-11-12 01:19:572251}
2252
[email protected]84214982008-12-10 18:49:102253void Browser::UpdateCommandsForTabState() {
[email protected]c7c42332008-11-15 01:10:542254 TabContents* current_tab = GetSelectedTabContents();
[email protected]64ff7942008-12-17 18:11:232255 if (!current_tab) // May be NULL during tab restore.
[email protected]d8375fd2008-11-25 22:45:392256 return;
[email protected]d8375fd2008-11-25 22:45:392257
[email protected]84214982008-12-10 18:49:102258 // Navigation commands
[email protected]ce3fa3c2009-04-20 19:55:572259 NavigationController& nc = current_tab->controller();
2260 command_updater_.UpdateCommandEnabled(IDC_BACK, nc.CanGoBack());
2261 command_updater_.UpdateCommandEnabled(IDC_FORWARD, nc.CanGoForward());
initial.commit09911bf2008-07-26 23:55:292262
[email protected]84214982008-12-10 18:49:102263 // Window management commands
[email protected]1fc025202009-01-20 23:03:142264 command_updater_.UpdateCommandEnabled(IDC_DUPLICATE_TAB,
[email protected]63b02932009-06-05 09:40:512265 !(type() & TYPE_APP) && CanDuplicateContentsAt(selected_index()));
[email protected]84214982008-12-10 18:49:102266
[email protected]57c6a652009-05-04 07:58:342267 // Current navigation entry, may be NULL.
2268 NavigationEntry* active_entry = current_tab->controller().GetActiveEntry();
[email protected]2bfd94d2009-04-29 20:32:032269 bool is_source_viewable =
[email protected]2bfd94d2009-04-29 20:32:032270 net::IsSupportedNonImageMimeType(
[email protected]57c6a652009-05-04 07:58:342271 current_tab->contents_mime_type().c_str());
[email protected]84214982008-12-10 18:49:102272
[email protected]57c6a652009-05-04 07:58:342273 // Page-related commands
[email protected]57c6a652009-05-04 07:58:342274 window_->SetStarredState(current_tab->is_starred());
2275 // View-source should not be enabled if already in view-source mode or
2276 // the source is not viewable.
2277 command_updater_.UpdateCommandEnabled(IDC_VIEW_SOURCE,
2278 active_entry && !active_entry->IsViewSourceMode() &&
2279 is_source_viewable);
[email protected]57c6a652009-05-04 07:58:342280 command_updater_.UpdateCommandEnabled(IDC_SAVE_PAGE,
2281 SavePackage::IsSavableURL(current_tab->GetURL()));
2282 command_updater_.UpdateCommandEnabled(IDC_ENCODING_MENU,
2283 SavePackage::IsSavableContents(current_tab->contents_mime_type()) &&
2284 SavePackage::IsSavableURL(current_tab->GetURL()));
[email protected]6de74452009-02-25 18:04:592285
[email protected]57c6a652009-05-04 07:58:342286 // Show various bits of UI
[email protected]57c6a652009-05-04 07:58:342287 command_updater_.UpdateCommandEnabled(IDC_CREATE_SHORTCUTS,
2288 !current_tab->GetFavIcon().isNull());
initial.commit09911bf2008-07-26 23:55:292289}
2290
[email protected]c3989812009-04-15 18:08:492291void Browser::UpdateStopGoState(bool is_loading, bool force) {
2292 window_->UpdateStopGoState(is_loading, force);
[email protected]1fc025202009-01-20 23:03:142293 command_updater_.UpdateCommandEnabled(IDC_GO, !is_loading);
2294 command_updater_.UpdateCommandEnabled(IDC_STOP, is_loading);
[email protected]64ff7942008-12-17 18:11:232295}
2296
[email protected]d938aed92009-01-22 19:49:332297
[email protected]36b6dcb2008-11-12 01:19:572298///////////////////////////////////////////////////////////////////////////////
2299// Browser, UI update coalescing and handling (private):
2300
2301void Browser::UpdateToolbar(bool should_restore_state) {
2302 window_->UpdateToolbar(GetSelectedTabContents(), should_restore_state);
initial.commit09911bf2008-07-26 23:55:292303}
2304
[email protected]36b6dcb2008-11-12 01:19:572305void Browser::ScheduleUIUpdate(const TabContents* source,
2306 unsigned changed_flags) {
[email protected]2b4355c2009-04-04 17:55:462307 // Do some synchronous updates.
[email protected]36b6dcb2008-11-12 01:19:572308 if (changed_flags & TabContents::INVALIDATE_URL &&
2309 source == GetSelectedTabContents()) {
2310 // Only update the URL for the current tab. Note that we do not update
2311 // the navigation commands since those would have already been updated
2312 // synchronously by NavigationStateChanged.
2313 UpdateToolbar(false);
[email protected]36b6dcb2008-11-12 01:19:572314 }
[email protected]2b4355c2009-04-04 17:55:462315 if (changed_flags & TabContents::INVALIDATE_LOAD && source) {
2316 // Update the loading state synchronously. This is so the throbber will
2317 // immediately start/stop, which gives a more snappy feel. We want to do
2318 // this for any tab so they start & stop quickly, but the source can be
2319 // NULL, so we have to check for that.
2320 tabstrip_model_.UpdateTabContentsStateAt(
[email protected]902cdf772009-05-06 15:08:122321 tabstrip_model_.GetIndexOfController(&source->controller()), true);
[email protected]2b4355c2009-04-04 17:55:462322 }
2323
2324 // If the only updates were synchronously handled above, we're done.
2325 if (changed_flags ==
2326 (TabContents::INVALIDATE_URL | TabContents::INVALIDATE_LOAD))
2327 return;
[email protected]36b6dcb2008-11-12 01:19:572328
2329 // Save the dirty bits.
2330 scheduled_updates_.push_back(UIUpdate(source, changed_flags));
2331
2332 if (chrome_updater_factory_.empty()) {
2333 // No task currently scheduled, start another.
2334 MessageLoop::current()->PostDelayedTask(FROM_HERE,
2335 chrome_updater_factory_.NewRunnableMethod(
2336 &Browser::ProcessPendingUIUpdates),
2337 kUIUpdateCoalescingTimeMS);
2338 }
2339}
2340
2341void Browser::ProcessPendingUIUpdates() {
2342#ifndef NDEBUG
2343 // Validate that all tabs we have pending updates for exist. This is scary
2344 // because the pending list must be kept in sync with any detached or
2345 // deleted tabs. This code does not dereference any TabContents pointers.
2346 for (size_t i = 0; i < scheduled_updates_.size(); i++) {
2347 bool found = false;
2348 for (int tab = 0; tab < tab_count(); tab++) {
[email protected]ce3fa3c2009-04-20 19:55:572349 if (&GetTabContentsAt(tab)->controller() ==
2350 &scheduled_updates_[i].source->controller()) {
[email protected]36b6dcb2008-11-12 01:19:572351 found = true;
2352 break;
2353 }
2354 }
2355 DCHECK(found);
2356 }
2357#endif
2358
2359 chrome_updater_factory_.RevokeAll();
2360
[email protected]2d46c842008-11-14 19:24:312361 // We could have many updates for the same thing in the queue. This map
2362 // tracks the bits of the stuff we've already updated for each TabContents so
2363 // we don't update again.
[email protected]36b6dcb2008-11-12 01:19:572364 typedef std::map<const TabContents*, unsigned> UpdateTracker;
2365 UpdateTracker updated_stuff;
2366
2367 for (size_t i = 0; i < scheduled_updates_.size(); i++) {
2368 // Do not dereference |contents|, it may be out-of-date!
2369 const TabContents* contents = scheduled_updates_[i].source;
2370 unsigned flags = scheduled_updates_[i].changed_flags;
2371
2372 // Remove any bits we have already updated, and save the new bits.
2373 UpdateTracker::iterator updated = updated_stuff.find(contents);
2374 if (updated != updated_stuff.end()) {
2375 // Turn off bits already set.
2376 flags &= ~updated->second;
2377 if (!flags)
2378 continue;
2379
2380 updated->second |= flags;
2381 } else {
2382 updated_stuff[contents] = flags;
2383 }
2384
[email protected]f7f3a5f2009-05-01 22:02:342385 if (flags & TabContents::INVALIDATE_PAGE_ACTIONS)
2386 window()->GetLocationBar()->UpdatePageActions();
2387
[email protected]36b6dcb2008-11-12 01:19:572388 // Updating the URL happens synchronously in ScheduleUIUpdate.
[email protected]ba8c48212009-05-12 21:20:402389 TabContents* selected_tab = GetSelectedTabContents();
[email protected]4d34e2e2009-05-26 22:55:282390 if (selected_tab &&
2391 flags & TabContents::INVALIDATE_LOAD && GetStatusBubble()) {
[email protected]ba8c48212009-05-12 21:20:402392 GetStatusBubble()->SetStatus(selected_tab->GetStatusText());
[email protected]4d34e2e2009-05-26 22:55:282393 }
[email protected]36b6dcb2008-11-12 01:19:572394
[email protected]c9cd2222009-05-06 05:16:502395 if (flags & TabContents::INVALIDATE_TAB) {
[email protected]36b6dcb2008-11-12 01:19:572396 tabstrip_model_.UpdateTabContentsStateAt(
[email protected]902cdf772009-05-06 15:08:122397 tabstrip_model_.GetIndexOfController(&contents->controller()), false);
[email protected]36b6dcb2008-11-12 01:19:572398 window_->UpdateTitleBar();
2399
[email protected]ba8c48212009-05-12 21:20:402400 if (selected_tab && contents == selected_tab) {
[email protected]1fc025202009-01-20 23:03:142401 command_updater_.UpdateCommandEnabled(IDC_CREATE_SHORTCUTS,
[email protected]ba8c48212009-05-12 21:20:402402 !selected_tab->GetFavIcon().isNull());
[email protected]36b6dcb2008-11-12 01:19:572403 }
2404 }
2405
2406 // We don't need to process INVALIDATE_STATE, since that's not visible.
2407 }
2408
2409 scheduled_updates_.clear();
2410}
2411
2412void Browser::RemoveScheduledUpdatesFor(TabContents* contents) {
2413 if (!contents)
2414 return;
2415
2416 // Remove any pending UI updates for the detached tab.
2417 UpdateVector::iterator cur_update = scheduled_updates_.begin();
2418 while (cur_update != scheduled_updates_.end()) {
2419 if (cur_update->source == contents) {
2420 cur_update = scheduled_updates_.erase(cur_update);
2421 } else {
2422 ++cur_update;
initial.commit09911bf2008-07-26 23:55:292423 }
2424 }
2425}
2426
[email protected]d938aed92009-01-22 19:49:332427
[email protected]36b6dcb2008-11-12 01:19:572428///////////////////////////////////////////////////////////////////////////////
2429// Browser, Getters for UI (private):
initial.commit09911bf2008-07-26 23:55:292430
[email protected]36b6dcb2008-11-12 01:19:572431StatusBubble* Browser::GetStatusBubble() {
[email protected]9b032bf2009-07-21 17:34:232432 return window_ ? window_->GetStatusBubble() : NULL;
initial.commit09911bf2008-07-26 23:55:292433}
2434
[email protected]36b6dcb2008-11-12 01:19:572435///////////////////////////////////////////////////////////////////////////////
2436// Browser, Session restore functions (private):
initial.commit09911bf2008-07-26 23:55:292437
2438void Browser::SyncHistoryWithTabs(int index) {
2439 if (!profile()->HasSessionService())
2440 return;
2441 SessionService* session_service = profile()->GetSessionService();
2442 if (session_service) {
2443 for (int i = index; i < tab_count(); ++i) {
2444 TabContents* contents = GetTabContentsAt(i);
2445 if (contents) {
2446 session_service->SetTabIndexInWindow(
[email protected]ce3fa3c2009-04-20 19:55:572447 session_id(), contents->controller().session_id(), i);
[email protected]5c0e6482009-07-14 20:20:092448 session_service->SetPinnedState(session_id(),
2449 contents->controller().session_id(),
2450 tabstrip_model_.IsTabPinned(i));
initial.commit09911bf2008-07-26 23:55:292451 }
2452 }
2453 }
2454}
2455
[email protected]ce3fa3c2009-04-20 19:55:572456TabContents* Browser::BuildRestoredTab(
[email protected]36b6dcb2008-11-12 01:19:572457 const std::vector<TabNavigation>& navigations,
2458 int selected_navigation) {
2459 if (!navigations.empty()) {
2460 DCHECK(selected_navigation >= 0 &&
2461 selected_navigation < static_cast<int>(navigations.size()));
[email protected]36b6dcb2008-11-12 01:19:572462 // Create a NavigationController. This constructor creates the appropriate
2463 // set of TabContents.
[email protected]57c6a652009-05-04 07:58:342464 TabContents* new_tab = new TabContents(profile_, NULL,
[email protected]ce3fa3c2009-04-20 19:55:572465 MSG_ROUTING_NONE, NULL);
2466 new_tab->controller().RestoreFromState(navigations, selected_navigation);
2467 return new_tab;
[email protected]36b6dcb2008-11-12 01:19:572468 } else {
2469 // No navigations. Create a tab with about:blank.
[email protected]ce3fa3c2009-04-20 19:55:572470 return CreateTabContentsForURL(GURL("about:blank"), GURL(), profile_,
2471 PageTransition::START_PAGE, false, NULL);
initial.commit09911bf2008-07-26 23:55:292472 }
2473}
2474
[email protected]36b6dcb2008-11-12 01:19:572475///////////////////////////////////////////////////////////////////////////////
2476// Browser, OnBeforeUnload handling (private):
initial.commit09911bf2008-07-26 23:55:292477
[email protected]04b4a6c2008-08-02 00:44:472478void Browser::ProcessPendingTabs() {
2479 DCHECK(is_attempting_to_close_browser_);
initial.commit09911bf2008-07-26 23:55:292480
[email protected]04b4a6c2008-08-02 00:44:472481 if (HasCompletedUnloadProcessing()) {
2482 // We've finished all the unload events and can proceed to close the
2483 // browser.
2484 OnWindowClosing();
initial.commit09911bf2008-07-26 23:55:292485 return;
2486 }
2487
[email protected]04b4a6c2008-08-02 00:44:472488 // Process beforeunload tabs first. When that queue is empty, process
2489 // unload tabs.
[email protected]04b4a6c2008-08-02 00:44:472490 if (!tabs_needing_before_unload_fired_.empty()) {
[email protected]06b42f032008-12-03 18:43:052491 TabContents* tab = *(tabs_needing_before_unload_fired_.begin());
[email protected]22484622009-06-10 21:17:242492 // Null check render_view_host here as this gets called on a PostTask and
2493 // the tab's render_view_host may have been nulled out.
2494 if (tab->render_view_host()) {
[email protected]ae23c272009-07-27 20:15:402495 tab->render_view_host()->FirePageBeforeUnload(false);
[email protected]22484622009-06-10 21:17:242496 } else {
2497 ClearUnloadState(tab);
2498 }
[email protected]04b4a6c2008-08-02 00:44:472499 } else if (!tabs_needing_unload_fired_.empty()) {
initial.commit09911bf2008-07-26 23:55:292500 // We've finished firing all beforeunload events and can proceed with unload
2501 // events.
2502 // TODO(ojan): We should add a call to browser_shutdown::OnShutdownStarting
2503 // somewhere around here so that we have accurate measurements of shutdown
2504 // time.
[email protected]04b4a6c2008-08-02 00:44:472505 // TODO(ojan): We can probably fire all the unload events in parallel and
2506 // get a perf benefit from that in the cases where the tab hangs in it's
2507 // unload handler or takes a long time to page in.
[email protected]06b42f032008-12-03 18:43:052508 TabContents* tab = *(tabs_needing_unload_fired_.begin());
[email protected]22484622009-06-10 21:17:242509 // Null check render_view_host here as this gets called on a PostTask and
2510 // the tab's render_view_host may have been nulled out.
2511 if (tab->render_view_host()) {
[email protected]eb6b87a2009-07-24 15:57:392512 tab->render_view_host()->ClosePage(false, -1, -1);
[email protected]22484622009-06-10 21:17:242513 } else {
2514 ClearUnloadState(tab);
2515 }
initial.commit09911bf2008-07-26 23:55:292516 } else {
[email protected]04b4a6c2008-08-02 00:44:472517 NOTREACHED();
initial.commit09911bf2008-07-26 23:55:292518 }
2519}
2520
[email protected]d043c2cc2009-03-25 18:30:452521bool Browser::HasCompletedUnloadProcessing() const {
[email protected]04b4a6c2008-08-02 00:44:472522 return is_attempting_to_close_browser_ &&
2523 tabs_needing_before_unload_fired_.empty() &&
2524 tabs_needing_unload_fired_.empty();
2525}
2526
2527void Browser::CancelWindowClose() {
2528 DCHECK(is_attempting_to_close_browser_);
2529 // Only cancelling beforeunload should be able to cancel the window's close.
2530 // So there had better be a tab that we think needs beforeunload fired.
2531 DCHECK(!tabs_needing_before_unload_fired_.empty());
2532
[email protected]8f673f3a2008-08-05 22:34:282533 tabs_needing_before_unload_fired_.clear();
2534 tabs_needing_unload_fired_.clear();
[email protected]04b4a6c2008-08-02 00:44:472535 is_attempting_to_close_browser_ = false;
2536}
2537
[email protected]06b42f032008-12-03 18:43:052538bool Browser::RemoveFromSet(UnloadListenerSet* set, TabContents* tab) {
[email protected]04b4a6c2008-08-02 00:44:472539 DCHECK(is_attempting_to_close_browser_);
2540
[email protected]06b42f032008-12-03 18:43:052541 UnloadListenerSet::iterator iter = std::find(set->begin(), set->end(), tab);
2542 if (iter != set->end()) {
2543 set->erase(iter);
2544 return true;
[email protected]04b4a6c2008-08-02 00:44:472545 }
2546 return false;
2547}
initial.commit09911bf2008-07-26 23:55:292548
[email protected]36b6dcb2008-11-12 01:19:572549void Browser::ClearUnloadState(TabContents* tab) {
2550 DCHECK(is_attempting_to_close_browser_);
[email protected]06b42f032008-12-03 18:43:052551 RemoveFromSet(&tabs_needing_before_unload_fired_, tab);
2552 RemoveFromSet(&tabs_needing_unload_fired_, tab);
[email protected]36b6dcb2008-11-12 01:19:572553 ProcessPendingTabs();
initial.commit09911bf2008-07-26 23:55:292554}
2555
[email protected]f7454892009-01-29 19:24:212556
[email protected]36b6dcb2008-11-12 01:19:572557///////////////////////////////////////////////////////////////////////////////
[email protected]69444cc2009-04-09 20:40:062558// Browser, In-progress download termination handling (private):
2559
2560bool Browser::CanCloseWithInProgressDownloads() {
2561 if (cancel_download_confirmation_state_ != NOT_PROMPTED) {
2562 // This should probably not happen.
2563 DCHECK(cancel_download_confirmation_state_ != WAITING_FOR_RESPONSE);
2564 return true;
2565 }
2566
2567 // If there are no download in-progress, our job is done.
2568 DownloadManager* download_manager = profile_->GetDownloadManager();
2569 if (!download_manager || download_manager->in_progress_count() == 0)
2570 return true;
2571
2572 // Let's figure out if we are the last window for our profile.
2573 // Note that we cannot just use BrowserList::GetBrowserCount as browser
2574 // windows closing is delayed and the returned count might include windows
2575 // that are being closed.
2576 int count = 0;
2577 for (BrowserList::const_iterator iter = BrowserList::begin();
2578 iter != BrowserList::end(); ++iter) {
2579 // Don't count this browser window or any other in the process of closing.
2580 if (*iter == this || (*iter)->is_attempting_to_close_browser_)
2581 continue;
2582
2583 // We test the original profile, because an incognito browser window keeps
2584 // the original profile alive (and its DownloadManager).
2585 // We also need to test explicitly the profile directly so that 2 incognito
2586 // profiles count as a match.
2587 if ((*iter)->profile() == profile() ||
2588 (*iter)->profile()->GetOriginalProfile() == profile())
2589 count++;
2590 }
2591 if (count > 0)
2592 return true;
2593
2594 cancel_download_confirmation_state_ = WAITING_FOR_RESPONSE;
2595 window_->ConfirmBrowserCloseWithPendingDownloads();
2596
2597 // Return false so the browser does not close. We'll close if the user
2598 // confirms in the dialog.
2599 return false;
2600}
2601
2602///////////////////////////////////////////////////////////////////////////////
[email protected]36b6dcb2008-11-12 01:19:572603// Browser, Assorted utility functions (private):
initial.commit09911bf2008-07-26 23:55:292604
initial.commit09911bf2008-07-26 23:55:292605Browser* Browser::GetOrCreateTabbedBrowser() {
2606 Browser* browser = BrowserList::FindBrowserWithType(
[email protected]299dabd2008-11-19 02:27:162607 profile_, TYPE_NORMAL);
[email protected]15952e462008-11-14 00:29:052608 if (!browser)
2609 browser = Browser::Create(profile_);
initial.commit09911bf2008-07-26 23:55:292610 return browser;
2611}
2612
[email protected]1f7d7e92009-06-02 20:55:042613void Browser::OpenURLAtIndex(TabContents* source,
2614 const GURL& url,
2615 const GURL& referrer,
2616 WindowOpenDisposition disposition,
2617 PageTransition::Type transition,
2618 int index,
2619 bool force_index) {
2620 // TODO(beng): Move all this code into a separate helper that has unit tests.
2621
2622 // No code for these yet
2623 DCHECK((disposition != NEW_POPUP) && (disposition != SAVE_TO_DISK));
2624
2625 TabContents* current_tab = source ? source : GetSelectedTabContents();
2626 bool source_tab_was_frontmost = (current_tab == GetSelectedTabContents());
2627 TabContents* new_contents = NULL;
2628
2629 // If the URL is part of the same web site, then load it in the same
2630 // SiteInstance (and thus the same process). This is an optimization to
2631 // reduce process overhead; it is not necessary for compatibility. (That is,
2632 // the new tab will not have script connections to the previous tab, so it
2633 // does not need to be part of the same SiteInstance or BrowsingInstance.)
2634 // Default to loading in a new SiteInstance and BrowsingInstance.
2635 // TODO(creis): should this apply to applications?
2636 SiteInstance* instance = NULL;
2637 // Don't use this logic when "--process-per-tab" is specified.
2638 if (!CommandLine::ForCurrentProcess()->HasSwitch(switches::kProcessPerTab)) {
2639 if (current_tab) {
2640 const GURL& current_url = current_tab->GetURL();
2641 if (SiteInstance::IsSameWebSite(current_url, url))
2642 instance = current_tab->GetSiteInstance();
2643 }
2644 }
2645
2646 // If this is not a normal window (such as a popup or an application), we can
2647 // only have one tab so a new tab always goes into a tabbed browser window.
2648 if (disposition != NEW_WINDOW && type_ != TYPE_NORMAL) {
2649 // If the disposition is OFF_THE_RECORD we don't want to create a new
2650 // browser that will itself create another OTR browser. This will result in
2651 // a browser leak (and crash below because no tab is created or selected).
2652 if (disposition == OFF_THE_RECORD) {
2653 OpenURLOffTheRecord(profile_, url);
2654 return;
2655 }
2656
2657 Browser* b = GetOrCreateTabbedBrowser();
2658 DCHECK(b);
2659
2660 // If we have just created a new browser window, make sure we select the
2661 // tab.
2662 if (b->tab_count() == 0 && disposition == NEW_BACKGROUND_TAB)
2663 disposition = NEW_FOREGROUND_TAB;
2664
2665 b->OpenURL(url, referrer, disposition, transition);
2666 b->window()->Show();
2667 return;
2668 }
2669
2670 if (profile_->IsOffTheRecord() && disposition == OFF_THE_RECORD)
2671 disposition = NEW_FOREGROUND_TAB;
2672
2673 if (disposition == SINGLETON_TAB) {
2674 ShowSingleDOMUITab(url);
2675 return;
2676 } else if (disposition == NEW_WINDOW) {
2677 Browser* browser = Browser::Create(profile_);
2678 new_contents = browser->AddTabWithURL(url, referrer, transition, true,
2679 index, force_index, instance);
2680 browser->window()->Show();
2681 } else if ((disposition == CURRENT_TAB) && current_tab) {
2682 tabstrip_model_.TabNavigating(current_tab, transition);
2683
2684 current_tab->controller().LoadURL(url, referrer, transition);
2685 new_contents = current_tab;
2686 if (GetStatusBubble())
2687 GetStatusBubble()->Hide();
2688
2689 // Update the location bar. This is synchronous. We specfically don't update
2690 // the load state since the load hasn't started yet and updating it will put
2691 // it out of sync with the actual state like whether we're displaying a
2692 // favicon, which controls the throbber. If we updated it here, the throbber
2693 // will show the default favicon for a split second when navigating away
2694 // from the new tab page.
2695 ScheduleUIUpdate(current_tab, TabContents::INVALIDATE_URL);
2696 } else if (disposition == OFF_THE_RECORD) {
2697 OpenURLOffTheRecord(profile_, url);
2698 return;
2699 } else if (disposition != SUPPRESS_OPEN) {
2700 new_contents = AddTabWithURL(url, referrer, transition,
2701 disposition != NEW_BACKGROUND_TAB, index, force_index, instance);
2702 }
2703
2704 if (disposition != NEW_BACKGROUND_TAB && source_tab_was_frontmost) {
2705 // Give the focus to the newly navigated tab, if the source tab was
2706 // front-most.
2707 new_contents->Focus();
2708 }
2709}
2710
initial.commit09911bf2008-07-26 23:55:292711void Browser::BuildPopupWindow(TabContents* source,
2712 TabContents* new_contents,
2713 const gfx::Rect& initial_pos) {
[email protected]9f5b80a2009-04-08 01:26:072714 BuildPopupWindowHelper(source, new_contents, initial_pos,
2715 (type_ & TYPE_APP) ? TYPE_APP_POPUP : TYPE_POPUP,
2716 profile_, false);
2717}
2718
2719void Browser::BuildPopupWindowHelper(TabContents* source,
2720 TabContents* new_contents,
2721 const gfx::Rect& initial_pos,
2722 Browser::Type browser_type,
2723 Profile* profile,
2724 bool start_restored) {
2725 Browser* browser = new Browser(browser_type, profile);
[email protected]15952e462008-11-14 00:29:052726 browser->set_override_bounds(initial_pos);
[email protected]9f5b80a2009-04-08 01:26:072727
2728 if (start_restored)
2729 browser->set_maximized_state(MAXIMIZED_STATE_UNMAXIMIZED);
2730
[email protected]15952e462008-11-14 00:29:052731 browser->CreateBrowserWindow();
[email protected]6b2ee922009-04-30 20:40:532732 browser->tabstrip_model()->AppendTabContents(new_contents, true);
[email protected]2f69fb52008-12-12 18:50:392733 browser->window()->Show();
initial.commit09911bf2008-07-26 23:55:292734}
2735
[email protected]d043c2cc2009-03-25 18:30:452736GURL Browser::GetHomePage() const {
[email protected]15952e462008-11-14 00:29:052737 if (profile_->GetPrefs()->GetBoolean(prefs::kHomePageIsNewTabPage))
[email protected]b689fce72009-03-17 22:45:342738 return GURL(chrome::kChromeUINewTabURL);
[email protected]15952e462008-11-14 00:29:052739 GURL home_page = GURL(URLFixerUpper::FixupURL(
[email protected]a239c3f2009-02-17 22:13:192740 WideToUTF8(profile_->GetPrefs()->GetString(prefs::kHomePage)),
2741 std::string()));
[email protected]15952e462008-11-14 00:29:052742 if (!home_page.is_valid())
[email protected]b689fce72009-03-17 22:45:342743 return GURL(chrome::kChromeUINewTabURL);
[email protected]15952e462008-11-14 00:29:052744 return home_page;
[email protected]36b6dcb2008-11-12 01:19:572745}
initial.commit09911bf2008-07-26 23:55:292746
[email protected]4f3dc372009-02-24 00:10:292747void Browser::FindInPage(bool find_next, bool forward_direction) {
[email protected]4801ecc2009-04-05 04:52:582748 ShowFindBar();
[email protected]4f3dc372009-02-24 00:10:292749 if (find_next) {
[email protected]57c6a652009-05-04 07:58:342750 GetSelectedTabContents()->StartFinding(string16(),
[email protected]e491f1c2009-05-22 20:28:122751 forward_direction,
2752 false); // Not case sensitive.
[email protected]4f3dc372009-02-24 00:10:292753 }
[email protected]fbd77592008-11-12 20:50:272754}
[email protected]cb17f7f2009-02-06 18:14:482755
[email protected]36b6dcb2008-11-12 01:19:572756void Browser::CloseFrame() {
2757 window_->Close();
initial.commit09911bf2008-07-26 23:55:292758}
2759
2760// static
2761std::wstring Browser::ComputeApplicationNameFromURL(const GURL& url) {
2762 std::string t;
2763 t.append(url.host());
2764 t.append("_");
2765 t.append(url.path());
2766 return UTF8ToWide(t);
2767}
2768
2769// static
initial.commit09911bf2008-07-26 23:55:292770void Browser::RegisterAppPrefs(const std::wstring& app_name) {
2771 // A set of apps that we've already started.
2772 static std::set<std::wstring>* g_app_names = NULL;
2773
2774 if (!g_app_names)
2775 g_app_names = new std::set<std::wstring>;
2776
2777 // Only register once for each app name.
2778 if (g_app_names->find(app_name) != g_app_names->end())
2779 return;
2780 g_app_names->insert(app_name);
2781
2782 // We need to register the window position pref.
2783 std::wstring window_pref(prefs::kBrowserWindowPlacement);
2784 window_pref.append(L"_");
2785 window_pref.append(app_name);
2786 PrefService* prefs = g_browser_process->local_state();
2787 DCHECK(prefs);
2788
2789 prefs->RegisterDictionaryPref(window_pref.c_str());
2790}
[email protected]5c238752009-06-13 10:29:072791
2792///////////////////////////////////////////////////////////////////////////////
2793// BrowserToolbarModel (private):
2794
2795NavigationController* Browser::BrowserToolbarModel::GetNavigationController() {
2796 // This |current_tab| can be NULL during the initialization of the
2797 // toolbar during window creation (i.e. before any tabs have been added
2798 // to the window).
2799 TabContents* current_tab = browser_->GetSelectedTabContents();
2800 return current_tab ? &current_tab->controller() : NULL;
2801}