blob: a483241fef2ed506ac0e4255e69a7b04f25bfc2e [file] [log] [blame]
license.botbf09a502008-08-24 00:55:551// Copyright (c) 2006-2008 The Chromium Authors. All rights reserved.
2// Use of this source code is governed by a BSD-style license that can be
3// found in the LICENSE file.
initial.commit09911bf2008-07-26 23:55:294
initial.commit09911bf2008-07-26 23:55:295#include <windows.h>
6#include <shellapi.h>
7
[email protected]15952e462008-11-14 00:29:058#include "chrome/browser/browser.h"
9
initial.commit09911bf2008-07-26 23:55:2910#include "base/command_line.h"
11#include "base/idle_timer.h"
12#include "base/logging.h"
13#include "base/string_util.h"
[email protected]012d2fb2008-09-13 01:30:0514#include "chrome/app/chrome_dll_resource.h"
[email protected]36b6dcb2008-11-12 01:19:5715#include "chrome/app/locales/locale_settings.h"
16#include "chrome/browser/automation/ui_controls.h"
initial.commit09911bf2008-07-26 23:55:2917#include "chrome/browser/browser_list.h"
18#include "chrome/browser/browser_process.h"
19#include "chrome/browser/browser_shutdown.h"
20#include "chrome/browser/browser_url_handler.h"
[email protected]012d2fb2008-09-13 01:30:0521#include "chrome/browser/browser_window.h"
initial.commit09911bf2008-07-26 23:55:2922#include "chrome/browser/cert_store.h"
[email protected]36b6dcb2008-11-12 01:19:5723#include "chrome/browser/character_encoding.h"
[email protected]1eb89e82008-08-15 12:27:0324#include "chrome/browser/debugger/debugger_window.h"
[email protected]5e495462008-11-20 23:07:4125#include "chrome/browser/dock_info.h"
[email protected]2baf83d2008-07-30 05:58:1726#include "chrome/browser/dom_ui/new_tab_ui.h"
[email protected]37936ee2008-09-14 01:09:5027#include "chrome/browser/download/save_package.h"
[email protected]36b6dcb2008-11-12 01:19:5728#include "chrome/browser/history_tab_ui.h"
29#include "chrome/browser/interstitial_page.h"
initial.commit09911bf2008-07-26 23:55:2930#include "chrome/browser/navigation_controller.h"
31#include "chrome/browser/navigation_entry.h"
[email protected]36b6dcb2008-11-12 01:19:5732#include "chrome/browser/options_window.h"
initial.commit09911bf2008-07-26 23:55:2933#include "chrome/browser/plugin_process_host.h"
34#include "chrome/browser/plugin_service.h"
35#include "chrome/browser/profile.h"
[email protected]169627b2008-12-06 19:30:1936#include "chrome/browser/sessions/session_service.h"
initial.commit09911bf2008-07-26 23:55:2937#include "chrome/browser/ssl_error_info.h"
38#include "chrome/browser/site_instance.h"
[email protected]36b6dcb2008-11-12 01:19:5739#include "chrome/browser/task_manager.h"
initial.commit09911bf2008-07-26 23:55:2940#include "chrome/browser/url_fixer_upper.h"
[email protected]f2530062008-12-03 23:52:0341#include "chrome/browser/user_data_manager.h"
initial.commit09911bf2008-07-26 23:55:2942#include "chrome/browser/user_metrics.h"
43#include "chrome/browser/view_ids.h"
[email protected]36b6dcb2008-11-12 01:19:5744#include "chrome/browser/views/download_tab_view.h"
45#include "chrome/browser/views/go_button.h"
initial.commit09911bf2008-07-26 23:55:2946#include "chrome/browser/views/location_bar_view.h"
[email protected]f2530062008-12-03 23:52:0347#include "chrome/browser/views/new_profile_dialog.h"
48#include "chrome/browser/views/select_profile_dialog.h"
[email protected]012d2fb2008-09-13 01:30:0549#include "chrome/browser/views/status_bubble.h"
initial.commit09911bf2008-07-26 23:55:2950#include "chrome/browser/views/toolbar_star_toggle.h"
[email protected]807bfce2008-10-14 16:42:2551#include "chrome/browser/web_contents_view.h"
initial.commit09911bf2008-07-26 23:55:2952#include "chrome/browser/window_sizer.h"
53#include "chrome/common/chrome_constants.h"
54#include "chrome/common/chrome_switches.h"
55#include "chrome/common/l10n_util.h"
56#include "chrome/common/pref_names.h"
57#include "chrome/common/pref_service.h"
[email protected]1eb89e82008-08-15 12:27:0358#include "chrome/common/win_util.h"
initial.commit09911bf2008-07-26 23:55:2959#include "net/base/cookie_monster.h"
60#include "net/base/cookie_policy.h"
61#include "net/base/net_util.h"
62#include "net/base/registry_controlled_domain.h"
63
[email protected]b08de9cd2008-08-27 23:40:2264#include "chromium_strings.h"
initial.commit09911bf2008-07-26 23:55:2965#include "generated_resources.h"
66
[email protected]e1acf6f2008-10-27 20:43:3367using base::TimeDelta;
68
initial.commit09911bf2008-07-26 23:55:2969static BrowserList g_browserlist;
70
71// How long we wait before updating the browser chrome while loading a page.
72static const int kUIUpdateCoalescingTimeMS = 200;
73
74// Idle time before helping prune memory consumption.
75static const int kBrowserReleaseMemoryInterval = 30; // In seconds.
76
77// How much horizontal and vertical offset there is between newly opened
78// windows.
[email protected]eb0c1e42008-08-04 17:58:0079static const int kWindowTilePixels = 20;
initial.commit09911bf2008-07-26 23:55:2980
[email protected]36b6dcb2008-11-12 01:19:5781///////////////////////////////////////////////////////////////////////////////
initial.commit09911bf2008-07-26 23:55:2982
83// A task to reduce the working set of the plugins.
84class ReducePluginsWorkingSetTask : public Task {
85 public:
86 virtual void Run() {
87 for (PluginProcessHostIterator iter; !iter.Done(); ++iter) {
88 PluginProcessHost* plugin = const_cast<PluginProcessHost*>(*iter);
89 DCHECK(plugin->process());
[email protected]176aa482008-11-14 03:25:1590 base::Process process(plugin->process());
initial.commit09911bf2008-07-26 23:55:2991 process.ReduceWorkingSet();
92 }
93 }
94};
95
96// A browser task to run when the user is not using the browser.
97// In our case, we're trying to be nice to the operating system and release
98// memory not in use.
[email protected]aeab57ea2008-08-28 20:50:1299class BrowserIdleTimer : public base::IdleTimer {
initial.commit09911bf2008-07-26 23:55:29100 public:
[email protected]aeab57ea2008-08-28 20:50:12101 BrowserIdleTimer()
102 : base::IdleTimer(TimeDelta::FromSeconds(kBrowserReleaseMemoryInterval),
103 false) {
initial.commit09911bf2008-07-26 23:55:29104 }
105
106 virtual void OnIdle() {
107 // We're idle. Release browser and renderer unused pages.
108
109 // Handle the Browser.
[email protected]176aa482008-11-14 03:25:15110 base::Process process(GetCurrentProcess());
initial.commit09911bf2008-07-26 23:55:29111 process.ReduceWorkingSet();
112
113 // Handle the Renderer(s).
114 RenderProcessHost::iterator renderer_iter;
115 for (renderer_iter = RenderProcessHost::begin(); renderer_iter !=
[email protected]176aa482008-11-14 03:25:15116 RenderProcessHost::end(); renderer_iter++) {
117 base::Process process = renderer_iter->second->process();
initial.commit09911bf2008-07-26 23:55:29118 process.ReduceWorkingSet();
119 }
120
[email protected]36b6dcb2008-11-12 01:19:57121 // Handle the Plugin(s). We need to iterate through the plugin processes
122 // on the IO thread because that thread manages the plugin process
123 // collection.
initial.commit09911bf2008-07-26 23:55:29124 g_browser_process->io_thread()->message_loop()->PostTask(FROM_HERE,
125 new ReducePluginsWorkingSetTask());
126 }
127};
128
[email protected]36b6dcb2008-11-12 01:19:57129///////////////////////////////////////////////////////////////////////////////
initial.commit09911bf2008-07-26 23:55:29130
131struct Browser::UIUpdate {
132 UIUpdate(const TabContents* src, unsigned flags)
133 : source(src),
134 changed_flags(flags) {
135 }
136
137 // The source of the update.
138 const TabContents* source;
139
140 // What changed in the UI.
141 unsigned changed_flags;
142};
143
[email protected]36b6dcb2008-11-12 01:19:57144///////////////////////////////////////////////////////////////////////////////
145// Browser, Constructors, Creation, Showing:
initial.commit09911bf2008-07-26 23:55:29146
[email protected]299dabd2008-11-19 02:27:16147Browser::Browser(Type type, Profile* profile)
[email protected]15952e462008-11-14 00:29:05148 : type_(type),
149 profile_(profile),
[email protected]f3e99e32008-07-30 04:48:39150 window_(NULL),
initial.commit09911bf2008-07-26 23:55:29151 tabstrip_model_(this, profile),
[email protected]15952e462008-11-14 00:29:05152 controller_(this),
initial.commit09911bf2008-07-26 23:55:29153 toolbar_model_(this),
[email protected]15952e462008-11-14 00:29:05154 chrome_updater_factory_(this),
155 is_attempting_to_close_browser_(false),
156 override_maximized_(false),
157 method_factory_(this),
158 idle_task_(new BrowserIdleTimer) {
initial.commit09911bf2008-07-26 23:55:29159 tabstrip_model_.AddObserver(this);
160
[email protected]e83f1682008-09-07 23:57:40161 NotificationService::current()->AddObserver(
162 this, NOTIFY_SSL_STATE_CHANGED, NotificationService::AllSources());
initial.commit09911bf2008-07-26 23:55:29163
initial.commit09911bf2008-07-26 23:55:29164 InitCommandState();
165 BrowserList::AddBrowser(this);
166
167 encoding_auto_detect_.Init(prefs::kWebKitUsesUniversalDetector,
168 profile_->GetPrefs(), NULL);
169
170 // Trim browser memory on idle for low & medium memory models.
171 if (g_browser_process->memory_model() < BrowserProcess::HIGH_MEMORY_MODEL)
172 idle_task_->Start();
initial.commit09911bf2008-07-26 23:55:29173}
174
175Browser::~Browser() {
176 // The tab strip should be empty at this point.
177 DCHECK(tabstrip_model_.empty());
178 tabstrip_model_.RemoveObserver(this);
179
180 BrowserList::RemoveBrowser(this);
181
182 if (!BrowserList::HasBrowserWithProfile(profile_)) {
183 // We're the last browser window with this profile. We need to nuke the
184 // TabRestoreService, which will start the shutdown of the
185 // NavigationControllers and allow for proper shutdown. If we don't do this
186 // chrome won't shutdown cleanly, and may end up crashing when some
187 // thread tries to use the IO thread (or another thread) that is no longer
188 // valid.
189 profile_->ResetTabRestoreService();
190 }
191
192 SessionService* session_service = profile_->GetSessionService();
193 if (session_service)
194 session_service->WindowClosed(session_id_);
195
[email protected]d8375fd2008-11-25 22:45:39196 TabRestoreService* tab_restore_service = profile()->GetTabRestoreService();
197 if (tab_restore_service)
198 tab_restore_service->BrowserClosed(this);
199
[email protected]e83f1682008-09-07 23:57:40200 NotificationService::current()->RemoveObserver(
201 this, NOTIFY_SSL_STATE_CHANGED, NotificationService::AllSources());
initial.commit09911bf2008-07-26 23:55:29202
initial.commit09911bf2008-07-26 23:55:29203 if (profile_->IsOffTheRecord() &&
204 !BrowserList::IsOffTheRecordSessionActive()) {
205 // We reuse the OTR cookie store across OTR windows. If the last OTR
206 // window is closed, then we want to wipe the cookie store clean, so when
207 // an OTR window is open again, it starts with an empty cookie store. This
208 // also frees up the memory that the OTR cookies were using. OTR never
209 // loads or writes persistent cookies (there is no backing store), so we
210 // can just delete all of the cookies in the store.
211 profile_->GetRequestContext()->cookie_store()->DeleteAll(false);
212 }
213
214 // There may be pending file dialogs, we need to tell them that we've gone
215 // away so they don't try and call back to us.
216 if (select_file_dialog_.get())
217 select_file_dialog_->ListenerDestroyed();
218}
219
[email protected]15952e462008-11-14 00:29:05220// static
221Browser* Browser::Create(Profile* profile) {
[email protected]299dabd2008-11-19 02:27:16222 Browser* browser = new Browser(TYPE_NORMAL, profile);
[email protected]15952e462008-11-14 00:29:05223 browser->CreateBrowserWindow();
224 return browser;
225}
[email protected]6104acf2008-11-11 22:27:34226
[email protected]15952e462008-11-14 00:29:05227// static
228Browser* Browser::CreateForPopup(Profile* profile) {
[email protected]299dabd2008-11-19 02:27:16229 Browser* browser = new Browser(TYPE_POPUP, profile);
[email protected]15952e462008-11-14 00:29:05230 browser->CreateBrowserWindow();
231 return browser;
232}
233
234// static
235Browser* Browser::CreateForApp(const std::wstring& app_name,
236 Profile* profile) {
[email protected]299dabd2008-11-19 02:27:16237 Browser* browser = new Browser(TYPE_APP, profile);
[email protected]15952e462008-11-14 00:29:05238 browser->app_name_ = app_name;
239 browser->CreateBrowserWindow();
240 return browser;
241}
242
243void Browser::CreateBrowserWindow() {
244 DCHECK(!window_);
245 window_ = BrowserWindow::CreateBrowserWindow(this);
246
247 // Show the First Run information bubble if we've been told to.
248 PrefService* local_state = g_browser_process->local_state();
249 if (local_state->IsPrefRegistered(prefs::kShouldShowFirstRunBubble) &&
250 local_state->GetBoolean(prefs::kShouldShowFirstRunBubble)) {
251 // Reset the preference so we don't show the bubble for subsequent windows.
252 local_state->ClearPref(prefs::kShouldShowFirstRunBubble);
253 GetLocationBarView()->ShowFirstRunBubble();
initial.commit09911bf2008-07-26 23:55:29254 }
initial.commit09911bf2008-07-26 23:55:29255}
256
[email protected]36b6dcb2008-11-12 01:19:57257///////////////////////////////////////////////////////////////////////////////
258// Browser, Creation Helpers:
259
260// static
[email protected]15952e462008-11-14 00:29:05261void Browser::OpenEmptyWindow(Profile* profile) {
262 Browser* browser = Browser::Create(profile);
[email protected]36b6dcb2008-11-12 01:19:57263 browser->AddBlankTab(true);
[email protected]15952e462008-11-14 00:29:05264 browser->window()->Show();
initial.commit09911bf2008-07-26 23:55:29265}
266
[email protected]36b6dcb2008-11-12 01:19:57267// static
268void Browser::OpenURLOffTheRecord(Profile* profile, const GURL& url) {
269 Profile* off_the_record_profile = profile->GetOffTheRecordProfile();
270 Browser* browser = BrowserList::FindBrowserWithType(
[email protected]15952e462008-11-14 00:29:05271 off_the_record_profile,
[email protected]299dabd2008-11-19 02:27:16272 TYPE_NORMAL);
[email protected]15952e462008-11-14 00:29:05273 if (!browser)
274 browser = Browser::Create(off_the_record_profile);
[email protected]36b6dcb2008-11-12 01:19:57275 // TODO(eroman): should we have referrer here?
276 browser->AddTabWithURL(url, GURL(), PageTransition::LINK, true, NULL);
[email protected]15952e462008-11-14 00:29:05277 browser->window()->Show();
[email protected]2baf83d2008-07-30 05:58:17278}
279
[email protected]36b6dcb2008-11-12 01:19:57280// static
[email protected]15952e462008-11-14 00:29:05281void Browser::OpenWebApplication(Profile* profile, WebApp* app) {
[email protected]36b6dcb2008-11-12 01:19:57282 const std::wstring& app_name =
283 app->name().empty() ? ComputeApplicationNameFromURL(app->url()) :
284 app->name();
[email protected]36b6dcb2008-11-12 01:19:57285 RegisterAppPrefs(app_name);
[email protected]15952e462008-11-14 00:29:05286
287 Browser* browser = Browser::CreateForApp(app_name, profile);
[email protected]36b6dcb2008-11-12 01:19:57288 browser->AddWebApplicationTab(profile, app, false);
[email protected]15952e462008-11-14 00:29:05289 browser->window()->Show();
initial.commit09911bf2008-07-26 23:55:29290}
291
[email protected]36b6dcb2008-11-12 01:19:57292///////////////////////////////////////////////////////////////////////////////
293// Browser, Command API:
initial.commit09911bf2008-07-26 23:55:29294
[email protected]36b6dcb2008-11-12 01:19:57295bool Browser::SupportsCommand(int id) const {
296 return controller_.SupportsCommand(id);
initial.commit09911bf2008-07-26 23:55:29297}
298
[email protected]36b6dcb2008-11-12 01:19:57299bool Browser::IsCommandEnabled(int id) const {
[email protected]5b0295eb2f2008-11-16 03:03:13300 // No commands are enabled if there is not yet any selected tab.
[email protected]e673f6c2008-12-09 21:24:11301 // TODO(pkasting): It seems like we should not need this, because either
302 // most/all commands should not have been enabled yet anyway or the ones that
303 // are enabled should be global, or safe themselves against having no selected
304 // tab. However, Ben says he tried removing this before and got lots of
305 // crashes, e.g. from Windows sending WM_COMMANDs at random times during
306 // window construction. This probably could use closer examination someday.
[email protected]5b0295eb2f2008-11-16 03:03:13307 if (!GetSelectedTabContents())
308 return false;
309
[email protected]e673f6c2008-12-09 21:24:11310 // TODO(pkasting): Should maybe enable/disable this in
311 // NavigationStateChanged()?
312 if (id == IDC_STOP)
313 return IsCurrentPageLoading();
314
[email protected]c7c42332008-11-15 01:10:54315 return controller_.IsCommandEnabled(id);
[email protected]36b6dcb2008-11-12 01:19:57316}
317
318///////////////////////////////////////////////////////////////////////////////
[email protected]36b6dcb2008-11-12 01:19:57319// Browser, State Storage and Retrieval for UI:
320
[email protected]bc9a5152008-11-15 00:32:04321std::wstring Browser::GetWindowPlacementKey() const {
[email protected]36b6dcb2008-11-12 01:19:57322 std::wstring name(prefs::kBrowserWindowPlacement);
323 if (!app_name_.empty()) {
324 name.append(L"_");
325 name.append(app_name_);
326 }
[email protected]bc9a5152008-11-15 00:32:04327 return name;
328}
[email protected]36b6dcb2008-11-12 01:19:57329
[email protected]bc9a5152008-11-15 00:32:04330bool Browser::ShouldSaveWindowPlacement() const {
331 // We don't save window position for popups.
[email protected]299dabd2008-11-19 02:27:16332 return type() != TYPE_POPUP;
[email protected]bc9a5152008-11-15 00:32:04333}
[email protected]36b6dcb2008-11-12 01:19:57334
[email protected]bc9a5152008-11-15 00:32:04335void Browser::SaveWindowPlacement(const gfx::Rect& bounds, bool maximized) {
336 // Save to the session storage service, used when reloading a past session.
337 // Note that we don't want to be the ones who cause lazy initialization of
338 // the session service. This function gets called during initial window
339 // showing, and we don't want to bring in the session service this early.
[email protected]36b6dcb2008-11-12 01:19:57340 if (profile()->HasSessionService()) {
341 SessionService* session_service = profile()->GetSessionService();
342 if (session_service)
343 session_service->SetWindowBounds(session_id_, bounds, maximized);
344 }
345}
346
[email protected]15952e462008-11-14 00:29:05347gfx::Rect Browser::GetSavedWindowBounds() const {
348 CommandLine parsed_command_line;
349 bool record_mode = parsed_command_line.HasSwitch(switches::kRecordMode);
350 bool playback_mode = parsed_command_line.HasSwitch(switches::kPlaybackMode);
351 if (record_mode || playback_mode) {
352 // In playback/record mode we always fix the size of the browser and
353 // move it to (0,0). The reason for this is two reasons: First we want
354 // resize/moves in the playback to still work, and Second we want
355 // playbacks to work (as much as possible) on machines w/ different
356 // screen sizes.
357 return gfx::Rect(0, 0, 800, 600);
358 }
359
360 gfx::Rect restored_bounds = override_bounds_;
361 bool maximized;
362 WindowSizer::GetBrowserWindowBounds(app_name_, restored_bounds,
363 &restored_bounds, &maximized);
364 return restored_bounds;
365}
366
367// TODO(beng): obtain maximized state some other way so we don't need to go
368// through all this hassle.
369bool Browser::GetSavedMaximizedState() const {
370 if (CommandLine().HasSwitch(switches::kStartMaximized))
371 return true;
372
373 gfx::Rect restored_bounds;
374 bool maximized = override_maximized_;
375 WindowSizer::GetBrowserWindowBounds(app_name_, restored_bounds,
376 &restored_bounds, &maximized);
377 return maximized;
[email protected]36b6dcb2008-11-12 01:19:57378}
379
380SkBitmap Browser::GetCurrentPageIcon() const {
[email protected]c7c42332008-11-15 01:10:54381 return GetSelectedTabContents()->GetFavIcon();
[email protected]36b6dcb2008-11-12 01:19:57382}
383
384std::wstring Browser::GetCurrentPageTitle() const {
385 TabContents* contents = tabstrip_model_.GetSelectedTabContents();
386 std::wstring title;
[email protected]c7c42332008-11-15 01:10:54387
388 // |contents| can be NULL because GetCurrentPageTitle is called by the window
389 // during the window's creation (before tabs have been added).
[email protected]36b6dcb2008-11-12 01:19:57390 if (contents) {
391 title = contents->GetTitle();
392 FormatTitleForDisplay(&title);
393 }
394 if (title.empty())
395 title = l10n_util::GetString(IDS_TAB_UNTITLED_TITLE);
396
397 return l10n_util::GetStringF(IDS_BROWSER_WINDOW_TITLE_FORMAT, title);
398}
399
[email protected]afb73882008-11-14 22:40:44400bool Browser::IsCurrentPageLoading() const {
[email protected]adf650f2008-12-09 16:10:06401 // GetSelectedTabContents can return NULL for example under Purify when
402 // the animations are running slowly and this function is called on a timer
403 // through LoadingAnimationCallback.
404 TabContents* tab_contents = GetSelectedTabContents();
405 return tab_contents && tab_contents->is_loading();
[email protected]afb73882008-11-14 22:40:44406}
407
[email protected]36b6dcb2008-11-12 01:19:57408// static
409void Browser::FormatTitleForDisplay(std::wstring* title) {
410 size_t current_index = 0;
411 size_t match_index;
412 while ((match_index = title->find(L'\n', current_index)) !=
413 std::wstring::npos) {
414 title->replace(match_index, 1, L"");
415 current_index = match_index;
416 }
417}
418
419///////////////////////////////////////////////////////////////////////////////
420// Browser, OnBeforeUnload handling:
421
422bool Browser::ShouldCloseWindow() {
423 if (HasCompletedUnloadProcessing()) {
424 return true;
425 }
426 is_attempting_to_close_browser_ = true;
427
428 for (int i = 0; i < tab_count(); ++i) {
429 if (tabstrip_model_.TabHasUnloadListener(i)) {
430 TabContents* tab = GetTabContentsAt(i);
[email protected]06b42f032008-12-03 18:43:05431 tabs_needing_before_unload_fired_.insert(tab);
[email protected]36b6dcb2008-11-12 01:19:57432 }
433 }
434
435 if (tabs_needing_before_unload_fired_.empty())
436 return true;
437
438 ProcessPendingTabs();
439 return false;
440}
441
442void Browser::OnWindowClosing() {
443 if (!ShouldCloseWindow())
444 return;
445
446 if (BrowserList::size() == 1)
447 browser_shutdown::OnShutdownStarting(browser_shutdown::WINDOW_CLOSE);
448
449 // Don't use HasSessionService here, we want to force creation of the
450 // session service so that user can restore what was open.
451 SessionService* session_service = profile()->GetSessionService();
452 if (session_service)
453 session_service->WindowClosing(session_id());
454
[email protected]d8375fd2008-11-25 22:45:39455 TabRestoreService* tab_restore_service = profile()->GetTabRestoreService();
456 if (tab_restore_service)
457 tab_restore_service->BrowserClosing(this);
458
[email protected]36b6dcb2008-11-12 01:19:57459 CloseAllTabs();
460}
461
462///////////////////////////////////////////////////////////////////////////////
[email protected]36b6dcb2008-11-12 01:19:57463// Browser, Tab adding/showing functions:
464
465TabContents* Browser::AddTabWithURL(
466 const GURL& url, const GURL& referrer, PageTransition::Type transition,
467 bool foreground, SiteInstance* instance) {
[email protected]299dabd2008-11-19 02:27:16468 if (type_ == TYPE_APP && tabstrip_model_.count() == 1) {
[email protected]36b6dcb2008-11-12 01:19:57469 NOTREACHED() << "Cannot add a tab in a mono tab application.";
470 return NULL;
471 }
472
473 GURL url_to_load = url;
474 if (url_to_load.is_empty())
475 url_to_load = GetHomePage();
476 TabContents* contents =
477 CreateTabContentsForURL(url_to_load, referrer, profile_, transition,
478 false, instance);
479 tabstrip_model_.AddTabContents(contents, -1, transition, foreground);
480 // By default, content believes it is not hidden. When adding contents
481 // in the background, tell it that it's hidden.
482 if (!foreground)
483 contents->WasHidden();
484 return contents;
485}
486
487TabContents* Browser::AddWebApplicationTab(Profile* profile,
488 WebApp* web_app,
489 bool lazy) {
490 DCHECK(web_app);
491
492 // TODO(acw): Do we need an "application launched" transition type?
493 // TODO(creis): Should we reuse the current instance (ie. process) here?
494 TabContents* contents =
495 CreateTabContentsForURL(web_app->url(), GURL(), profile,
496 PageTransition::LINK, lazy, NULL);
497 if (contents->AsWebContents())
498 contents->AsWebContents()->SetWebApp(web_app);
499
500 if (lazy) {
501 contents->controller()->LoadURLLazily(
502 web_app->url(), GURL(), PageTransition::LINK, web_app->name(), NULL);
503 }
504 tabstrip_model_.AddTabContents(contents, -1, PageTransition::LINK, !lazy);
505 return contents;
506}
507
508TabContents* Browser::AddTabWithNavigationController(
509 NavigationController* ctrl, PageTransition::Type type) {
510 TabContents* tc = ctrl->active_contents();
511 tabstrip_model_.AddTabContents(tc, -1, type, true);
512 return tc;
513}
514
515NavigationController* Browser::AddRestoredTab(
516 const std::vector<TabNavigation>& navigations,
517 int tab_index,
518 int selected_navigation,
519 bool select) {
520 NavigationController* restored_controller =
521 BuildRestoredNavigationController(navigations, selected_navigation);
522
523 tabstrip_model_.InsertTabContentsAt(
524 tab_index,
525 restored_controller->active_contents(),
526 select, false);
527 if (profile_->HasSessionService()) {
528 SessionService* session_service = profile_->GetSessionService();
529 if (session_service)
530 session_service->TabRestored(restored_controller);
531 }
532 return restored_controller;
533}
534
535void Browser::ReplaceRestoredTab(
536 const std::vector<TabNavigation>& navigations,
537 int selected_navigation) {
538 NavigationController* restored_controller =
539 BuildRestoredNavigationController(navigations, selected_navigation);
540
541 tabstrip_model_.ReplaceNavigationControllerAt(
542 tabstrip_model_.selected_index(),
543 restored_controller);
544}
545
546void Browser::ShowNativeUITab(const GURL& url) {
547 int i, c;
548 TabContents* tc;
549 for (i = 0, c = tabstrip_model_.count(); i < c; ++i) {
550 tc = tabstrip_model_.GetTabContentsAt(i);
551 if (tc->type() == TAB_CONTENTS_NATIVE_UI &&
552 tc->GetURL() == url) {
553 tabstrip_model_.SelectTabContentsAt(i, false);
554 return;
555 }
556 }
557
558 TabContents* contents = CreateTabContentsForURL(url, GURL(), profile_,
559 PageTransition::LINK, false,
560 NULL);
561 AddNewContents(NULL, contents, NEW_FOREGROUND_TAB, gfx::Rect(), true);
562}
563
564///////////////////////////////////////////////////////////////////////////////
565// Browser, Assorted browser commands:
566
567void Browser::GoBack() {
[email protected]fbd77592008-11-12 20:50:27568 UserMetrics::RecordAction(L"Back", profile_);
569
[email protected]36b6dcb2008-11-12 01:19:57570 // If we are showing an interstitial, just hide it.
571 TabContents* current_tab = GetSelectedTabContents();
[email protected]c7c42332008-11-15 01:10:54572 WebContents* web_contents = current_tab->AsWebContents();
573 if (web_contents && web_contents->showing_interstitial_page()) {
574 // Pressing back on an interstitial page means "don't proceed".
575 web_contents->interstitial_page()->DontProceed();
576 return;
[email protected]36b6dcb2008-11-12 01:19:57577 }
[email protected]c7c42332008-11-15 01:10:54578 if (current_tab->controller()->CanGoBack())
579 current_tab->controller()->GoBack();
[email protected]36b6dcb2008-11-12 01:19:57580}
581
582void Browser::GoForward() {
[email protected]fbd77592008-11-12 20:50:27583 UserMetrics::RecordAction(L"Forward", profile_);
[email protected]c7c42332008-11-15 01:10:54584 if (GetSelectedTabContents()->controller()->CanGoForward())
585 GetSelectedTabContents()->controller()->GoForward();
[email protected]36b6dcb2008-11-12 01:19:57586}
587
588void Browser::Reload() {
[email protected]fbd77592008-11-12 20:50:27589 UserMetrics::RecordAction(L"Reload", profile_);
590
[email protected]36b6dcb2008-11-12 01:19:57591 // If we are showing an interstitial, treat this as an OpenURL.
592 TabContents* current_tab = GetSelectedTabContents();
593 if (current_tab) {
594 WebContents* web_contents = current_tab->AsWebContents();
595 if (web_contents && web_contents->showing_interstitial_page()) {
596 NavigationEntry* entry = current_tab->controller()->GetActiveEntry();
597 DCHECK(entry); // Should exist if interstitial is showing.
598 OpenURL(entry->url(), GURL(), CURRENT_TAB, PageTransition::RELOAD);
599 return;
600 }
601 }
602
603 if (current_tab) {
604 // As this is caused by a user action, give the focus to the page.
605 current_tab->Focus();
606 current_tab->controller()->Reload(true);
607 }
608}
609
[email protected]36b6dcb2008-11-12 01:19:57610void Browser::Home() {
[email protected]fbd77592008-11-12 20:50:27611 UserMetrics::RecordAction(L"Home", profile_);
[email protected]36b6dcb2008-11-12 01:19:57612 GURL homepage_url = GetHomePage();
613 GetSelectedTabContents()->controller()->LoadURL(
614 homepage_url, GURL(), PageTransition::AUTO_BOOKMARK);
615}
616
[email protected]fbd77592008-11-12 20:50:27617void Browser::OpenCurrentURL() {
618 UserMetrics::RecordAction(L"LoadURL", profile_);
619 LocationBarView* lbv = GetLocationBarView();
620 if (lbv) {
621 OpenURL(GURL(lbv->location_input()), GURL(), lbv->disposition(),
622 lbv->transition());
[email protected]fbd77592008-11-12 20:50:27623 }
624}
625
[email protected]84214982008-12-10 18:49:10626void Browser::Go() {
627 UserMetrics::RecordAction(L"Go", profile_);
628 LocationBarView* lbv = GetLocationBarView();
629 if (lbv)
630 lbv->location_entry()->model()->AcceptInput(CURRENT_TAB, false);
631}
632
633void Browser::Stop() {
634 UserMetrics::RecordAction(L"Stop", profile_);
635 GetSelectedTabContents()->AsWebContents()->Stop();
636}
637
638void Browser::NewWindow() {
639 UserMetrics::RecordAction(L"NewWindow", profile_);
640 Browser::OpenEmptyWindow(profile_->GetOriginalProfile());
641}
642
643void Browser::NewIncognitoWindow() {
644 UserMetrics::RecordAction(L"NewIncognitoWindow", profile_);
645 Browser::OpenEmptyWindow(profile_->GetOffTheRecordProfile());
646}
647
648void Browser::NewProfileWindowByIndex(int index) {
649 UserMetrics::RecordAction(L"NewProfileWindowByIndex", profile_);
650 UserDataManager::Get()->LaunchChromeForProfile(index);
651}
652
653void Browser::CloseWindow() {
654 UserMetrics::RecordAction(L"CloseWindow", profile_);
655 window_->Close();
656}
657
[email protected]fbd77592008-11-12 20:50:27658void Browser::NewTab() {
659 UserMetrics::RecordAction(L"NewTab", profile_);
[email protected]299dabd2008-11-19 02:27:16660 if (type() == TYPE_NORMAL) {
[email protected]fbd77592008-11-12 20:50:27661 AddBlankTab(true);
662 } else {
663 Browser* b = GetOrCreateTabbedBrowser();
[email protected]fbd77592008-11-12 20:50:27664 b->AddBlankTab(true);
[email protected]15952e462008-11-14 00:29:05665 b->window()->Show();
[email protected]fbd77592008-11-12 20:50:27666 }
667}
668
669void Browser::CloseTab() {
670 UserMetrics::RecordAction(L"CloseTab_Accelerator", profile_);
671 tabstrip_model_.CloseTabContentsAt(tabstrip_model_.selected_index());
672}
673
[email protected]fbd77592008-11-12 20:50:27674void Browser::SelectNextTab() {
675 UserMetrics::RecordAction(L"SelectNextTab", profile_);
676 tabstrip_model_.SelectNextTab();
677}
678
679void Browser::SelectPreviousTab() {
680 UserMetrics::RecordAction(L"SelectPrevTab", profile_);
681 tabstrip_model_.SelectPreviousTab();
682}
683
684void Browser::SelectNumberedTab(int index) {
685 if (index < tab_count()) {
686 UserMetrics::RecordAction(L"SelectNumberedTab", profile_);
687 tabstrip_model_.SelectTabContentsAt(index, true);
688 }
689}
690
691void Browser::SelectLastTab() {
692 UserMetrics::RecordAction(L"SelectLastTab", profile_);
693 tabstrip_model_.SelectLastTab();
694}
695
696void Browser::DuplicateTab() {
697 UserMetrics::RecordAction(L"Duplicate", profile_);
698 DuplicateContentsAt(selected_index());
699}
700
701void Browser::RestoreTab() {
702 UserMetrics::RecordAction(L"RestoreTab", profile_);
703 TabRestoreService* service = profile_->GetTabRestoreService();
704 if (!service)
705 return;
706
[email protected]d8375fd2008-11-25 22:45:39707 service->RestoreMostRecentEntry(this);
[email protected]fbd77592008-11-12 20:50:27708}
709
710void Browser::ConvertPopupToTabbedBrowser() {
711 UserMetrics::RecordAction(L"ShowAsTab", profile_);
712
[email protected]299dabd2008-11-19 02:27:16713 if (type() != TYPE_NORMAL) {
[email protected]fbd77592008-11-12 20:50:27714 NOTREACHED();
715 return;
716 }
717
718 int tab_strip_index = tabstrip_model_.selected_index();
719 TabContents* contents = tabstrip_model_.DetachTabContentsAt(tab_strip_index);
[email protected]15952e462008-11-14 00:29:05720 Browser* browser = Browser::Create(profile_);
721 browser->tabstrip_model()->AppendTabContents(contents, true);
722 browser->window()->Show();
[email protected]fbd77592008-11-12 20:50:27723}
724
725void Browser::Exit() {
726 UserMetrics::RecordAction(L"Exit", profile_);
727 BrowserList::CloseAllBrowsers(true);
728}
729
[email protected]36b6dcb2008-11-12 01:19:57730void Browser::BookmarkCurrentPage() {
[email protected]fbd77592008-11-12 20:50:27731 UserMetrics::RecordAction(L"Star", profile_);
732
[email protected]36b6dcb2008-11-12 01:19:57733 TabContents* tab = GetSelectedTabContents();
[email protected]c7c42332008-11-15 01:10:54734 if (!tab->AsWebContents())
[email protected]36b6dcb2008-11-12 01:19:57735 return;
736
737 WebContents* rvh = tab->AsWebContents();
738 BookmarkModel* model = tab->profile()->GetBookmarkModel();
739 if (!model || !model->IsLoaded())
740 return; // Ignore requests until bookmarks are loaded.
741
742 NavigationEntry* entry = rvh->controller()->GetActiveEntry();
743 if (!entry)
744 return; // Can't star if there is no URL.
745 const GURL& url = entry->display_url();
746 if (url.is_empty() || !url.is_valid())
747 return;
748
749 if (window_->GetStarButton()) {
750 if (!window_->GetStarButton()->is_bubble_showing()) {
751 const bool newly_bookmarked = !model->IsBookmarked(url);
752 if (newly_bookmarked) {
753 model->SetURLStarred(url, entry->title(), true);
754 if (!model->IsBookmarked(url)) {
755 // Starring failed. This shouldn't happen.
756 NOTREACHED();
757 return;
758 }
759 }
760 window_->GetStarButton()->ShowStarBubble(url, newly_bookmarked);
761 }
762 } else if (model->IsBookmarked(url)) {
763 // If we can't find the star button and the user wanted to unstar it,
764 // go ahead and unstar it without showing the bubble.
765 model->SetURLStarred(url, std::wstring(), false);
766 }
767}
768
[email protected]fbd77592008-11-12 20:50:27769void Browser::ViewSource() {
770 UserMetrics::RecordAction(L"ViewSource", profile_);
[email protected]36b6dcb2008-11-12 01:19:57771
[email protected]36b6dcb2008-11-12 01:19:57772 TabContents* current_tab = GetSelectedTabContents();
[email protected]fbd77592008-11-12 20:50:27773 NavigationEntry* entry = current_tab->controller()->GetLastCommittedEntry();
774 if (entry) {
775 GURL url("view-source:" + entry->url().spec());
776 AddTabWithURL(url, GURL(), PageTransition::LINK, true, NULL);
[email protected]36b6dcb2008-11-12 01:19:57777 }
778}
initial.commit09911bf2008-07-26 23:55:29779
[email protected]fbd77592008-11-12 20:50:27780void Browser::ClosePopups() {
781 UserMetrics::RecordAction(L"CloseAllSuppressedPopups", profile_);
782 GetSelectedTabContents()->CloseAllSuppressedPopups();
783}
initial.commit09911bf2008-07-26 23:55:29784
[email protected]fbd77592008-11-12 20:50:27785void Browser::Print() {
786 UserMetrics::RecordAction(L"PrintPreview", profile_);
787 GetSelectedTabContents()->AsWebContents()->PrintPreview();
788}
789
790void Browser::SavePage() {
791 UserMetrics::RecordAction(L"SavePage", profile_);
792 GetSelectedTabContents()->AsWebContents()->OnSavePage();
793}
794
795void Browser::ToggleEncodingAutoDetect() {
796 UserMetrics::RecordAction(L"AutoDetectChange", profile_);
797 encoding_auto_detect_.SetValue(!encoding_auto_detect_.GetValue());
798 // Reload the page so we can try to auto-detect the charset.
799 Reload();
800}
801
802void Browser::OverrideEncoding(int encoding_id) {
803 UserMetrics::RecordAction(L"OverrideEncoding", profile_);
804 const std::wstring selected_encoding =
805 CharacterEncoding::GetCanonicalEncodingNameByCommandId(encoding_id);
806 TabContents* current_tab = GetSelectedTabContents();
[email protected]c7c42332008-11-15 01:10:54807 if (!selected_encoding.empty() && current_tab->AsWebContents())
[email protected]fbd77592008-11-12 20:50:27808 current_tab->AsWebContents()->override_encoding(selected_encoding);
809 // Update the list of recently selected encodings.
810 std::wstring new_selected_encoding_list;
811 if (CharacterEncoding::UpdateRecentlySelectdEncoding(
812 profile_->GetPrefs()->GetString(prefs::kRecentlySelectedEncoding),
813 encoding_id,
814 &new_selected_encoding_list)) {
815 profile_->GetPrefs()->SetString(prefs::kRecentlySelectedEncoding,
816 new_selected_encoding_list);
817 }
[email protected]36b6dcb2008-11-12 01:19:57818}
819
[email protected]84214982008-12-10 18:49:10820// TODO(devint): http://b/issue?id=1117225 Cut, Copy, and Paste are always
821// enabled in the page menu regardless of whether the command will do
822// anything. When someone selects the menu item, we just act as if they hit
823// the keyboard shortcut for the command by sending the associated key press
824// to windows. The real fix to this bug is to disable the commands when they
825// won't do anything. We'll need something like an overall clipboard command
826// manager to do that.
827
828void Browser::Cut() {
829 UserMetrics::RecordAction(L"Cut", profile_);
830 ui_controls::SendKeyPress(L'X', true, false, false);
[email protected]36b6dcb2008-11-12 01:19:57831}
832
[email protected]84214982008-12-10 18:49:10833void Browser::Copy() {
834 UserMetrics::RecordAction(L"Copy", profile_);
835 ui_controls::SendKeyPress(L'C', true, false, false);
[email protected]36b6dcb2008-11-12 01:19:57836}
837
[email protected]84214982008-12-10 18:49:10838void Browser::CopyCurrentPageURL() {
839 UserMetrics::RecordAction(L"CopyURLToClipBoard", profile_);
840 std::string url = GetSelectedTabContents()->GetURL().spec();
841
842 if (!::OpenClipboard(NULL)) {
843 NOTREACHED();
844 return;
845 }
846
847 if (::EmptyClipboard()) {
848 HGLOBAL text = ::GlobalAlloc(GMEM_MOVEABLE, url.size() + 1);
849 LPSTR ptr = static_cast<LPSTR>(::GlobalLock(text));
850 memcpy(ptr, url.c_str(), url.size());
851 ptr[url.size()] = '\0';
852 ::GlobalUnlock(text);
853
854 ::SetClipboardData(CF_TEXT, text);
855 }
856
857 if (!::CloseClipboard()) {
858 NOTREACHED();
859 }
[email protected]36b6dcb2008-11-12 01:19:57860}
861
[email protected]84214982008-12-10 18:49:10862void Browser::Paste() {
863 UserMetrics::RecordAction(L"Paste", profile_);
864 ui_controls::SendKeyPress(L'V', true, false, false);
865}
866
867void Browser::Find() {
868 UserMetrics::RecordAction(L"Find", profile_);
869 GetSelectedTabContents()->AsWebContents()->view()->FindInPage(*this, false,
870 false);
871}
872
873void Browser::FindNext() {
874 UserMetrics::RecordAction(L"FindNext", profile_);
875 AdvanceFindSelection(true);
876}
877
878void Browser::FindPrevious() {
879 UserMetrics::RecordAction(L"FindPrevious", profile_);
880 AdvanceFindSelection(false);
881}
882
883void Browser::ZoomIn() {
884 UserMetrics::RecordAction(L"ZoomPlus", profile_);
885 GetSelectedTabContents()->AsWebContents()->render_view_host()->Zoom(
886 PageZoom::LARGER);
887}
888
889void Browser::ZoomReset() {
890 UserMetrics::RecordAction(L"ZoomNormal", profile_);
891 GetSelectedTabContents()->AsWebContents()->render_view_host()->Zoom(
892 PageZoom::STANDARD);
893}
894
895void Browser::ZoomOut() {
896 UserMetrics::RecordAction(L"ZoomMinus", profile_);
897 GetSelectedTabContents()->AsWebContents()->render_view_host()->Zoom(
898 PageZoom::SMALLER);
899}
900
901void Browser::FocusToolbar() {
902 UserMetrics::RecordAction(L"FocusToolbar", profile_);
903 window_->FocusToolbar();
904}
905
906void Browser::FocusLocationBar() {
907 UserMetrics::RecordAction(L"FocusLocation", profile_);
908 LocationBarView* lbv = GetLocationBarView();
909 if (lbv) {
910 AutocompleteEditView* aev = lbv->location_entry();
911 aev->SetFocus();
912 aev->SelectAll(true);
913 }
914}
915
916void Browser::FocusSearch() {
917 // TODO(beng): replace this with FocusLocationBar
918 UserMetrics::RecordAction(L"FocusSearch", profile_);
919 LocationBarView* lbv = GetLocationBarView();
920 if (lbv) {
921 AutocompleteEditView* aev = lbv->location_entry();
922 aev->SetUserText(L"?");
923 aev->SetFocus();
924 }
925}
926
927void Browser::OpenFile() {
928 UserMetrics::RecordAction(L"OpenFile", profile_);
929 if (!select_file_dialog_.get())
930 select_file_dialog_ = SelectFileDialog::Create(this);
931
932 // TODO(beng): figure out how to juggle this.
933 HWND parent_hwnd = reinterpret_cast<HWND>(window_->GetNativeHandle());
934 select_file_dialog_->SelectFile(SelectFileDialog::SELECT_OPEN_FILE,
935 std::wstring(), std::wstring(),
936 std::wstring(), std::wstring(),
937 parent_hwnd, NULL);
938}
939
940void Browser::OpenCreateShortcutsDialog() {
941 UserMetrics::RecordAction(L"CreateShortcut", profile_);
942 GetSelectedTabContents()->AsWebContents()->CreateShortcut();
[email protected]36b6dcb2008-11-12 01:19:57943}
944
[email protected]fbd77592008-11-12 20:50:27945void Browser::OpenDebuggerWindow() {
946#ifndef CHROME_DEBUGGER_DISABLED
947 UserMetrics::RecordAction(L"Debugger", profile_);
948 TabContents* current_tab = GetSelectedTabContents();
[email protected]fbd77592008-11-12 20:50:27949 if (current_tab->AsWebContents()) {
950 // Only one debugger instance can exist at a time right now.
951 // TODO(erikkay): need an alert, dialog, something
952 // or better yet, fix the one instance limitation
953 if (!DebuggerWindow::DoesDebuggerExist()) {
954 debugger_window_ = new DebuggerWindow();
955 }
956 debugger_window_->Show(current_tab);
[email protected]36b6dcb2008-11-12 01:19:57957 }
[email protected]fbd77592008-11-12 20:50:27958#endif
959}
[email protected]36b6dcb2008-11-12 01:19:57960
[email protected]fbd77592008-11-12 20:50:27961void Browser::OpenJavaScriptConsole() {
962 UserMetrics::RecordAction(L"ShowJSConsole", profile_);
963 GetSelectedTabContents()->AsWebContents()->render_view_host()->
964 ShowJavaScriptConsole();
965}
966
[email protected]84214982008-12-10 18:49:10967void Browser::OpenTaskManager() {
968 UserMetrics::RecordAction(L"TaskManager", profile_);
969 TaskManager::Open();
970}
971
972void Browser::OpenSelectProfileDialog() {
973 UserMetrics::RecordAction(L"SelectProfile", profile_);
974 SelectProfileDialog::RunDialog();
975}
976
977void Browser::OpenNewProfileDialog() {
978 UserMetrics::RecordAction(L"CreateProfile", profile_);
979 NewProfileDialog::RunDialog();
980}
981
982void Browser::OpenBugReportDialog() {
983 UserMetrics::RecordAction(L"ReportBug", profile_);
984 window_->ShowReportBugDialog();
985}
986
987void Browser::ToggleBookmarkBar() {
988 UserMetrics::RecordAction(L"ShowBookmarksBar", profile_);
989 window_->ToggleBookmarkBar();
990}
991
992void Browser::ShowHistoryTab() {
993 UserMetrics::RecordAction(L"ShowHistory", profile_);
994 ShowNativeUITab(HistoryTabUI::GetURL());
995}
996
997void Browser::OpenBookmarkManager() {
998 UserMetrics::RecordAction(L"ShowBookmarkManager", profile_);
999 window_->ShowBookmarkManager();
1000}
1001
1002void Browser::ShowDownloadsTab() {
1003 UserMetrics::RecordAction(L"ShowDownloads", profile_);
1004 ShowNativeUITab(DownloadTabUI::GetURL());
1005}
1006
1007void Browser::OpenClearBrowsingDataDialog() {
1008 UserMetrics::RecordAction(L"ClearBrowsingData_ShowDlg", profile_);
1009 window_->ShowClearBrowsingDataDialog();
1010}
1011
1012void Browser::OpenImportSettingsDialog() {
1013 UserMetrics::RecordAction(L"Import_ShowDlg", profile_);
1014 window_->ShowImportDialog();
1015}
1016
1017void Browser::OpenOptionsDialog() {
1018 UserMetrics::RecordAction(L"ShowOptions", profile_);
1019 ShowOptionsWindow(OPTIONS_PAGE_DEFAULT, OPTIONS_GROUP_NONE, profile_);
1020}
1021
1022void Browser::OpenKeywordEditor() {
1023 UserMetrics::RecordAction(L"EditSearchEngines", profile_);
1024 window_->ShowSearchEnginesDialog();
[email protected]fbd77592008-11-12 20:50:271025}
1026
1027void Browser::OpenPasswordManager() {
[email protected]2d46c842008-11-14 19:24:311028 window_->ShowPasswordManager();
[email protected]fbd77592008-11-12 20:50:271029}
1030
1031void Browser::OpenAboutChromeDialog() {
1032 UserMetrics::RecordAction(L"AboutChrome", profile_);
[email protected]2d46c842008-11-14 19:24:311033 window_->ShowAboutChromeDialog();
[email protected]fbd77592008-11-12 20:50:271034}
1035
[email protected]fbd77592008-11-12 20:50:271036void Browser::OpenHelpTab() {
1037 GURL help_url(l10n_util::GetString(IDS_HELP_CONTENT_URL));
1038 AddTabWithURL(help_url, GURL(), PageTransition::AUTO_BOOKMARK, true,
1039 NULL);
1040}
1041
[email protected]36b6dcb2008-11-12 01:19:571042///////////////////////////////////////////////////////////////////////////////
1043
1044// static
1045void Browser::RegisterPrefs(PrefService* prefs) {
1046 prefs->RegisterDictionaryPref(prefs::kBrowserWindowPlacement);
1047 prefs->RegisterIntegerPref(prefs::kOptionsWindowLastTabIndex, 0);
1048}
1049
1050// static
1051void Browser::RegisterUserPrefs(PrefService* prefs) {
1052 prefs->RegisterStringPref(prefs::kHomePage, L"chrome-internal:");
1053 prefs->RegisterBooleanPref(prefs::kHomePageIsNewTabPage, true);
1054 prefs->RegisterIntegerPref(prefs::kCookieBehavior,
1055 net::CookiePolicy::ALLOW_ALL_COOKIES);
1056 prefs->RegisterBooleanPref(prefs::kShowHomeButton, false);
1057 prefs->RegisterStringPref(prefs::kRecentlySelectedEncoding, L"");
1058 // TODO(peterson): bug #3870 move this to the AutofillManager once it is
1059 // checked-in.
1060 prefs->RegisterBooleanPref(prefs::kFormAutofillEnabled, true);
1061 prefs->RegisterBooleanPref(prefs::kDeleteBrowsingHistory, true);
1062 prefs->RegisterBooleanPref(prefs::kDeleteDownloadHistory, true);
1063 prefs->RegisterBooleanPref(prefs::kDeleteCache, true);
1064 prefs->RegisterBooleanPref(prefs::kDeleteCookies, true);
1065 prefs->RegisterBooleanPref(prefs::kDeletePasswords, false);
1066 prefs->RegisterBooleanPref(prefs::kDeleteFormData, true);
1067 prefs->RegisterIntegerPref(prefs::kDeleteTimePeriod, 0);
1068}
1069
1070// static
1071Browser* Browser::GetBrowserForController(
1072 const NavigationController* controller, int* index_result) {
1073 BrowserList::const_iterator it;
1074 for (it = BrowserList::begin(); it != BrowserList::end(); ++it) {
1075 int index = (*it)->tabstrip_model_.GetIndexOfController(controller);
1076 if (index != TabStripModel::kNoTab) {
1077 if (index_result)
1078 *index_result = index;
1079 return *it;
1080 }
1081 }
1082
1083 return NULL;
1084}
1085
1086///////////////////////////////////////////////////////////////////////////////
1087// Browser, CommandHandler implementation:
1088
1089void Browser::ExecuteCommand(int id) {
[email protected]c7c42332008-11-15 01:10:541090 DCHECK(IsCommandEnabled(id)) << "Invalid or disabled command";
[email protected]36b6dcb2008-11-12 01:19:571091
[email protected]fbd77592008-11-12 20:50:271092 // The order of commands in this switch statement must match the function
1093 // declaration order in browser.h!
[email protected]36b6dcb2008-11-12 01:19:571094 switch (id) {
[email protected]84214982008-12-10 18:49:101095 // Navigation commands
[email protected]cb525c82008-12-08 23:04:541096 case IDC_BACK: GoBack(); break;
1097 case IDC_FORWARD: GoForward(); break;
1098 case IDC_RELOAD: Reload(); break;
[email protected]cb525c82008-12-08 23:04:541099 case IDC_HOME: Home(); break;
[email protected]cb525c82008-12-08 23:04:541100 case IDC_OPEN_CURRENT_URL: OpenCurrentURL(); break;
[email protected]84214982008-12-10 18:49:101101 case IDC_GO: Go(); break;
1102 case IDC_STOP: Stop(); break;
[email protected]36b6dcb2008-11-12 01:19:571103
[email protected]84214982008-12-10 18:49:101104 // Window management commands
[email protected]cb525c82008-12-08 23:04:541105 case IDC_NEW_WINDOW: NewWindow(); break;
1106 case IDC_NEW_INCOGNITO_WINDOW: NewIncognitoWindow(); break;
[email protected]84214982008-12-10 18:49:101107 case IDC_NEW_WINDOW_PROFILE_0:
1108 case IDC_NEW_WINDOW_PROFILE_1:
1109 case IDC_NEW_WINDOW_PROFILE_2:
1110 case IDC_NEW_WINDOW_PROFILE_3:
1111 case IDC_NEW_WINDOW_PROFILE_4:
1112 case IDC_NEW_WINDOW_PROFILE_5:
1113 case IDC_NEW_WINDOW_PROFILE_6:
1114 case IDC_NEW_WINDOW_PROFILE_7:
1115 case IDC_NEW_WINDOW_PROFILE_8:
1116 NewProfileWindowByIndex(id - IDC_NEW_WINDOW_PROFILE_0); break;
[email protected]cb525c82008-12-08 23:04:541117 case IDC_CLOSE_WINDOW: CloseWindow(); break;
[email protected]84214982008-12-10 18:49:101118 case IDC_NEW_TAB: NewTab(); break;
1119 case IDC_CLOSE_TAB: CloseTab(); break;
[email protected]cb525c82008-12-08 23:04:541120 case IDC_SELECT_NEXT_TAB: SelectNextTab(); break;
1121 case IDC_SELECT_PREVIOUS_TAB: SelectPreviousTab(); break;
[email protected]36b6dcb2008-11-12 01:19:571122 case IDC_SELECT_TAB_0:
1123 case IDC_SELECT_TAB_1:
1124 case IDC_SELECT_TAB_2:
1125 case IDC_SELECT_TAB_3:
1126 case IDC_SELECT_TAB_4:
1127 case IDC_SELECT_TAB_5:
1128 case IDC_SELECT_TAB_6:
[email protected]cb525c82008-12-08 23:04:541129 case IDC_SELECT_TAB_7: SelectNumberedTab(id - IDC_SELECT_TAB_0);
1130 break;
1131 case IDC_SELECT_LAST_TAB: SelectLastTab(); break;
1132 case IDC_DUPLICATE_TAB: DuplicateTab(); break;
1133 case IDC_RESTORE_TAB: RestoreTab(); break;
1134 case IDC_SHOW_AS_TAB: ConvertPopupToTabbedBrowser(); break;
1135 case IDC_EXIT: Exit(); break;
[email protected]36b6dcb2008-11-12 01:19:571136
[email protected]84214982008-12-10 18:49:101137 // Page-related commands
[email protected]cb525c82008-12-08 23:04:541138 case IDC_STAR: BookmarkCurrentPage(); break;
1139 case IDC_VIEW_SOURCE: ViewSource(); break;
1140 case IDC_CLOSE_POPUPS: ClosePopups(); break;
1141 case IDC_PRINT: Print(); break;
1142 case IDC_SAVE_PAGE: SavePage(); break;
1143 case IDC_ENCODING_AUTO_DETECT: ToggleEncodingAutoDetect(); break;
[email protected]36b6dcb2008-11-12 01:19:571144 case IDC_ENCODING_UTF8:
1145 case IDC_ENCODING_UTF16LE:
1146 case IDC_ENCODING_ISO88591:
1147 case IDC_ENCODING_WINDOWS1252:
1148 case IDC_ENCODING_GB2312:
1149 case IDC_ENCODING_GB18030:
1150 case IDC_ENCODING_BIG5HKSCS:
1151 case IDC_ENCODING_BIG5:
1152 case IDC_ENCODING_KOREAN:
1153 case IDC_ENCODING_SHIFTJIS:
1154 case IDC_ENCODING_ISO2022JP:
1155 case IDC_ENCODING_EUCJP:
1156 case IDC_ENCODING_THAI:
1157 case IDC_ENCODING_ISO885915:
1158 case IDC_ENCODING_MACINTOSH:
1159 case IDC_ENCODING_ISO88592:
1160 case IDC_ENCODING_WINDOWS1250:
1161 case IDC_ENCODING_ISO88595:
1162 case IDC_ENCODING_WINDOWS1251:
1163 case IDC_ENCODING_KOI8R:
1164 case IDC_ENCODING_KOI8U:
1165 case IDC_ENCODING_ISO88597:
1166 case IDC_ENCODING_WINDOWS1253:
1167 case IDC_ENCODING_ISO88594:
1168 case IDC_ENCODING_ISO885913:
1169 case IDC_ENCODING_WINDOWS1257:
1170 case IDC_ENCODING_ISO88593:
1171 case IDC_ENCODING_ISO885910:
1172 case IDC_ENCODING_ISO885914:
1173 case IDC_ENCODING_ISO885916:
[email protected]36b6dcb2008-11-12 01:19:571174 case IDC_ENCODING_WINDOWS1254:
1175 case IDC_ENCODING_ISO88596:
1176 case IDC_ENCODING_WINDOWS1256:
1177 case IDC_ENCODING_ISO88598:
1178 case IDC_ENCODING_WINDOWS1255:
[email protected]cb525c82008-12-08 23:04:541179 case IDC_ENCODING_WINDOWS1258: OverrideEncoding(id); break;
[email protected]36b6dcb2008-11-12 01:19:571180
[email protected]84214982008-12-10 18:49:101181 // Clipboard commands
1182 case IDC_CUT: Cut(); break;
1183 case IDC_COPY: Copy(); break;
1184 case IDC_COPY_URL: CopyCurrentPageURL(); break;
1185 case IDC_PASTE: Paste(); break;
1186
1187 // Find-in-page
1188 case IDC_FIND: Find(); break;
1189 case IDC_FIND_NEXT: FindNext(); break;
1190 case IDC_FIND_PREVIOUS: FindPrevious(); break;
1191
1192 // Zoom
1193 case IDC_ZOOM_PLUS: ZoomIn(); break;
1194 case IDC_ZOOM_NORMAL: ZoomReset(); break;
1195 case IDC_ZOOM_MINUS: ZoomOut(); break;
1196
1197 // Focus various bits of UI
1198 case IDC_FOCUS_TOOLBAR: FocusToolbar(); break;
1199 case IDC_FOCUS_LOCATION: FocusLocationBar(); break;
1200 case IDC_FOCUS_SEARCH: FocusSearch(); break;
1201
1202 // Show various bits of UI
1203 case IDC_OPEN_FILE: OpenFile(); break;
1204 case IDC_CREATE_SHORTCUTS: OpenCreateShortcutsDialog(); break;
[email protected]cb525c82008-12-08 23:04:541205 case IDC_DEBUGGER: OpenDebuggerWindow(); break;
1206 case IDC_JS_CONSOLE: OpenJavaScriptConsole(); break;
[email protected]cb525c82008-12-08 23:04:541207 case IDC_TASK_MANAGER: OpenTaskManager(); break;
[email protected]cb525c82008-12-08 23:04:541208 case IDC_SELECT_PROFILE: OpenSelectProfileDialog(); break;
1209 case IDC_NEW_PROFILE: OpenNewProfileDialog(); break;
[email protected]84214982008-12-10 18:49:101210 case IDC_REPORT_BUG: OpenBugReportDialog(); break;
1211 case IDC_SHOW_BOOKMARK_BAR: ToggleBookmarkBar(); break;
1212 case IDC_SHOW_HISTORY: ShowHistoryTab(); break;
1213 case IDC_SHOW_BOOKMARK_MANAGER: OpenBookmarkManager(); break;
1214 case IDC_SHOW_DOWNLOADS: ShowDownloadsTab(); break;
1215 case IDC_CLEAR_BROWSING_DATA: OpenClearBrowsingDataDialog(); break;
1216 case IDC_IMPORT_SETTINGS: OpenImportSettingsDialog(); break;
1217 case IDC_OPTIONS: OpenOptionsDialog(); break;
1218 case IDC_EDIT_SEARCH_ENGINES: OpenKeywordEditor(); break;
1219 case IDC_VIEW_PASSWORDS: OpenPasswordManager(); break;
1220 case IDC_ABOUT: OpenAboutChromeDialog(); break;
1221 case IDC_HELP_PAGE: OpenHelpTab(); break;
[email protected]36b6dcb2008-11-12 01:19:571222
1223 default:
[email protected]84214982008-12-10 18:49:101224 LOG(WARNING) << "Received Unimplemented Command: " << id;
[email protected]fbd77592008-11-12 20:50:271225 break;
[email protected]36b6dcb2008-11-12 01:19:571226 }
1227}
1228
1229///////////////////////////////////////////////////////////////////////////////
1230// Browser, TabStripModelDelegate implementation:
1231
[email protected]15952e462008-11-14 00:29:051232GURL Browser::GetBlankTabURL() const {
1233 return NewTabUIURL();
1234}
1235
[email protected]36b6dcb2008-11-12 01:19:571236void Browser::CreateNewStripWithContents(TabContents* detached_contents,
[email protected]5e495462008-11-20 23:07:411237 const gfx::Rect& window_bounds,
1238 const DockInfo& dock_info) {
[email protected]299dabd2008-11-19 02:27:161239 DCHECK(type_ == TYPE_NORMAL);
[email protected]adf650f2008-12-09 16:10:061240
[email protected]5e495462008-11-20 23:07:411241 gfx::Rect new_window_bounds = window_bounds;
1242 bool maximize = false;
1243 if (dock_info.GetNewWindowBounds(&new_window_bounds, &maximize))
1244 dock_info.AdjustOtherWindowBounds();
1245
[email protected]36b6dcb2008-11-12 01:19:571246 // Create an empty new browser window the same size as the old one.
[email protected]299dabd2008-11-19 02:27:161247 Browser* browser = new Browser(TYPE_NORMAL, profile_);
[email protected]5e495462008-11-20 23:07:411248 browser->set_override_bounds(new_window_bounds);
1249 browser->set_override_maximized(maximize);
[email protected]15952e462008-11-14 00:29:051250 browser->CreateBrowserWindow();
1251 browser->tabstrip_model()->AppendTabContents(detached_contents, true);
1252 browser->window()->Show();
[email protected]36b6dcb2008-11-12 01:19:571253
1254 // When we detach a tab we need to make sure any associated Find window moves
[email protected]2d46c842008-11-14 19:24:311255 // along with it to its new home (basically we just make new_window the
1256 // parent of the Find window).
[email protected]36b6dcb2008-11-12 01:19:571257 // TODO(brettw) this could probably be improved, see
1258 // WebContentsView::ReparentFindWindow for more.
1259 if (detached_contents->AsWebContents())
[email protected]15952e462008-11-14 00:29:051260 detached_contents->AsWebContents()->view()->ReparentFindWindow(browser);
[email protected]36b6dcb2008-11-12 01:19:571261}
1262
1263int Browser::GetDragActions() const {
1264 int result = 0;
[email protected]299dabd2008-11-19 02:27:161265 if (BrowserList::GetBrowserCountForType(profile_, TYPE_NORMAL) > 1 ||
[email protected]36b6dcb2008-11-12 01:19:571266 tab_count() > 1)
1267 result |= TAB_TEAROFF_ACTION;
1268 if (tab_count() > 1)
1269 result |= TAB_MOVE_ACTION;
1270 return result;
1271}
1272
1273TabContents* Browser::CreateTabContentsForURL(
1274 const GURL& url, const GURL& referrer, Profile* profile,
1275 PageTransition::Type transition, bool defer_load,
1276 SiteInstance* instance) const {
1277 // Create an appropriate tab contents.
1278 GURL real_url = url;
1279 TabContentsType type = TabContents::TypeForURL(&real_url);
1280 DCHECK(type != TAB_CONTENTS_UNKNOWN_TYPE);
1281
[email protected]ec322ff2008-11-19 22:53:301282 TabContents* contents = TabContents::CreateWithType(type, profile, instance);
[email protected]36b6dcb2008-11-12 01:19:571283 contents->SetupController(profile);
1284
1285 if (!defer_load) {
1286 // Load the initial URL before adding the new tab contents to the tab strip
1287 // so that the tab contents has navigation state.
1288 contents->controller()->LoadURL(url, referrer, transition);
1289 }
1290
1291 return contents;
1292}
1293
1294bool Browser::CanDuplicateContentsAt(int index) {
1295 TabContents* contents = GetTabContentsAt(index);
1296 DCHECK(contents);
1297
1298 NavigationController* nc = contents->controller();
1299 return nc ? (nc->active_contents() && nc->GetLastCommittedEntry()) : false;
1300}
1301
1302void Browser::DuplicateContentsAt(int index) {
1303 TabContents* contents = GetTabContentsAt(index);
1304 TabContents* new_contents = NULL;
1305 DCHECK(contents);
1306
[email protected]299dabd2008-11-19 02:27:161307 if (type_ == TYPE_NORMAL) {
[email protected]36b6dcb2008-11-12 01:19:571308 // If this is a tabbed browser, just create a duplicate tab inside the same
1309 // window next to the tab being duplicated.
[email protected]ec322ff2008-11-19 22:53:301310 new_contents = contents->controller()->Clone()->active_contents();
[email protected]36b6dcb2008-11-12 01:19:571311 // If you duplicate a tab that is not selected, we need to make sure to
1312 // select the tab being duplicated so that DetermineInsertionIndex returns
1313 // the right index (if tab 5 is selected and we right-click tab 1 we want
1314 // the new tab to appear in index position 2, not 6).
1315 if (tabstrip_model_.selected_index() != index)
1316 tabstrip_model_.SelectTabContentsAt(index, true);
1317 tabstrip_model_.AddTabContents(new_contents, index + 1,
1318 PageTransition::LINK, true);
1319 } else {
[email protected]15952e462008-11-14 00:29:051320 Browser* browser = NULL;
[email protected]299dabd2008-11-19 02:27:161321 if (type_ == TYPE_APP) {
[email protected]15952e462008-11-14 00:29:051322 browser = Browser::CreateForApp(app_name_, profile_);
[email protected]299dabd2008-11-19 02:27:161323 } else if (type_ == TYPE_POPUP) {
[email protected]15952e462008-11-14 00:29:051324 browser = Browser::CreateForPopup(profile_);
1325 }
[email protected]36b6dcb2008-11-12 01:19:571326
1327 // We need to show the browser now. Otherwise ContainerWin assumes the
1328 // TabContents is invisible and won't size it.
[email protected]15952e462008-11-14 00:29:051329 browser->window()->Show();
[email protected]36b6dcb2008-11-12 01:19:571330
1331 // The page transition below is only for the purpose of inserting the tab.
[email protected]15952e462008-11-14 00:29:051332 new_contents = browser->AddTabWithNavigationController(
[email protected]ec322ff2008-11-19 22:53:301333 contents->controller()->Clone(),
[email protected]36b6dcb2008-11-12 01:19:571334 PageTransition::LINK);
[email protected]36b6dcb2008-11-12 01:19:571335 }
1336
1337 if (profile_->HasSessionService()) {
1338 SessionService* session_service = profile_->GetSessionService();
1339 if (session_service)
1340 session_service->TabRestored(new_contents->controller());
1341 }
1342}
1343
[email protected]36b6dcb2008-11-12 01:19:571344void Browser::CloseFrameAfterDragSession() {
1345 // This is scheduled to run after we return to the message loop because
1346 // otherwise the frame will think the drag session is still active and ignore
1347 // the request.
1348 MessageLoop::current()->PostTask(FROM_HERE,
1349 method_factory_.NewRunnableMethod(&Browser::CloseFrame));
initial.commit09911bf2008-07-26 23:55:291350}
1351
[email protected]2d46c842008-11-14 19:24:311352///////////////////////////////////////////////////////////////////////////////
[email protected]36b6dcb2008-11-12 01:19:571353// Browser, TabStripModelObserver implementation:
1354
1355void Browser::TabInsertedAt(TabContents* contents,
1356 int index,
1357 bool foreground) {
1358 contents->set_delegate(this);
1359 contents->controller()->SetWindowID(session_id());
1360
1361 SyncHistoryWithTabs(tabstrip_model_.GetIndexOfTabContents(contents));
1362
1363 // When a tab is dropped into a tab strip we need to make sure that the
1364 // associated Find window is moved along with it. We therefore change the
1365 // parent of the Find window (if the parent is already correctly set this
1366 // does nothing).
1367 // TODO(brettw) this could probably be improved, see
1368 // WebContentsView::ReparentFindWindow for more.
1369 if (contents->AsWebContents())
1370 contents->AsWebContents()->view()->ReparentFindWindow(this);
1371
1372 // If the tab crashes in the beforeunload or unload handler, it won't be
1373 // able to ack. But we know we can close it.
1374 NotificationService::current()->
1375 AddObserver(this, NOTIFY_WEB_CONTENTS_DISCONNECTED,
1376 Source<TabContents>(contents));
1377}
1378
1379void Browser::TabClosingAt(TabContents* contents, int index) {
1380 NavigationController* controller = contents->controller();
1381 DCHECK(controller);
1382 NotificationService::current()->
1383 Notify(NOTIFY_TAB_CLOSING,
1384 Source<NavigationController>(controller),
1385 NotificationService::NoDetails());
1386
1387 // Sever the TabContents' connection back to us.
1388 contents->set_delegate(NULL);
1389}
1390
1391void Browser::TabDetachedAt(TabContents* contents, int index) {
1392 contents->set_delegate(NULL);
1393 if (!tabstrip_model_.closing_all())
1394 SyncHistoryWithTabs(0);
1395
1396 RemoveScheduledUpdatesFor(contents);
1397
1398 NotificationService::current()->
[email protected]adf650f2008-12-09 16:10:061399 RemoveObserver(this, NOTIFY_WEB_CONTENTS_DISCONNECTED,
[email protected]36b6dcb2008-11-12 01:19:571400 Source<TabContents>(contents));
1401}
1402
1403void Browser::TabSelectedAt(TabContents* old_contents,
1404 TabContents* new_contents,
1405 int index,
1406 bool user_gesture) {
1407 DCHECK(old_contents != new_contents);
1408
1409 // If we have any update pending, do it now.
1410 if (!chrome_updater_factory_.empty() && old_contents)
1411 ProcessPendingUIUpdates();
1412
1413 LocationBarView* location_bar = GetLocationBarView();
1414 if (old_contents) {
1415 // Save what the user's currently typing, so it can be restored when we
1416 // switch back to this tab.
1417 if (location_bar)
1418 location_bar->location_entry()->SaveStateToTab(old_contents);
1419 }
1420
1421 // Propagate the profile to the location bar.
1422 UpdateToolbar(true);
1423
1424 // Force the go/stop button to change.
[email protected]e673f6c2008-12-09 21:24:111425 GetGoButton()->ChangeMode(
1426 (new_contents->AsWebContents() && new_contents->is_loading()) ?
1427 GoButton::MODE_STOP : GoButton::MODE_GO);
[email protected]36b6dcb2008-11-12 01:19:571428
[email protected]84214982008-12-10 18:49:101429 // Update commands to reflect current state.
1430 UpdateCommandsForTabState();
[email protected]36b6dcb2008-11-12 01:19:571431
1432 // Reset the status bubble.
1433 GetStatusBubble()->Hide();
1434
1435 // Show the loading state (if any).
1436 GetStatusBubble()->SetStatus(GetSelectedTabContents()->GetStatusText());
1437
1438 // Update sessions. Don't force creation of sessions. If sessions doesn't
1439 // exist, the change will be picked up by sessions when created.
1440 if (profile_->HasSessionService()) {
1441 SessionService* session_service = profile_->GetSessionService();
1442 if (session_service && !tabstrip_model_.closing_all()) {
[email protected]2d46c842008-11-14 19:24:311443 session_service->SetSelectedTabInWindow(
1444 session_id(), tabstrip_model_.selected_index());
[email protected]36b6dcb2008-11-12 01:19:571445 }
1446 }
1447}
1448
1449void Browser::TabMoved(TabContents* contents,
1450 int from_index,
1451 int to_index) {
1452 DCHECK(from_index >= 0 && to_index >= 0);
1453 // Notify the history service.
1454 SyncHistoryWithTabs(std::min(from_index, to_index));
1455}
1456
1457void Browser::TabStripEmpty() {
1458 // Close the frame after we return to the message loop (not immediately,
1459 // otherwise it will destroy this object before the stack has a chance to
1460 // cleanly unwind.)
1461 // Note: This will be called several times if TabStripEmpty is called several
1462 // times. This is because it does not close the window if tabs are
1463 // still present.
1464 // NOTE: If you change to be immediate (no invokeLater) then you'll need to
1465 // update BrowserList::CloseAllBrowsers.
1466 MessageLoop::current()->PostTask(FROM_HERE,
1467 method_factory_.NewRunnableMethod(&Browser::CloseFrame));
1468}
1469
1470///////////////////////////////////////////////////////////////////////////////
1471// Browser, TabContentsDelegate implementation:
initial.commit09911bf2008-07-26 23:55:291472
1473void Browser::OpenURLFromTab(TabContents* source,
[email protected]c0588052008-10-27 23:01:501474 const GURL& url, const GURL& referrer,
initial.commit09911bf2008-07-26 23:55:291475 WindowOpenDisposition disposition,
[email protected]e38f40152008-09-12 23:08:301476 PageTransition::Type transition) {
initial.commit09911bf2008-07-26 23:55:291477 // No code for these yet
1478 DCHECK((disposition != NEW_POPUP) && (disposition != SAVE_TO_DISK));
1479
1480 TabContents* current_tab = source ? source : GetSelectedTabContents();
1481 bool source_tab_was_frontmost = (current_tab == GetSelectedTabContents());
1482 TabContents* new_contents = NULL;
1483
1484 // If the URL is part of the same web site, then load it in the same
1485 // SiteInstance (and thus the same process). This is an optimization to
1486 // reduce process overhead; it is not necessary for compatibility. (That is,
1487 // the new tab will not have script connections to the previous tab, so it
1488 // does not need to be part of the same SiteInstance or BrowsingInstance.)
1489 // Default to loading in a new SiteInstance and BrowsingInstance.
1490 // TODO(creis): should this apply to applications?
1491 SiteInstance* instance = NULL;
1492 // Don't use this logic when "--process-per-tab" is specified.
1493 if (!CommandLine().HasSwitch(switches::kProcessPerTab)) {
1494 if (current_tab) {
1495 const WebContents* const web_contents = current_tab->AsWebContents();
1496 if (web_contents) {
1497 const GURL& current_url = web_contents->GetURL();
1498 if (SiteInstance::IsSameWebSite(current_url, url))
[email protected]e9ba4472008-09-14 15:42:431499 instance = web_contents->GetSiteInstance();
initial.commit09911bf2008-07-26 23:55:291500 }
1501 }
1502 }
1503
1504 // If this is an application we can only have one tab so a new tab always
1505 // goes into a tabbed browser window.
[email protected]299dabd2008-11-19 02:27:161506 if (disposition != NEW_WINDOW && type_ == TYPE_APP) {
initial.commit09911bf2008-07-26 23:55:291507 // If the disposition is OFF_THE_RECORD we don't want to create a new
1508 // browser that will itself create another OTR browser. This will result in
1509 // a browser leak (and crash below because no tab is created or selected).
1510 if (disposition == OFF_THE_RECORD) {
1511 OpenURLOffTheRecord(profile_, url);
1512 return;
1513 }
1514
1515 Browser* b = GetOrCreateTabbedBrowser();
1516 DCHECK(b);
1517
1518 // If we have just created a new browser window, make sure we select the
1519 // tab.
1520 if (b->tab_count() == 0 && disposition == NEW_BACKGROUND_TAB)
1521 disposition = NEW_FOREGROUND_TAB;
1522
[email protected]c0588052008-10-27 23:01:501523 b->OpenURL(url, referrer, disposition, transition);
[email protected]15952e462008-11-14 00:29:051524 b->window()->Show();
initial.commit09911bf2008-07-26 23:55:291525 return;
1526 }
1527
1528 if (profile_->IsOffTheRecord() && disposition == OFF_THE_RECORD)
1529 disposition = NEW_FOREGROUND_TAB;
1530
1531 if (disposition == NEW_WINDOW) {
[email protected]15952e462008-11-14 00:29:051532 Browser* browser = Browser::Create(profile_);
1533 new_contents = browser->AddTabWithURL(url, referrer, transition, true,
1534 instance);
1535 browser->window()->Show();
initial.commit09911bf2008-07-26 23:55:291536 } else if ((disposition == CURRENT_TAB) && current_tab) {
1537 if (transition == PageTransition::TYPED ||
1538 transition == PageTransition::AUTO_BOOKMARK ||
1539 transition == PageTransition::GENERATED ||
1540 transition == PageTransition::START_PAGE) {
[email protected]968e56ae2008-08-04 18:39:281541 // Don't forget the openers if this tab is a New Tab page opened at the
1542 // end of the TabStrip (e.g. by pressing Ctrl+T). Give the user one
1543 // navigation of one of these transition types before resetting the
1544 // opener relationships (this allows for the use case of opening a new
1545 // tab to do a quick look-up of something while viewing a tab earlier in
1546 // the strip). We can make this heuristic more permissive if need be.
1547 // TODO(beng): (http://b/1306495) write unit tests for this once this
1548 // object is unit-testable.
1549 int current_tab_index =
1550 tabstrip_model_.GetIndexOfTabContents(current_tab);
[email protected]adf650f2008-12-09 16:10:061551 bool forget_openers =
[email protected]968e56ae2008-08-04 18:39:281552 !(current_tab->type() == TAB_CONTENTS_NEW_TAB_UI &&
1553 current_tab_index == (tab_count() - 1) &&
1554 current_tab->controller()->GetEntryCount() == 1);
1555 if (forget_openers) {
1556 // If the user navigates the current tab to another page in any way
1557 // other than by clicking a link, we want to pro-actively forget all
1558 // TabStrip opener relationships since we assume they're beginning a
1559 // different task by reusing the current tab.
1560 tabstrip_model_.ForgetAllOpeners();
1561 // In this specific case we also want to reset the group relationship,
1562 // since it is now technically invalid.
1563 tabstrip_model_.ForgetGroup(current_tab);
1564 }
initial.commit09911bf2008-07-26 23:55:291565 }
[email protected]c0588052008-10-27 23:01:501566 current_tab->controller()->LoadURL(url, referrer, transition);
[email protected]2d46c842008-11-14 19:24:311567 // The TabContents might have changed as part of the navigation (ex: new
1568 // tab page can become WebContents).
initial.commit09911bf2008-07-26 23:55:291569 new_contents = current_tab->controller()->active_contents();
1570 GetStatusBubble()->Hide();
1571
1572 // Synchronously update the location bar. This allows us to immediately
1573 // have the URL bar update when the user types something, rather than
1574 // going through the normal system of ScheduleUIUpdate which has a delay.
[email protected]36b6dcb2008-11-12 01:19:571575 UpdateToolbar(false);
initial.commit09911bf2008-07-26 23:55:291576 } else if (disposition == OFF_THE_RECORD) {
1577 OpenURLOffTheRecord(profile_, url);
1578 return;
1579 } else if (disposition != SUPPRESS_OPEN) {
[email protected]15952e462008-11-14 00:29:051580 new_contents = AddTabWithURL(url, referrer, transition,
1581 disposition != NEW_BACKGROUND_TAB, instance);
initial.commit09911bf2008-07-26 23:55:291582 }
1583
1584 if (disposition != NEW_BACKGROUND_TAB && source_tab_was_frontmost) {
[email protected]2baf83d2008-07-30 05:58:171585 // Give the focus to the newly navigated tab, if the source tab was
1586 // front-most.
initial.commit09911bf2008-07-26 23:55:291587 new_contents->Focus();
1588 }
1589}
1590
1591void Browser::NavigationStateChanged(const TabContents* source,
1592 unsigned changed_flags) {
initial.commit09911bf2008-07-26 23:55:291593 // Only update the UI when something visible has changed.
[email protected]e83f1682008-09-07 23:57:401594 if (changed_flags)
initial.commit09911bf2008-07-26 23:55:291595 ScheduleUIUpdate(source, changed_flags);
1596
[email protected]84214982008-12-10 18:49:101597 // We don't schedule updates to commands since they will only change once per
1598 // navigation, so we don't have to worry about flickering.
[email protected]e83f1682008-09-07 23:57:401599 if (changed_flags & TabContents::INVALIDATE_URL)
[email protected]84214982008-12-10 18:49:101600 UpdateCommandsForTabState();
initial.commit09911bf2008-07-26 23:55:291601}
1602
1603void Browser::ReplaceContents(TabContents* source, TabContents* new_contents) {
1604 source->set_delegate(NULL);
1605 new_contents->set_delegate(this);
1606
1607 RemoveScheduledUpdatesFor(source);
1608
1609 int index = tabstrip_model_.GetIndexOfTabContents(source);
1610 tabstrip_model_.ReplaceTabContentsAt(index, new_contents);
[email protected]8f673f3a2008-08-05 22:34:281611
1612 if (is_attempting_to_close_browser_) {
1613 // Need to do this asynchronously as it will close the tab, which is
1614 // currently on the call stack above us.
1615 MessageLoop::current()->PostTask(FROM_HERE,
[email protected]8a2ce5a2008-08-11 23:43:081616 method_factory_.NewRunnableMethod(&Browser::ClearUnloadState,
[email protected]8f673f3a2008-08-05 22:34:281617 Source<TabContents>(source).ptr()));
1618 }
1619 // Need to remove ourselves as an observer for disconnection on the replaced
1620 // TabContents, since we only care to fire onbeforeunload handlers on active
1621 // Tabs. Make sure an observer is added for the replacement TabContents.
1622 NotificationService::current()->
[email protected]adf650f2008-12-09 16:10:061623 RemoveObserver(this, NOTIFY_WEB_CONTENTS_DISCONNECTED,
[email protected]8f673f3a2008-08-05 22:34:281624 Source<TabContents>(source));
1625 NotificationService::current()->
1626 AddObserver(this, NOTIFY_WEB_CONTENTS_DISCONNECTED,
1627 Source<TabContents>(new_contents));
initial.commit09911bf2008-07-26 23:55:291628}
1629
1630void Browser::AddNewContents(TabContents* source,
1631 TabContents* new_contents,
1632 WindowOpenDisposition disposition,
1633 const gfx::Rect& initial_pos,
1634 bool user_gesture) {
1635 DCHECK(disposition != SAVE_TO_DISK); // No code for this yet
1636
1637 // If this is an application we can only have one tab so we need to process
1638 // this in tabbed browser window.
1639 if (tabstrip_model_.count() > 0 &&
1640 disposition != NEW_WINDOW && disposition != NEW_POPUP &&
[email protected]299dabd2008-11-19 02:27:161641 type_ != TYPE_NORMAL) {
initial.commit09911bf2008-07-26 23:55:291642 Browser* b = GetOrCreateTabbedBrowser();
1643 DCHECK(b);
1644 PageTransition::Type transition = PageTransition::LINK;
1645 // If we were called from an "installed webapp" we want to emulate the code
1646 // that is run from browser_init.cc for links from external applications.
1647 // This means we need to open the tab with the START PAGE transition.
1648 // AddNewContents doesn't support this but the TabStripModel's
1649 // AddTabContents method does.
[email protected]299dabd2008-11-19 02:27:161650 if (type_ == TYPE_APP)
initial.commit09911bf2008-07-26 23:55:291651 transition = PageTransition::START_PAGE;
1652 b->tabstrip_model()->AddTabContents(new_contents, -1, transition, true);
[email protected]15952e462008-11-14 00:29:051653 b->window()->Show();
initial.commit09911bf2008-07-26 23:55:291654 return;
1655 }
1656
1657 if (disposition == NEW_POPUP) {
1658 BuildPopupWindow(source, new_contents, initial_pos);
1659 } else if (disposition == NEW_WINDOW) {
[email protected]15952e462008-11-14 00:29:051660 Browser* browser = Browser::Create(profile_);
1661 browser->AddNewContents(source, new_contents, NEW_FOREGROUND_TAB,
1662 initial_pos, user_gesture);
1663 browser->window()->Show();
initial.commit09911bf2008-07-26 23:55:291664 } else if (disposition == CURRENT_TAB) {
1665 ReplaceContents(source, new_contents);
1666 } else if (disposition != SUPPRESS_OPEN) {
1667 tabstrip_model_.AddTabContents(new_contents, -1, PageTransition::LINK,
1668 disposition == NEW_FOREGROUND_TAB);
1669 }
1670}
1671
initial.commit09911bf2008-07-26 23:55:291672void Browser::ActivateContents(TabContents* contents) {
1673 tabstrip_model_.SelectTabContentsAt(
1674 tabstrip_model_.GetIndexOfTabContents(contents), false);
[email protected]f3e99e32008-07-30 04:48:391675 window_->Activate();
initial.commit09911bf2008-07-26 23:55:291676}
1677
initial.commit09911bf2008-07-26 23:55:291678void Browser::LoadingStateChanged(TabContents* source) {
[email protected]afb73882008-11-14 22:40:441679 window_->UpdateLoadingAnimations(tabstrip_model_.TabsAreLoading());
[email protected]f3e99e32008-07-30 04:48:391680 window_->UpdateTitleBar();
initial.commit09911bf2008-07-26 23:55:291681
1682 // Let the go button know that it should change appearance if possible.
1683 if (source == GetSelectedTabContents()) {
1684 GetGoButton()->ScheduleChangeMode(
1685 source->is_loading() ? GoButton::MODE_STOP : GoButton::MODE_GO);
1686
1687 GetStatusBubble()->SetStatus(GetSelectedTabContents()->GetStatusText());
1688 }
1689}
1690
1691void Browser::CloseContents(TabContents* source) {
[email protected]04b4a6c2008-08-02 00:44:471692 if (is_attempting_to_close_browser_) {
1693 // If we're trying to close the browser, just clear the state related to
[email protected]adf650f2008-12-09 16:10:061694 // waiting for unload to fire. Don't actually try to close the tab as it
[email protected]04b4a6c2008-08-02 00:44:471695 // will go down the slow shutdown path instead of the fast path of killing
1696 // all the renderer processes.
[email protected]8a2ce5a2008-08-11 23:43:081697 ClearUnloadState(source);
[email protected]04b4a6c2008-08-02 00:44:471698 return;
1699 }
1700
initial.commit09911bf2008-07-26 23:55:291701 int index = tabstrip_model_.GetIndexOfTabContents(source);
1702 if (index == TabStripModel::kNoTab) {
1703 NOTREACHED() << "CloseContents called for tab not in our strip";
1704 return;
1705 }
1706 tabstrip_model_.CloseTabContentsAt(index);
1707}
1708
[email protected]15e8abe2008-08-20 22:40:401709void Browser::MoveContents(TabContents* source, const gfx::Rect& pos) {
[email protected]299dabd2008-11-19 02:27:161710 if (type() != TYPE_POPUP) {
initial.commit09911bf2008-07-26 23:55:291711 NOTREACHED() << "moving invalid browser type";
1712 return;
1713 }
[email protected]2d46c842008-11-14 19:24:311714 window_->SetBounds(pos);
initial.commit09911bf2008-07-26 23:55:291715}
1716
1717bool Browser::IsPopup(TabContents* source) {
1718 // A non-tabbed BROWSER is an unconstrained popup.
[email protected]299dabd2008-11-19 02:27:161719 return (type() == TYPE_POPUP);
initial.commit09911bf2008-07-26 23:55:291720}
1721
[email protected]36b6dcb2008-11-12 01:19:571722void Browser::ToolbarSizeChanged(TabContents* source, bool is_animating) {
1723 if (source == GetSelectedTabContents() || source == NULL) {
1724 // This will refresh the shelf if needed.
1725 window_->SelectedTabToolbarSizeChanged(is_animating);
1726 }
1727}
1728
1729void Browser::URLStarredChanged(TabContents* source, bool starred) {
1730 if (source == GetSelectedTabContents())
1731 SetStarredButtonToggled(starred);
1732}
1733
1734void Browser::ContentsMouseEvent(TabContents* source, UINT message) {
1735 if (source == GetSelectedTabContents()) {
1736 if (message == WM_MOUSEMOVE) {
1737 GetStatusBubble()->MouseMoved();
1738 } else if (message == WM_MOUSELEAVE) {
1739 GetStatusBubble()->SetURL(GURL(), std::wstring());
1740 }
1741 }
1742}
1743
1744void Browser::UpdateTargetURL(TabContents* source, const GURL& url) {
1745 if (source == GetSelectedTabContents()) {
1746 PrefService* prefs = profile_->GetPrefs();
1747 GetStatusBubble()->SetURL(url, prefs->GetString(prefs::kAcceptLanguages));
1748 }
1749}
1750
1751void Browser::ContentsZoomChange(bool zoom_in) {
1752 controller_.ExecuteCommand(zoom_in ? IDC_ZOOM_PLUS : IDC_ZOOM_MINUS);
1753}
1754
1755bool Browser::IsApplication() const {
[email protected]299dabd2008-11-19 02:27:161756 return type_ == TYPE_APP;
[email protected]36b6dcb2008-11-12 01:19:571757}
1758
1759void Browser::ConvertContentsToApplication(TabContents* contents) {
1760 if (!contents->AsWebContents() || !contents->AsWebContents()->web_app()) {
1761 NOTREACHED();
1762 return;
1763 }
1764
1765 int index = tabstrip_model_.GetIndexOfTabContents(contents);
1766 if (index < 0)
1767 return;
1768
1769 WebApp* app = contents->AsWebContents()->web_app();
1770 const std::wstring& app_name =
1771 app->name().empty() ? ComputeApplicationNameFromURL(app->url()) :
1772 app->name();
1773 RegisterAppPrefs(app_name);
1774
1775 tabstrip_model_.DetachTabContentsAt(index);
[email protected]15952e462008-11-14 00:29:051776 Browser* browser = Browser::CreateForApp(app_name, profile_);
1777 browser->tabstrip_model()->AppendTabContents(contents, true);
1778 browser->window()->Show();
[email protected]36b6dcb2008-11-12 01:19:571779}
1780
1781void Browser::ContentsStateChanged(TabContents* source) {
1782 int index = tabstrip_model_.GetIndexOfTabContents(source);
1783 if (index != TabStripModel::kNoTab)
1784 tabstrip_model_.UpdateTabContentsStateAt(index);
1785}
1786
1787bool Browser::ShouldDisplayURLField() {
1788 return !IsApplication();
1789}
1790
1791void Browser::BeforeUnloadFired(TabContents* tab,
1792 bool proceed,
1793 bool* proceed_to_fire_unload) {
1794 if (!is_attempting_to_close_browser_) {
1795 *proceed_to_fire_unload = proceed;
1796 return;
1797 }
1798
1799 if (!proceed) {
1800 CancelWindowClose();
1801 *proceed_to_fire_unload = false;
1802 return;
1803 }
1804
[email protected]06b42f032008-12-03 18:43:051805 if (RemoveFromSet(&tabs_needing_before_unload_fired_, tab)) {
[email protected]2d46c842008-11-14 19:24:311806 // Now that beforeunload has fired, put the tab on the queue to fire
1807 // unload.
[email protected]06b42f032008-12-03 18:43:051808 tabs_needing_unload_fired_.insert(tab);
[email protected]36b6dcb2008-11-12 01:19:571809 ProcessPendingTabs();
[email protected]adf650f2008-12-09 16:10:061810 // We want to handle firing the unload event ourselves since we want to
[email protected]36b6dcb2008-11-12 01:19:571811 // fire all the beforeunload events before attempting to fire the unload
1812 // events should the user cancel closing the browser.
1813 *proceed_to_fire_unload = false;
1814 return;
1815 }
1816
1817 *proceed_to_fire_unload = true;
1818}
1819
initial.commit09911bf2008-07-26 23:55:291820void Browser::ShowHtmlDialog(HtmlDialogContentsDelegate* delegate,
[email protected]2d46c842008-11-14 19:24:311821 void* parent_window) {
1822 window_->ShowHTMLDialog(delegate, parent_window);
initial.commit09911bf2008-07-26 23:55:291823}
1824
[email protected]36b6dcb2008-11-12 01:19:571825///////////////////////////////////////////////////////////////////////////////
1826// Browser, SelectFileDialog::Listener implementation:
1827
1828void Browser::FileSelected(const std::wstring& path, void* params) {
1829 GURL file_url = net::FilePathToFileURL(path);
1830 if (!file_url.is_empty())
1831 OpenURL(file_url, GURL(), CURRENT_TAB, PageTransition::TYPED);
1832}
1833
1834///////////////////////////////////////////////////////////////////////////////
1835// Browser, NotificationObserver implementation:
1836
initial.commit09911bf2008-07-26 23:55:291837void Browser::Observe(NotificationType type,
1838 const NotificationSource& source,
1839 const NotificationDetails& details) {
[email protected]e83f1682008-09-07 23:57:401840 switch (type) {
[email protected]e83f1682008-09-07 23:57:401841 case NOTIFY_WEB_CONTENTS_DISCONNECTED:
1842 if (is_attempting_to_close_browser_) {
1843 // Need to do this asynchronously as it will close the tab, which is
1844 // currently on the call stack above us.
1845 MessageLoop::current()->PostTask(FROM_HERE,
1846 method_factory_.NewRunnableMethod(&Browser::ClearUnloadState,
1847 Source<TabContents>(source).ptr()));
1848 }
1849 break;
1850
1851 case NOTIFY_SSL_STATE_CHANGED:
1852 // When the current tab's SSL state changes, we need to update the URL
[email protected]90e8d062008-09-08 02:26:321853 // bar to reflect the new state. Note that it's possible for the selected
1854 // tab contents to be NULL. This is because we listen for all sources
1855 // (NavigationControllers) for convenience, so the notification could
1856 // actually be for a different window while we're doing asynchronous
1857 // closing of this one.
1858 if (GetSelectedTabContents() &&
1859 GetSelectedTabContents()->controller() ==
[email protected]e83f1682008-09-07 23:57:401860 Source<NavigationController>(source).ptr())
[email protected]36b6dcb2008-11-12 01:19:571861 UpdateToolbar(false);
[email protected]e83f1682008-09-07 23:57:401862 break;
1863
1864 default:
1865 NOTREACHED() << "Got a notification we didn't register for.";
initial.commit09911bf2008-07-26 23:55:291866 }
1867}
1868
[email protected]36b6dcb2008-11-12 01:19:571869///////////////////////////////////////////////////////////////////////////////
1870// Browser, Command and state updating (private):
1871
1872void Browser::InitCommandState() {
1873 // All browser commands whose state isn't set automagically some other way
1874 // (like Back & Forward with initial page load) must have their state
1875 // initialized here, otherwise they will be forever disabled.
1876
[email protected]84214982008-12-10 18:49:101877 // Navigation commands
[email protected]36b6dcb2008-11-12 01:19:571878 controller_.UpdateCommandEnabled(IDC_RELOAD, true);
[email protected]299dabd2008-11-19 02:27:161879 controller_.UpdateCommandEnabled(IDC_HOME, type() == TYPE_NORMAL);
[email protected]84214982008-12-10 18:49:101880 controller_.UpdateCommandEnabled(IDC_OPEN_CURRENT_URL, true);
[email protected]36b6dcb2008-11-12 01:19:571881 controller_.UpdateCommandEnabled(IDC_GO, true);
[email protected]84214982008-12-10 18:49:101882
1883 // Window management commands
1884 controller_.UpdateCommandEnabled(IDC_NEW_WINDOW, true);
1885 controller_.UpdateCommandEnabled(IDC_NEW_INCOGNITO_WINDOW, true);
1886 controller_.UpdateCommandEnabled(IDC_PROFILE_MENU, true);
1887 // TODO(pkasting): Perhaps the code that populates this submenu should do
1888 // this?
1889 controller_.UpdateCommandEnabled(IDC_NEW_WINDOW_PROFILE_0, true);
1890 controller_.UpdateCommandEnabled(IDC_NEW_WINDOW_PROFILE_1, true);
1891 controller_.UpdateCommandEnabled(IDC_NEW_WINDOW_PROFILE_2, true);
1892 controller_.UpdateCommandEnabled(IDC_NEW_WINDOW_PROFILE_3, true);
1893 controller_.UpdateCommandEnabled(IDC_NEW_WINDOW_PROFILE_4, true);
1894 controller_.UpdateCommandEnabled(IDC_NEW_WINDOW_PROFILE_5, true);
1895 controller_.UpdateCommandEnabled(IDC_NEW_WINDOW_PROFILE_6, true);
1896 controller_.UpdateCommandEnabled(IDC_NEW_WINDOW_PROFILE_7, true);
1897 controller_.UpdateCommandEnabled(IDC_NEW_WINDOW_PROFILE_8, true);
1898 controller_.UpdateCommandEnabled(IDC_CLOSE_WINDOW, true);
[email protected]f1d306e62008-12-08 20:50:051899 controller_.UpdateCommandEnabled(IDC_NEW_TAB, true);
1900 controller_.UpdateCommandEnabled(IDC_CLOSE_TAB, true);
[email protected]36b6dcb2008-11-12 01:19:571901 controller_.UpdateCommandEnabled(IDC_SELECT_NEXT_TAB, true);
[email protected]f1d306e62008-12-08 20:50:051902 controller_.UpdateCommandEnabled(IDC_SELECT_PREVIOUS_TAB, true);
[email protected]36b6dcb2008-11-12 01:19:571903 controller_.UpdateCommandEnabled(IDC_SELECT_TAB_0, true);
1904 controller_.UpdateCommandEnabled(IDC_SELECT_TAB_1, true);
1905 controller_.UpdateCommandEnabled(IDC_SELECT_TAB_2, true);
1906 controller_.UpdateCommandEnabled(IDC_SELECT_TAB_3, true);
1907 controller_.UpdateCommandEnabled(IDC_SELECT_TAB_4, true);
1908 controller_.UpdateCommandEnabled(IDC_SELECT_TAB_5, true);
1909 controller_.UpdateCommandEnabled(IDC_SELECT_TAB_6, true);
1910 controller_.UpdateCommandEnabled(IDC_SELECT_TAB_7, true);
1911 controller_.UpdateCommandEnabled(IDC_SELECT_LAST_TAB, true);
[email protected]f1d306e62008-12-08 20:50:051912 controller_.UpdateCommandEnabled(IDC_DUPLICATE_TAB, true);
[email protected]84214982008-12-10 18:49:101913 controller_.UpdateCommandEnabled(IDC_RESTORE_TAB,
1914 (!profile_->IsOffTheRecord() && type() == TYPE_NORMAL));
1915 controller_.UpdateCommandEnabled(IDC_SHOW_AS_TAB, type() == TYPE_POPUP);
1916 controller_.UpdateCommandEnabled(IDC_EXIT, true);
1917
1918 // Page-related commands
1919 controller_.UpdateCommandEnabled(IDC_CLOSE_POPUPS, true);
[email protected]36b6dcb2008-11-12 01:19:571920 controller_.UpdateCommandEnabled(IDC_ENCODING_AUTO_DETECT, true);
1921 controller_.UpdateCommandEnabled(IDC_ENCODING_UTF8, true);
1922 controller_.UpdateCommandEnabled(IDC_ENCODING_UTF16LE, true);
1923 controller_.UpdateCommandEnabled(IDC_ENCODING_ISO88591, true);
1924 controller_.UpdateCommandEnabled(IDC_ENCODING_WINDOWS1252, true);
1925 controller_.UpdateCommandEnabled(IDC_ENCODING_GB2312, true);
1926 controller_.UpdateCommandEnabled(IDC_ENCODING_GB18030, true);
1927 controller_.UpdateCommandEnabled(IDC_ENCODING_BIG5HKSCS, true);
1928 controller_.UpdateCommandEnabled(IDC_ENCODING_BIG5, true);
1929 controller_.UpdateCommandEnabled(IDC_ENCODING_THAI, true);
1930 controller_.UpdateCommandEnabled(IDC_ENCODING_KOREAN, true);
1931 controller_.UpdateCommandEnabled(IDC_ENCODING_SHIFTJIS, true);
1932 controller_.UpdateCommandEnabled(IDC_ENCODING_ISO2022JP, true);
1933 controller_.UpdateCommandEnabled(IDC_ENCODING_EUCJP, true);
1934 controller_.UpdateCommandEnabled(IDC_ENCODING_ISO885915, true);
1935 controller_.UpdateCommandEnabled(IDC_ENCODING_MACINTOSH, true);
1936 controller_.UpdateCommandEnabled(IDC_ENCODING_ISO88592, true);
1937 controller_.UpdateCommandEnabled(IDC_ENCODING_WINDOWS1250, true);
1938 controller_.UpdateCommandEnabled(IDC_ENCODING_ISO88595, true);
1939 controller_.UpdateCommandEnabled(IDC_ENCODING_WINDOWS1251, true);
1940 controller_.UpdateCommandEnabled(IDC_ENCODING_KOI8R, true);
1941 controller_.UpdateCommandEnabled(IDC_ENCODING_KOI8U, true);
1942 controller_.UpdateCommandEnabled(IDC_ENCODING_ISO88597, true);
1943 controller_.UpdateCommandEnabled(IDC_ENCODING_WINDOWS1253, true);
1944 controller_.UpdateCommandEnabled(IDC_ENCODING_ISO88594, true);
1945 controller_.UpdateCommandEnabled(IDC_ENCODING_ISO885913, true);
1946 controller_.UpdateCommandEnabled(IDC_ENCODING_WINDOWS1257, true);
1947 controller_.UpdateCommandEnabled(IDC_ENCODING_ISO88593, true);
1948 controller_.UpdateCommandEnabled(IDC_ENCODING_ISO885910, true);
1949 controller_.UpdateCommandEnabled(IDC_ENCODING_ISO885914, true);
1950 controller_.UpdateCommandEnabled(IDC_ENCODING_ISO885916, true);
[email protected]36b6dcb2008-11-12 01:19:571951 controller_.UpdateCommandEnabled(IDC_ENCODING_WINDOWS1254, true);
1952 controller_.UpdateCommandEnabled(IDC_ENCODING_ISO88596, true);
1953 controller_.UpdateCommandEnabled(IDC_ENCODING_WINDOWS1256, true);
1954 controller_.UpdateCommandEnabled(IDC_ENCODING_ISO88598, true);
1955 controller_.UpdateCommandEnabled(IDC_ENCODING_WINDOWS1255, true);
1956 controller_.UpdateCommandEnabled(IDC_ENCODING_WINDOWS1258, true);
[email protected]84214982008-12-10 18:49:101957
1958 // Clipboard commands
1959 controller_.UpdateCommandEnabled(IDC_CUT, true);
1960 controller_.UpdateCommandEnabled(IDC_COPY, true);
1961 controller_.UpdateCommandEnabled(IDC_COPY_URL, true);
1962 controller_.UpdateCommandEnabled(IDC_PASTE, true);
1963
1964 // Focus various bits of UI
1965 controller_.UpdateCommandEnabled(IDC_FOCUS_TOOLBAR, true);
1966 controller_.UpdateCommandEnabled(IDC_FOCUS_LOCATION, true);
1967 controller_.UpdateCommandEnabled(IDC_FOCUS_SEARCH, true);
1968
1969 // Show various bits of UI
1970 controller_.UpdateCommandEnabled(IDC_OPEN_FILE, true);
1971 controller_.UpdateCommandEnabled(IDC_CREATE_SHORTCUTS, false);
1972 controller_.UpdateCommandEnabled(IDC_DEVELOPER_MENU, true);
1973 // The debugger doesn't work in single process mode.
[email protected]36b6dcb2008-11-12 01:19:571974 controller_.UpdateCommandEnabled(IDC_DEBUGGER,
1975 !RenderProcessHost::run_renderer_in_process());
[email protected]84214982008-12-10 18:49:101976 controller_.UpdateCommandEnabled(IDC_TASK_MANAGER, true);
1977 controller_.UpdateCommandEnabled(IDC_SELECT_PROFILE, true);
1978 controller_.UpdateCommandEnabled(IDC_NEW_PROFILE, true);
1979 controller_.UpdateCommandEnabled(IDC_REPORT_BUG, true);
1980 controller_.UpdateCommandEnabled(IDC_SHOW_BOOKMARK_BAR, true);
1981 controller_.UpdateCommandEnabled(IDC_SHOW_HISTORY, true);
1982 controller_.UpdateCommandEnabled(IDC_SHOW_BOOKMARK_MANAGER, true);
1983 controller_.UpdateCommandEnabled(IDC_SHOW_DOWNLOADS, true);
1984 controller_.UpdateCommandEnabled(IDC_CLEAR_BROWSING_DATA, true);
1985 controller_.UpdateCommandEnabled(IDC_IMPORT_SETTINGS, true);
1986 controller_.UpdateCommandEnabled(IDC_OPTIONS, true);
1987 controller_.UpdateCommandEnabled(IDC_EDIT_SEARCH_ENGINES, true);
1988 controller_.UpdateCommandEnabled(IDC_VIEW_PASSWORDS, true);
1989 controller_.UpdateCommandEnabled(IDC_ABOUT, true);
[email protected]f1d306e62008-12-08 20:50:051990 controller_.UpdateCommandEnabled(IDC_HELP_PAGE, true);
[email protected]36b6dcb2008-11-12 01:19:571991}
1992
[email protected]84214982008-12-10 18:49:101993void Browser::UpdateCommandsForTabState() {
[email protected]c7c42332008-11-15 01:10:541994 TabContents* current_tab = GetSelectedTabContents();
[email protected]d8375fd2008-11-25 22:45:391995 if (!current_tab) {
1996 // It's possible for this to be null during tab restore.
1997 return;
1998 }
1999
[email protected]84214982008-12-10 18:49:102000 // Navigation commands
initial.commit09911bf2008-07-26 23:55:292001 NavigationController* nc = current_tab->controller();
2002 controller_.UpdateCommandEnabled(IDC_BACK, nc->CanGoBack());
2003 controller_.UpdateCommandEnabled(IDC_FORWARD, nc->CanGoForward());
2004
[email protected]84214982008-12-10 18:49:102005 // Window management commands
2006 controller_.UpdateCommandEnabled(IDC_DUPLICATE_TAB,
2007 CanDuplicateContentsAt(selected_index()));
2008
2009 // Show various bits of UI
2010 controller_.UpdateCommandEnabled(IDC_CREATE_SHORTCUTS,
2011 current_tab->type() == TAB_CONTENTS_WEB &&
2012 !current_tab->GetFavIcon().isNull());
2013
[email protected]c7c42332008-11-15 01:10:542014 WebContents* web_contents = current_tab->AsWebContents();
initial.commit09911bf2008-07-26 23:55:292015 if (web_contents) {
[email protected]84214982008-12-10 18:49:102016 // Page-related commands
initial.commit09911bf2008-07-26 23:55:292017 controller_.UpdateCommandEnabled(IDC_STAR, true);
2018 SetStarredButtonToggled(web_contents->is_starred());
initial.commit09911bf2008-07-26 23:55:292019 // View-source should not be enabled if already in view-source mode.
[email protected]f1d306e62008-12-08 20:50:052020 controller_.UpdateCommandEnabled(IDC_VIEW_SOURCE,
initial.commit09911bf2008-07-26 23:55:292021 current_tab->type() != TAB_CONTENTS_VIEW_SOURCE &&
2022 current_tab->controller()->GetActiveEntry());
[email protected]84214982008-12-10 18:49:102023 controller_.UpdateCommandEnabled(IDC_PRINT, true);
[email protected]f1d306e62008-12-08 20:50:052024 controller_.UpdateCommandEnabled(IDC_SAVE_PAGE,
initial.commit09911bf2008-07-26 23:55:292025 SavePackage::IsSavableURL(current_tab->GetURL()));
[email protected]84214982008-12-10 18:49:102026 controller_.UpdateCommandEnabled(IDC_ENCODING_MENU,
2027 SavePackage::IsSavableContents(web_contents->contents_mime_type()) &&
2028 SavePackage::IsSavableURL(current_tab->GetURL()));
2029
2030 // Find-in-page
[email protected]fbd77592008-11-12 20:50:272031 controller_.UpdateCommandEnabled(IDC_FIND, true);
2032 controller_.UpdateCommandEnabled(IDC_FIND_NEXT, true);
2033 controller_.UpdateCommandEnabled(IDC_FIND_PREVIOUS, true);
initial.commit09911bf2008-07-26 23:55:292034
[email protected]84214982008-12-10 18:49:102035 // Zoom
2036 controller_.UpdateCommandEnabled(IDC_ZOOM_MENU, true);
2037 controller_.UpdateCommandEnabled(IDC_ZOOM_PLUS, true);
2038 controller_.UpdateCommandEnabled(IDC_ZOOM_NORMAL, true);
2039 controller_.UpdateCommandEnabled(IDC_ZOOM_MINUS, true);
2040
2041 // Show various bits of UI
2042 controller_.UpdateCommandEnabled(IDC_JS_CONSOLE, true);
2043 } else {
2044 // Page-related commands
initial.commit09911bf2008-07-26 23:55:292045 // Both disable the starring button and ensure it doesn't show a star.
2046 controller_.UpdateCommandEnabled(IDC_STAR, false);
2047 SetStarredButtonToggled(false);
[email protected]84214982008-12-10 18:49:102048 controller_.UpdateCommandEnabled(IDC_VIEW_SOURCE, false);
2049 controller_.UpdateCommandEnabled(IDC_PRINT, false);
2050 controller_.UpdateCommandEnabled(IDC_SAVE_PAGE, false);
[email protected]f1d306e62008-12-08 20:50:052051 controller_.UpdateCommandEnabled(IDC_ENCODING_MENU, false);
initial.commit09911bf2008-07-26 23:55:292052
[email protected]84214982008-12-10 18:49:102053 // Find-in-page
[email protected]fbd77592008-11-12 20:50:272054 controller_.UpdateCommandEnabled(IDC_FIND, false);
2055 controller_.UpdateCommandEnabled(IDC_FIND_NEXT, false);
2056 controller_.UpdateCommandEnabled(IDC_FIND_PREVIOUS, false);
[email protected]84214982008-12-10 18:49:102057
2058 // Zoom
2059 controller_.UpdateCommandEnabled(IDC_ZOOM_MENU, false);
[email protected]fbd77592008-11-12 20:50:272060 controller_.UpdateCommandEnabled(IDC_ZOOM_PLUS, false);
[email protected]fbd77592008-11-12 20:50:272061 controller_.UpdateCommandEnabled(IDC_ZOOM_NORMAL, false);
[email protected]84214982008-12-10 18:49:102062 controller_.UpdateCommandEnabled(IDC_ZOOM_MINUS, false);
initial.commit09911bf2008-07-26 23:55:292063
[email protected]84214982008-12-10 18:49:102064 // Show various bits of UI
2065 controller_.UpdateCommandEnabled(IDC_JS_CONSOLE, false);
[email protected]f2530062008-12-03 23:52:032066 }
initial.commit09911bf2008-07-26 23:55:292067}
2068
[email protected]36b6dcb2008-11-12 01:19:572069void Browser::SetStarredButtonToggled(bool starred) {
2070 window_->GetStarButton()->SetToggled(starred);
initial.commit09911bf2008-07-26 23:55:292071}
2072
[email protected]36b6dcb2008-11-12 01:19:572073///////////////////////////////////////////////////////////////////////////////
2074// Browser, UI update coalescing and handling (private):
2075
2076void Browser::UpdateToolbar(bool should_restore_state) {
2077 window_->UpdateToolbar(GetSelectedTabContents(), should_restore_state);
initial.commit09911bf2008-07-26 23:55:292078}
2079
[email protected]36b6dcb2008-11-12 01:19:572080void Browser::ScheduleUIUpdate(const TabContents* source,
2081 unsigned changed_flags) {
2082 // Synchronously update the URL.
2083 if (changed_flags & TabContents::INVALIDATE_URL &&
2084 source == GetSelectedTabContents()) {
2085 // Only update the URL for the current tab. Note that we do not update
2086 // the navigation commands since those would have already been updated
2087 // synchronously by NavigationStateChanged.
2088 UpdateToolbar(false);
2089
2090 if (changed_flags == TabContents::INVALIDATE_URL)
2091 return; // Just had an update URL and nothing else.
2092 }
2093
2094 // Save the dirty bits.
2095 scheduled_updates_.push_back(UIUpdate(source, changed_flags));
2096
2097 if (chrome_updater_factory_.empty()) {
2098 // No task currently scheduled, start another.
2099 MessageLoop::current()->PostDelayedTask(FROM_HERE,
2100 chrome_updater_factory_.NewRunnableMethod(
2101 &Browser::ProcessPendingUIUpdates),
2102 kUIUpdateCoalescingTimeMS);
2103 }
2104}
2105
2106void Browser::ProcessPendingUIUpdates() {
2107#ifndef NDEBUG
2108 // Validate that all tabs we have pending updates for exist. This is scary
2109 // because the pending list must be kept in sync with any detached or
2110 // deleted tabs. This code does not dereference any TabContents pointers.
2111 for (size_t i = 0; i < scheduled_updates_.size(); i++) {
2112 bool found = false;
2113 for (int tab = 0; tab < tab_count(); tab++) {
2114 if (GetTabContentsAt(tab)->controller() ==
2115 scheduled_updates_[i].source->controller()) {
2116 found = true;
2117 break;
2118 }
2119 }
2120 DCHECK(found);
2121 }
2122#endif
2123
2124 chrome_updater_factory_.RevokeAll();
2125
[email protected]2d46c842008-11-14 19:24:312126 // We could have many updates for the same thing in the queue. This map
2127 // tracks the bits of the stuff we've already updated for each TabContents so
2128 // we don't update again.
[email protected]36b6dcb2008-11-12 01:19:572129 typedef std::map<const TabContents*, unsigned> UpdateTracker;
2130 UpdateTracker updated_stuff;
2131
2132 for (size_t i = 0; i < scheduled_updates_.size(); i++) {
2133 // Do not dereference |contents|, it may be out-of-date!
2134 const TabContents* contents = scheduled_updates_[i].source;
2135 unsigned flags = scheduled_updates_[i].changed_flags;
2136
2137 // Remove any bits we have already updated, and save the new bits.
2138 UpdateTracker::iterator updated = updated_stuff.find(contents);
2139 if (updated != updated_stuff.end()) {
2140 // Turn off bits already set.
2141 flags &= ~updated->second;
2142 if (!flags)
2143 continue;
2144
2145 updated->second |= flags;
2146 } else {
2147 updated_stuff[contents] = flags;
2148 }
2149
2150 // Updates to the title or favicon require a tab repaint. However, the
2151 // inverse is not true since updates to the title also update the window
2152 // title.
2153 bool invalidate_tab = false;
2154 if (flags & TabContents::INVALIDATE_TITLE ||
2155 flags & TabContents::INVALIDATE_FAVICON) {
2156 invalidate_tab = true;
2157
2158 // Anything that repaints the tab means the favicon is updated.
2159 updated_stuff[contents] |= TabContents::INVALIDATE_FAVICON;
2160 }
2161
2162 // Updating the URL happens synchronously in ScheduleUIUpdate.
2163
2164 if (flags & TabContents::INVALIDATE_LOAD)
2165 GetStatusBubble()->SetStatus(GetSelectedTabContents()->GetStatusText());
2166
2167 if (invalidate_tab) { // INVALIDATE_TITLE or INVALIDATE_FAVICON.
2168 tabstrip_model_.UpdateTabContentsStateAt(
2169 tabstrip_model_.GetIndexOfController(contents->controller()));
2170 window_->UpdateTitleBar();
2171
2172 if (contents == GetSelectedTabContents()) {
2173 TabContents* current_tab = GetSelectedTabContents();
[email protected]f1d306e62008-12-08 20:50:052174 controller_.UpdateCommandEnabled(IDC_CREATE_SHORTCUTS,
[email protected]36b6dcb2008-11-12 01:19:572175 current_tab->type() == TAB_CONTENTS_WEB &&
2176 !current_tab->GetFavIcon().isNull());
2177 }
2178 }
2179
2180 // We don't need to process INVALIDATE_STATE, since that's not visible.
2181 }
2182
2183 scheduled_updates_.clear();
2184}
2185
2186void Browser::RemoveScheduledUpdatesFor(TabContents* contents) {
2187 if (!contents)
2188 return;
2189
2190 // Remove any pending UI updates for the detached tab.
2191 UpdateVector::iterator cur_update = scheduled_updates_.begin();
2192 while (cur_update != scheduled_updates_.end()) {
2193 if (cur_update->source == contents) {
2194 cur_update = scheduled_updates_.erase(cur_update);
2195 } else {
2196 ++cur_update;
initial.commit09911bf2008-07-26 23:55:292197 }
2198 }
2199}
2200
[email protected]36b6dcb2008-11-12 01:19:572201///////////////////////////////////////////////////////////////////////////////
2202// Browser, Getters for UI (private):
initial.commit09911bf2008-07-26 23:55:292203
[email protected]36b6dcb2008-11-12 01:19:572204LocationBarView* Browser::GetLocationBarView() const {
2205 return window_->GetLocationBarView();
initial.commit09911bf2008-07-26 23:55:292206}
2207
2208GoButton* Browser::GetGoButton() {
[email protected]195442e2008-07-31 22:41:282209 return window_->GetGoButton();
initial.commit09911bf2008-07-26 23:55:292210}
2211
[email protected]36b6dcb2008-11-12 01:19:572212StatusBubble* Browser::GetStatusBubble() {
2213 return window_->GetStatusBubble();
initial.commit09911bf2008-07-26 23:55:292214}
2215
[email protected]36b6dcb2008-11-12 01:19:572216///////////////////////////////////////////////////////////////////////////////
2217// Browser, Session restore functions (private):
initial.commit09911bf2008-07-26 23:55:292218
2219void Browser::SyncHistoryWithTabs(int index) {
2220 if (!profile()->HasSessionService())
2221 return;
2222 SessionService* session_service = profile()->GetSessionService();
2223 if (session_service) {
2224 for (int i = index; i < tab_count(); ++i) {
2225 TabContents* contents = GetTabContentsAt(i);
2226 if (contents) {
2227 session_service->SetTabIndexInWindow(
2228 session_id(), contents->controller()->session_id(), i);
2229 }
2230 }
2231 }
2232}
2233
[email protected]36b6dcb2008-11-12 01:19:572234NavigationController* Browser::BuildRestoredNavigationController(
2235 const std::vector<TabNavigation>& navigations,
2236 int selected_navigation) {
2237 if (!navigations.empty()) {
2238 DCHECK(selected_navigation >= 0 &&
2239 selected_navigation < static_cast<int>(navigations.size()));
[email protected]36b6dcb2008-11-12 01:19:572240 // Create a NavigationController. This constructor creates the appropriate
2241 // set of TabContents.
[email protected]ec322ff2008-11-19 22:53:302242 return new NavigationController(profile_, navigations, selected_navigation);
[email protected]36b6dcb2008-11-12 01:19:572243 } else {
2244 // No navigations. Create a tab with about:blank.
2245 TabContents* contents =
2246 CreateTabContentsForURL(GURL("about:blank"), GURL(), profile_,
2247 PageTransition::START_PAGE, false, NULL);
2248 return new NavigationController(contents, profile_);
initial.commit09911bf2008-07-26 23:55:292249 }
2250}
2251
[email protected]36b6dcb2008-11-12 01:19:572252///////////////////////////////////////////////////////////////////////////////
2253// Browser, OnBeforeUnload handling (private):
initial.commit09911bf2008-07-26 23:55:292254
[email protected]04b4a6c2008-08-02 00:44:472255void Browser::ProcessPendingTabs() {
2256 DCHECK(is_attempting_to_close_browser_);
initial.commit09911bf2008-07-26 23:55:292257
[email protected]04b4a6c2008-08-02 00:44:472258 if (HasCompletedUnloadProcessing()) {
2259 // We've finished all the unload events and can proceed to close the
2260 // browser.
2261 OnWindowClosing();
initial.commit09911bf2008-07-26 23:55:292262 return;
2263 }
2264
[email protected]04b4a6c2008-08-02 00:44:472265 // Process beforeunload tabs first. When that queue is empty, process
2266 // unload tabs.
[email protected]04b4a6c2008-08-02 00:44:472267 if (!tabs_needing_before_unload_fired_.empty()) {
[email protected]06b42f032008-12-03 18:43:052268 TabContents* tab = *(tabs_needing_before_unload_fired_.begin());
[email protected]1f5af4442008-09-25 22:11:062269 tab->AsWebContents()->render_view_host()->FirePageBeforeUnload();
[email protected]04b4a6c2008-08-02 00:44:472270 } else if (!tabs_needing_unload_fired_.empty()) {
initial.commit09911bf2008-07-26 23:55:292271 // We've finished firing all beforeunload events and can proceed with unload
2272 // events.
2273 // TODO(ojan): We should add a call to browser_shutdown::OnShutdownStarting
2274 // somewhere around here so that we have accurate measurements of shutdown
2275 // time.
[email protected]04b4a6c2008-08-02 00:44:472276 // TODO(ojan): We can probably fire all the unload events in parallel and
2277 // get a perf benefit from that in the cases where the tab hangs in it's
2278 // unload handler or takes a long time to page in.
[email protected]06b42f032008-12-03 18:43:052279 TabContents* tab = *(tabs_needing_unload_fired_.begin());
[email protected]1f5af4442008-09-25 22:11:062280 tab->AsWebContents()->render_view_host()->FirePageUnload();
initial.commit09911bf2008-07-26 23:55:292281 } else {
[email protected]04b4a6c2008-08-02 00:44:472282 NOTREACHED();
initial.commit09911bf2008-07-26 23:55:292283 }
2284}
2285
[email protected]04b4a6c2008-08-02 00:44:472286bool Browser::HasCompletedUnloadProcessing() {
2287 return is_attempting_to_close_browser_ &&
2288 tabs_needing_before_unload_fired_.empty() &&
2289 tabs_needing_unload_fired_.empty();
2290}
2291
2292void Browser::CancelWindowClose() {
2293 DCHECK(is_attempting_to_close_browser_);
2294 // Only cancelling beforeunload should be able to cancel the window's close.
2295 // So there had better be a tab that we think needs beforeunload fired.
2296 DCHECK(!tabs_needing_before_unload_fired_.empty());
2297
[email protected]8f673f3a2008-08-05 22:34:282298 tabs_needing_before_unload_fired_.clear();
2299 tabs_needing_unload_fired_.clear();
[email protected]04b4a6c2008-08-02 00:44:472300
2301 is_attempting_to_close_browser_ = false;
2302}
2303
[email protected]06b42f032008-12-03 18:43:052304bool Browser::RemoveFromSet(UnloadListenerSet* set, TabContents* tab) {
[email protected]04b4a6c2008-08-02 00:44:472305 DCHECK(is_attempting_to_close_browser_);
2306
[email protected]06b42f032008-12-03 18:43:052307 UnloadListenerSet::iterator iter = std::find(set->begin(), set->end(), tab);
2308 if (iter != set->end()) {
2309 set->erase(iter);
2310 return true;
[email protected]04b4a6c2008-08-02 00:44:472311 }
2312 return false;
2313}
initial.commit09911bf2008-07-26 23:55:292314
[email protected]36b6dcb2008-11-12 01:19:572315void Browser::ClearUnloadState(TabContents* tab) {
2316 DCHECK(is_attempting_to_close_browser_);
[email protected]06b42f032008-12-03 18:43:052317 RemoveFromSet(&tabs_needing_before_unload_fired_, tab);
2318 RemoveFromSet(&tabs_needing_unload_fired_, tab);
[email protected]36b6dcb2008-11-12 01:19:572319 ProcessPendingTabs();
initial.commit09911bf2008-07-26 23:55:292320}
2321
[email protected]36b6dcb2008-11-12 01:19:572322///////////////////////////////////////////////////////////////////////////////
2323// Browser, Assorted utility functions (private):
initial.commit09911bf2008-07-26 23:55:292324
initial.commit09911bf2008-07-26 23:55:292325Browser* Browser::GetOrCreateTabbedBrowser() {
2326 Browser* browser = BrowserList::FindBrowserWithType(
[email protected]299dabd2008-11-19 02:27:162327 profile_, TYPE_NORMAL);
[email protected]15952e462008-11-14 00:29:052328 if (!browser)
2329 browser = Browser::Create(profile_);
initial.commit09911bf2008-07-26 23:55:292330 return browser;
2331}
2332
initial.commit09911bf2008-07-26 23:55:292333void Browser::BuildPopupWindow(TabContents* source,
2334 TabContents* new_contents,
2335 const gfx::Rect& initial_pos) {
[email protected]299dabd2008-11-19 02:27:162336 Type type = type_ == TYPE_APP ? type_ : TYPE_POPUP;
[email protected]15952e462008-11-14 00:29:052337 Browser* browser = new Browser(type, profile_);
2338 browser->set_override_bounds(initial_pos);
2339 browser->CreateBrowserWindow();
2340 // TODO(beng): See if this can be made to use
2341 // TabStripModel::AppendTabContents.
2342 browser->AddNewContents(source, new_contents, NEW_FOREGROUND_TAB,
2343 gfx::Rect(), true);
2344 browser->window()->Show();
initial.commit09911bf2008-07-26 23:55:292345}
2346
[email protected]36b6dcb2008-11-12 01:19:572347GURL Browser::GetHomePage() {
[email protected]15952e462008-11-14 00:29:052348 if (profile_->GetPrefs()->GetBoolean(prefs::kHomePageIsNewTabPage))
[email protected]36b6dcb2008-11-12 01:19:572349 return NewTabUIURL();
[email protected]15952e462008-11-14 00:29:052350 GURL home_page = GURL(URLFixerUpper::FixupURL(
2351 profile_->GetPrefs()->GetString(prefs::kHomePage),
2352 std::wstring()));
2353 if (!home_page.is_valid())
2354 return NewTabUIURL();
2355 return home_page;
[email protected]36b6dcb2008-11-12 01:19:572356}
initial.commit09911bf2008-07-26 23:55:292357
[email protected]fbd77592008-11-12 20:50:272358void Browser::AdvanceFindSelection(bool forward_direction) {
2359 GetSelectedTabContents()->AsWebContents()->view()->FindInPage(
2360 *this, true, forward_direction);
2361}
2362
[email protected]36b6dcb2008-11-12 01:19:572363void Browser::CloseFrame() {
2364 window_->Close();
initial.commit09911bf2008-07-26 23:55:292365}
2366
2367// static
2368std::wstring Browser::ComputeApplicationNameFromURL(const GURL& url) {
2369 std::string t;
2370 t.append(url.host());
2371 t.append("_");
2372 t.append(url.path());
2373 return UTF8ToWide(t);
2374}
2375
2376// static
initial.commit09911bf2008-07-26 23:55:292377void Browser::RegisterAppPrefs(const std::wstring& app_name) {
2378 // A set of apps that we've already started.
2379 static std::set<std::wstring>* g_app_names = NULL;
2380
2381 if (!g_app_names)
2382 g_app_names = new std::set<std::wstring>;
2383
2384 // Only register once for each app name.
2385 if (g_app_names->find(app_name) != g_app_names->end())
2386 return;
2387 g_app_names->insert(app_name);
2388
2389 // We need to register the window position pref.
2390 std::wstring window_pref(prefs::kBrowserWindowPlacement);
2391 window_pref.append(L"_");
2392 window_pref.append(app_name);
2393 PrefService* prefs = g_browser_process->local_state();
2394 DCHECK(prefs);
2395
2396 prefs->RegisterDictionaryPref(window_pref.c_str());
2397}