OLD | NEW |
1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. | 1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. |
2 // Use of this source code is governed by a BSD-style license that can be | 2 // Use of this source code is governed by a BSD-style license that can be |
3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
4 | 4 |
5 #include "chrome/browser/ui/browser.h" | 5 #include "chrome/browser/ui/browser.h" |
6 | 6 |
7 #if defined(OS_WIN) | 7 #if defined(OS_WIN) |
8 #include <windows.h> | 8 #include <windows.h> |
9 #include <shellapi.h> | 9 #include <shellapi.h> |
10 #endif // OS_WIN | 10 #endif // OS_WIN |
(...skipping 117 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
128 #include "chrome/browser/ui/search/search_model.h" | 128 #include "chrome/browser/ui/search/search_model.h" |
129 #include "chrome/browser/ui/search_engines/search_engine_tab_helper.h" | 129 #include "chrome/browser/ui/search_engines/search_engine_tab_helper.h" |
130 #include "chrome/browser/ui/singleton_tabs.h" | 130 #include "chrome/browser/ui/singleton_tabs.h" |
131 #include "chrome/browser/ui/status_bubble.h" | 131 #include "chrome/browser/ui/status_bubble.h" |
132 #include "chrome/browser/ui/sync/browser_synced_window_delegate.h" | 132 #include "chrome/browser/ui/sync/browser_synced_window_delegate.h" |
133 #include "chrome/browser/ui/tab_contents/core_tab_helper.h" | 133 #include "chrome/browser/ui/tab_contents/core_tab_helper.h" |
134 #include "chrome/browser/ui/tab_contents/tab_contents.h" | 134 #include "chrome/browser/ui/tab_contents/tab_contents.h" |
135 #include "chrome/browser/ui/tabs/dock_info.h" | 135 #include "chrome/browser/ui/tabs/dock_info.h" |
136 #include "chrome/browser/ui/tabs/tab_menu_model.h" | 136 #include "chrome/browser/ui/tabs/tab_menu_model.h" |
137 #include "chrome/browser/ui/tabs/tab_strip_model.h" | 137 #include "chrome/browser/ui/tabs/tab_strip_model.h" |
| 138 #include "chrome/browser/ui/unload_controller.h" |
138 #include "chrome/browser/ui/web_applications/web_app_ui.h" | 139 #include "chrome/browser/ui/web_applications/web_app_ui.h" |
139 #include "chrome/browser/ui/webui/feedback_ui.h" | 140 #include "chrome/browser/ui/webui/feedback_ui.h" |
140 #include "chrome/browser/ui/webui/ntp/app_launcher_handler.h" | 141 #include "chrome/browser/ui/webui/ntp/app_launcher_handler.h" |
141 #include "chrome/browser/ui/webui/signin/login_ui_service.h" | 142 #include "chrome/browser/ui/webui/signin/login_ui_service.h" |
142 #include "chrome/browser/ui/webui/signin/login_ui_service_factory.h" | 143 #include "chrome/browser/ui/webui/signin/login_ui_service_factory.h" |
143 #include "chrome/browser/ui/window_sizer/window_sizer.h" | 144 #include "chrome/browser/ui/window_sizer/window_sizer.h" |
144 #include "chrome/browser/upgrade_detector.h" | 145 #include "chrome/browser/upgrade_detector.h" |
145 #include "chrome/browser/web_applications/web_app.h" | 146 #include "chrome/browser/web_applications/web_app.h" |
146 #include "chrome/common/chrome_constants.h" | 147 #include "chrome/common/chrome_constants.h" |
147 #include "chrome/common/chrome_notification_types.h" | 148 #include "chrome/common/chrome_notification_types.h" |
(...skipping 147 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
295 // Browser, Constructors, Creation, Showing: | 296 // Browser, Constructors, Creation, Showing: |
296 | 297 |
297 Browser::Browser(Type type, Profile* profile) | 298 Browser::Browser(Type type, Profile* profile) |
298 : type_(type), | 299 : type_(type), |
299 profile_(profile), | 300 profile_(profile), |
300 window_(NULL), | 301 window_(NULL), |
301 ALLOW_THIS_IN_INITIALIZER_LIST( | 302 ALLOW_THIS_IN_INITIALIZER_LIST( |
302 tab_strip_model_(new TabStripModel(this, profile))), | 303 tab_strip_model_(new TabStripModel(this, profile))), |
303 app_type_(APP_TYPE_HOST), | 304 app_type_(APP_TYPE_HOST), |
304 chrome_updater_factory_(this), | 305 chrome_updater_factory_(this), |
305 is_attempting_to_close_browser_(false), | |
306 cancel_download_confirmation_state_(NOT_PROMPTED), | 306 cancel_download_confirmation_state_(NOT_PROMPTED), |
307 initial_show_state_(ui::SHOW_STATE_DEFAULT), | 307 initial_show_state_(ui::SHOW_STATE_DEFAULT), |
308 is_session_restore_(false), | 308 is_session_restore_(false), |
| 309 ALLOW_THIS_IN_INITIALIZER_LIST( |
| 310 unload_controller_(new chrome::UnloadController(this))), |
309 weak_factory_(this), | 311 weak_factory_(this), |
310 ALLOW_THIS_IN_INITIALIZER_LIST( | 312 ALLOW_THIS_IN_INITIALIZER_LIST( |
311 content_setting_bubble_model_delegate_( | 313 content_setting_bubble_model_delegate_( |
312 new BrowserContentSettingBubbleModelDelegate(this))), | 314 new BrowserContentSettingBubbleModelDelegate(this))), |
313 ALLOW_THIS_IN_INITIALIZER_LIST( | 315 ALLOW_THIS_IN_INITIALIZER_LIST( |
314 toolbar_model_delegate_( | 316 toolbar_model_delegate_( |
315 new BrowserToolbarModelDelegate(this))), | 317 new BrowserToolbarModelDelegate(this))), |
316 ALLOW_THIS_IN_INITIALIZER_LIST( | 318 ALLOW_THIS_IN_INITIALIZER_LIST( |
317 tab_restore_service_delegate_( | 319 tab_restore_service_delegate_( |
318 new BrowserTabRestoreServiceDelegate(this))), | 320 new BrowserTabRestoreServiceDelegate(this))), |
(...skipping 249 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
568 } | 570 } |
569 } | 571 } |
570 | 572 |
571 /////////////////////////////////////////////////////////////////////////////// | 573 /////////////////////////////////////////////////////////////////////////////// |
572 // Browser, OnBeforeUnload handling: | 574 // Browser, OnBeforeUnload handling: |
573 | 575 |
574 bool Browser::ShouldCloseWindow() { | 576 bool Browser::ShouldCloseWindow() { |
575 if (!CanCloseWithInProgressDownloads()) | 577 if (!CanCloseWithInProgressDownloads()) |
576 return false; | 578 return false; |
577 | 579 |
578 if (HasCompletedUnloadProcessing()) | 580 return unload_controller_->ShouldCloseWindow(); |
579 return true; | 581 } |
580 | 582 |
581 is_attempting_to_close_browser_ = true; | 583 bool Browser::IsAttemptingToCloseBrowser() const { |
582 | 584 return unload_controller_->is_attempting_to_close_browser(); |
583 if (!TabsNeedBeforeUnloadFired()) | |
584 return true; | |
585 | |
586 ProcessPendingTabs(); | |
587 return false; | |
588 } | 585 } |
589 | 586 |
590 void Browser::OnWindowClosing() { | 587 void Browser::OnWindowClosing() { |
591 if (!ShouldCloseWindow()) | 588 if (!ShouldCloseWindow()) |
592 return; | 589 return; |
593 | 590 |
594 bool exiting = false; | 591 bool exiting = false; |
595 | 592 |
596 // Application should shutdown on last window close if the user is explicitly | 593 // Application should shutdown on last window close if the user is explicitly |
597 // trying to quit, or if there is nothing keeping the browser alive (such as | 594 // trying to quit, or if there is nothing keeping the browser alive (such as |
(...skipping 64 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
662 // Show the download page so the user can figure-out what downloads are still | 659 // Show the download page so the user can figure-out what downloads are still |
663 // in-progress. | 660 // in-progress. |
664 chrome::ShowDownloads(this); | 661 chrome::ShowDownloads(this); |
665 } | 662 } |
666 | 663 |
667 Browser::DownloadClosePreventionType Browser::OkToCloseWithInProgressDownloads( | 664 Browser::DownloadClosePreventionType Browser::OkToCloseWithInProgressDownloads( |
668 int* num_downloads_blocking) const { | 665 int* num_downloads_blocking) const { |
669 DCHECK(num_downloads_blocking); | 666 DCHECK(num_downloads_blocking); |
670 *num_downloads_blocking = 0; | 667 *num_downloads_blocking = 0; |
671 | 668 |
672 if (is_attempting_to_close_browser_) | 669 if (IsAttemptingToCloseBrowser()) |
673 return DOWNLOAD_CLOSE_OK; | 670 return DOWNLOAD_CLOSE_OK; |
674 | 671 |
675 // If we're not running a full browser process with a profile manager | 672 // If we're not running a full browser process with a profile manager |
676 // (testing), it's ok to close the browser. | 673 // (testing), it's ok to close the browser. |
677 if (!g_browser_process->profile_manager()) | 674 if (!g_browser_process->profile_manager()) |
678 return DOWNLOAD_CLOSE_OK; | 675 return DOWNLOAD_CLOSE_OK; |
679 | 676 |
680 int total_download_count = DownloadService::DownloadCountAllProfiles(); | 677 int total_download_count = DownloadService::DownloadCountAllProfiles(); |
681 if (total_download_count == 0) | 678 if (total_download_count == 0) |
682 return DOWNLOAD_CLOSE_OK; // No downloads; can definitely close. | 679 return DOWNLOAD_CLOSE_OK; // No downloads; can definitely close. |
683 | 680 |
684 // Figure out how many windows are open total, and associated with this | 681 // Figure out how many windows are open total, and associated with this |
685 // profile, that are relevant for the ok-to-close decision. | 682 // profile, that are relevant for the ok-to-close decision. |
686 int profile_window_count = 0; | 683 int profile_window_count = 0; |
687 int total_window_count = 0; | 684 int total_window_count = 0; |
688 for (BrowserList::const_iterator iter = BrowserList::begin(); | 685 for (BrowserList::const_iterator iter = BrowserList::begin(); |
689 iter != BrowserList::end(); ++iter) { | 686 iter != BrowserList::end(); ++iter) { |
690 // Don't count this browser window or any other in the process of closing. | 687 // Don't count this browser window or any other in the process of closing. |
691 Browser* const browser = *iter; | 688 Browser* const browser = *iter; |
692 // Check is_attempting_to_close_browser_ as window closing may be | 689 // Window closing may be delayed, and windows that are in the process of |
693 // delayed, and windows that are in the process of closing don't | 690 // closing don't count against our totals. |
694 // count against our totals. | 691 if (browser == this || browser->IsAttemptingToCloseBrowser()) |
695 if (browser == this || browser->is_attempting_to_close_browser_) | |
696 continue; | 692 continue; |
697 | 693 |
698 if ((*iter)->profile() == profile()) | 694 if ((*iter)->profile() == profile()) |
699 profile_window_count++; | 695 profile_window_count++; |
700 total_window_count++; | 696 total_window_count++; |
701 } | 697 } |
702 | 698 |
703 // If there aren't any other windows, we're at browser shutdown, | 699 // If there aren't any other windows, we're at browser shutdown, |
704 // which would cancel all current downloads. | 700 // which would cancel all current downloads. |
705 if (total_window_count == 0) { | 701 if (total_window_count == 0) { |
(...skipping 464 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1170 bool foreground) { | 1166 bool foreground) { |
1171 SetAsDelegate(contents, this); | 1167 SetAsDelegate(contents, this); |
1172 contents->restore_tab_helper()->SetWindowID(session_id()); | 1168 contents->restore_tab_helper()->SetWindowID(session_id()); |
1173 | 1169 |
1174 SyncHistoryWithTabs(index); | 1170 SyncHistoryWithTabs(index); |
1175 | 1171 |
1176 // Make sure the loading state is updated correctly, otherwise the throbber | 1172 // Make sure the loading state is updated correctly, otherwise the throbber |
1177 // won't start if the page is loading. | 1173 // won't start if the page is loading. |
1178 LoadingStateChanged(contents->web_contents()); | 1174 LoadingStateChanged(contents->web_contents()); |
1179 | 1175 |
1180 // If the tab crashes in the beforeunload or unload handler, it won't be | |
1181 // able to ack. But we know we can close it. | |
1182 registrar_.Add(this, content::NOTIFICATION_WEB_CONTENTS_DISCONNECTED, | |
1183 content::Source<WebContents>(contents->web_contents())); | |
1184 | |
1185 registrar_.Add(this, content::NOTIFICATION_INTERSTITIAL_ATTACHED, | 1176 registrar_.Add(this, content::NOTIFICATION_INTERSTITIAL_ATTACHED, |
1186 content::Source<WebContents>(contents->web_contents())); | 1177 content::Source<WebContents>(contents->web_contents())); |
1187 | 1178 |
1188 registrar_.Add(this, content::NOTIFICATION_INTERSTITIAL_DETACHED, | 1179 registrar_.Add(this, content::NOTIFICATION_INTERSTITIAL_DETACHED, |
1189 content::Source<WebContents>(contents->web_contents())); | 1180 content::Source<WebContents>(contents->web_contents())); |
1190 } | 1181 } |
1191 | 1182 |
1192 void Browser::TabClosingAt(TabStripModel* tab_strip_model, | 1183 void Browser::TabClosingAt(TabStripModel* tab_strip_model, |
1193 TabContents* contents, | 1184 TabContents* contents, |
1194 int index) { | 1185 int index) { |
(...skipping 148 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1343 | 1334 |
1344 void Browser::TabStripEmpty() { | 1335 void Browser::TabStripEmpty() { |
1345 // Close the frame after we return to the message loop (not immediately, | 1336 // Close the frame after we return to the message loop (not immediately, |
1346 // otherwise it will destroy this object before the stack has a chance to | 1337 // otherwise it will destroy this object before the stack has a chance to |
1347 // cleanly unwind.) | 1338 // cleanly unwind.) |
1348 // Note: This will be called several times if TabStripEmpty is called several | 1339 // Note: This will be called several times if TabStripEmpty is called several |
1349 // times. This is because it does not close the window if tabs are | 1340 // times. This is because it does not close the window if tabs are |
1350 // still present. | 1341 // still present. |
1351 MessageLoop::current()->PostTask( | 1342 MessageLoop::current()->PostTask( |
1352 FROM_HERE, base::Bind(&Browser::CloseFrame, weak_factory_.GetWeakPtr())); | 1343 FROM_HERE, base::Bind(&Browser::CloseFrame, weak_factory_.GetWeakPtr())); |
1353 // Set is_attempting_to_close_browser_ here, so that extensions, etc, do not | |
1354 // attempt to add tabs to the browser before it closes. | |
1355 is_attempting_to_close_browser_ = true; | |
1356 } | 1344 } |
1357 | 1345 |
1358 bool Browser::PreHandleKeyboardEvent(const NativeWebKeyboardEvent& event, | 1346 bool Browser::PreHandleKeyboardEvent(const NativeWebKeyboardEvent& event, |
1359 bool* is_keyboard_shortcut) { | 1347 bool* is_keyboard_shortcut) { |
1360 // Escape exits tabbed fullscreen mode. | 1348 // Escape exits tabbed fullscreen mode. |
1361 // TODO(koz): Write a test for this http://crbug.com/100441. | 1349 // TODO(koz): Write a test for this http://crbug.com/100441. |
1362 if (event.windowsKeyCode == 27 && | 1350 if (event.windowsKeyCode == 27 && |
1363 fullscreen_controller_->HandleUserPressedEscape()) { | 1351 fullscreen_controller_->HandleUserPressedEscape()) { |
1364 return true; | 1352 return true; |
1365 } | 1353 } |
1366 return window()->PreHandleKeyboardEvent(event, is_keyboard_shortcut); | 1354 return window()->PreHandleKeyboardEvent(event, is_keyboard_shortcut); |
1367 } | 1355 } |
1368 | 1356 |
1369 void Browser::HandleKeyboardEvent(const NativeWebKeyboardEvent& event) { | 1357 void Browser::HandleKeyboardEvent(const NativeWebKeyboardEvent& event) { |
1370 window()->HandleKeyboardEvent(event); | 1358 window()->HandleKeyboardEvent(event); |
1371 } | 1359 } |
1372 | 1360 |
1373 void Browser::OnAcceptFullscreenPermission( | 1361 void Browser::OnAcceptFullscreenPermission( |
1374 const GURL& url, | 1362 const GURL& url, |
1375 FullscreenExitBubbleType bubble_type) { | 1363 FullscreenExitBubbleType bubble_type) { |
1376 fullscreen_controller_->OnAcceptFullscreenPermission(url, bubble_type); | 1364 fullscreen_controller_->OnAcceptFullscreenPermission(url, bubble_type); |
1377 } | 1365 } |
1378 | 1366 |
1379 void Browser::OnDenyFullscreenPermission(FullscreenExitBubbleType bubble_type) { | 1367 void Browser::OnDenyFullscreenPermission(FullscreenExitBubbleType bubble_type) { |
1380 fullscreen_controller_->OnDenyFullscreenPermission(bubble_type); | 1368 fullscreen_controller_->OnDenyFullscreenPermission(bubble_type); |
1381 } | 1369 } |
1382 | 1370 |
1383 bool Browser::TabsNeedBeforeUnloadFired() { | 1371 bool Browser::TabsNeedBeforeUnloadFired() { |
1384 if (tabs_needing_before_unload_fired_.empty()) { | 1372 return unload_controller_->TabsNeedBeforeUnloadFired(); |
1385 for (int i = 0; i < tab_count(); ++i) { | |
1386 WebContents* contents = chrome::GetTabContentsAt(this, i)->web_contents(); | |
1387 if (contents->NeedToFireBeforeUnload()) | |
1388 tabs_needing_before_unload_fired_.insert(contents); | |
1389 } | |
1390 } | |
1391 return !tabs_needing_before_unload_fired_.empty(); | |
1392 } | 1373 } |
1393 | 1374 |
1394 bool Browser::IsFullscreenForTabOrPending() const { | 1375 bool Browser::IsFullscreenForTabOrPending() const { |
1395 return fullscreen_controller_->IsFullscreenForTabOrPending(); | 1376 return fullscreen_controller_->IsFullscreenForTabOrPending(); |
1396 } | 1377 } |
1397 | 1378 |
1398 bool Browser::IsMouseLocked() const { | 1379 bool Browser::IsMouseLocked() const { |
1399 return fullscreen_controller_->IsMouseLocked(); | 1380 return fullscreen_controller_->IsMouseLocked(); |
1400 } | 1381 } |
1401 | 1382 |
(...skipping 103 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1505 command_controller_->LoadingStateChanged(is_loading, false); | 1486 command_controller_->LoadingStateChanged(is_loading, false); |
1506 if (GetStatusBubble()) { | 1487 if (GetStatusBubble()) { |
1507 GetStatusBubble()->SetStatus( | 1488 GetStatusBubble()->SetStatus( |
1508 chrome::GetActiveTabContents(this)->core_tab_helper()-> | 1489 chrome::GetActiveTabContents(this)->core_tab_helper()-> |
1509 GetStatusText()); | 1490 GetStatusText()); |
1510 } | 1491 } |
1511 } | 1492 } |
1512 } | 1493 } |
1513 | 1494 |
1514 void Browser::CloseContents(WebContents* source) { | 1495 void Browser::CloseContents(WebContents* source) { |
1515 if (is_attempting_to_close_browser_) { | 1496 if (unload_controller_->CanCloseContents(source)) |
1516 // If we're trying to close the browser, just clear the state related to | 1497 chrome::CloseWebContents(this, source); |
1517 // waiting for unload to fire. Don't actually try to close the tab as it | |
1518 // will go down the slow shutdown path instead of the fast path of killing | |
1519 // all the renderer processes. | |
1520 ClearUnloadState(source, true); | |
1521 return; | |
1522 } | |
1523 | |
1524 chrome::CloseWebContents(this, source); | |
1525 } | 1498 } |
1526 | 1499 |
1527 void Browser::MoveContents(WebContents* source, const gfx::Rect& pos) { | 1500 void Browser::MoveContents(WebContents* source, const gfx::Rect& pos) { |
1528 if (!IsPopupOrPanel(source)) { | 1501 if (!IsPopupOrPanel(source)) { |
1529 NOTREACHED() << "moving invalid browser type"; | 1502 NOTREACHED() << "moving invalid browser type"; |
1530 return; | 1503 return; |
1531 } | 1504 } |
1532 window_->SetBounds(pos); | 1505 window_->SetBounds(pos); |
1533 } | 1506 } |
1534 | 1507 |
(...skipping 45 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1580 return is_app(); | 1553 return is_app(); |
1581 } | 1554 } |
1582 | 1555 |
1583 gfx::Rect Browser::GetRootWindowResizerRect() const { | 1556 gfx::Rect Browser::GetRootWindowResizerRect() const { |
1584 return window_->GetRootWindowResizerRect(); | 1557 return window_->GetRootWindowResizerRect(); |
1585 } | 1558 } |
1586 | 1559 |
1587 void Browser::BeforeUnloadFired(WebContents* web_contents, | 1560 void Browser::BeforeUnloadFired(WebContents* web_contents, |
1588 bool proceed, | 1561 bool proceed, |
1589 bool* proceed_to_fire_unload) { | 1562 bool* proceed_to_fire_unload) { |
1590 if (!is_attempting_to_close_browser_) { | 1563 *proceed_to_fire_unload = |
1591 *proceed_to_fire_unload = proceed; | 1564 unload_controller_->BeforeUnloadFired(web_contents, proceed); |
1592 if (!proceed) | |
1593 web_contents->SetClosedByUserGesture(false); | |
1594 return; | |
1595 } | |
1596 | |
1597 if (!proceed) { | |
1598 CancelWindowClose(); | |
1599 *proceed_to_fire_unload = false; | |
1600 web_contents->SetClosedByUserGesture(false); | |
1601 return; | |
1602 } | |
1603 | |
1604 if (RemoveFromSet(&tabs_needing_before_unload_fired_, web_contents)) { | |
1605 // Now that beforeunload has fired, put the tab on the queue to fire | |
1606 // unload. | |
1607 tabs_needing_unload_fired_.insert(web_contents); | |
1608 ProcessPendingTabs(); | |
1609 // We want to handle firing the unload event ourselves since we want to | |
1610 // fire all the beforeunload events before attempting to fire the unload | |
1611 // events should the user cancel closing the browser. | |
1612 *proceed_to_fire_unload = false; | |
1613 return; | |
1614 } | |
1615 | |
1616 *proceed_to_fire_unload = true; | |
1617 } | 1565 } |
1618 | 1566 |
1619 void Browser::SetFocusToLocationBar(bool select_all) { | 1567 void Browser::SetFocusToLocationBar(bool select_all) { |
1620 // Two differences between this and FocusLocationBar(): | 1568 // Two differences between this and FocusLocationBar(): |
1621 // (1) This doesn't get recorded in user metrics, since it's called | 1569 // (1) This doesn't get recorded in user metrics, since it's called |
1622 // internally. | 1570 // internally. |
1623 // (2) This checks whether the location bar can be focused, and if not, clears | 1571 // (2) This checks whether the location bar can be focused, and if not, clears |
1624 // the focus. FocusLocationBar() is only reached when the location bar is | 1572 // the focus. FocusLocationBar() is only reached when the location bar is |
1625 // focusable, but this may be reached at other times, e.g. while in | 1573 // focusable, but this may be reached at other times, e.g. while in |
1626 // fullscreen mode, where we need to leave focus in a consistent state. | 1574 // fullscreen mode, where we need to leave focus in a consistent state. |
(...skipping 407 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
2034 false)); | 1982 false)); |
2035 } | 1983 } |
2036 | 1984 |
2037 /////////////////////////////////////////////////////////////////////////////// | 1985 /////////////////////////////////////////////////////////////////////////////// |
2038 // Browser, content::NotificationObserver implementation: | 1986 // Browser, content::NotificationObserver implementation: |
2039 | 1987 |
2040 void Browser::Observe(int type, | 1988 void Browser::Observe(int type, |
2041 const content::NotificationSource& source, | 1989 const content::NotificationSource& source, |
2042 const content::NotificationDetails& details) { | 1990 const content::NotificationDetails& details) { |
2043 switch (type) { | 1991 switch (type) { |
2044 case content::NOTIFICATION_WEB_CONTENTS_DISCONNECTED: | |
2045 if (is_attempting_to_close_browser_) { | |
2046 // Pass in false so that we delay processing. We need to delay the | |
2047 // processing as it may close the tab, which is currently on the call | |
2048 // stack above us. | |
2049 ClearUnloadState(content::Source<WebContents>(source).ptr(), false); | |
2050 } | |
2051 break; | |
2052 | |
2053 case content::NOTIFICATION_SSL_VISIBLE_STATE_CHANGED: | 1992 case content::NOTIFICATION_SSL_VISIBLE_STATE_CHANGED: |
2054 // When the current tab's SSL state changes, we need to update the URL | 1993 // When the current tab's SSL state changes, we need to update the URL |
2055 // bar to reflect the new state. Note that it's possible for the selected | 1994 // bar to reflect the new state. Note that it's possible for the selected |
2056 // tab contents to be NULL. This is because we listen for all sources | 1995 // tab contents to be NULL. This is because we listen for all sources |
2057 // (NavigationControllers) for convenience, so the notification could | 1996 // (NavigationControllers) for convenience, so the notification could |
2058 // actually be for a different window while we're doing asynchronous | 1997 // actually be for a different window while we're doing asynchronous |
2059 // closing of this one. | 1998 // closing of this one. |
2060 if (chrome::GetActiveWebContents(this) && | 1999 if (chrome::GetActiveWebContents(this) && |
2061 &chrome::GetActiveWebContents(this)->GetController() == | 2000 &chrome::GetActiveWebContents(this)->GetController() == |
2062 content::Source<NavigationController>(source).ptr()) | 2001 content::Source<NavigationController>(source).ptr()) |
(...skipping 326 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
2389 session_service->SetPinnedState( | 2328 session_service->SetPinnedState( |
2390 session_id(), | 2329 session_id(), |
2391 tab->restore_tab_helper()->session_id(), | 2330 tab->restore_tab_helper()->session_id(), |
2392 tab_strip_model_->IsTabPinned(i)); | 2331 tab_strip_model_->IsTabPinned(i)); |
2393 } | 2332 } |
2394 } | 2333 } |
2395 } | 2334 } |
2396 } | 2335 } |
2397 | 2336 |
2398 /////////////////////////////////////////////////////////////////////////////// | 2337 /////////////////////////////////////////////////////////////////////////////// |
2399 // Browser, OnBeforeUnload handling (private): | |
2400 | |
2401 void Browser::ProcessPendingTabs() { | |
2402 if (!is_attempting_to_close_browser_) { | |
2403 // Because we might invoke this after a delay it's possible for the value of | |
2404 // is_attempting_to_close_browser_ to have changed since we scheduled the | |
2405 // task. | |
2406 return; | |
2407 } | |
2408 | |
2409 if (HasCompletedUnloadProcessing()) { | |
2410 // We've finished all the unload events and can proceed to close the | |
2411 // browser. | |
2412 OnWindowClosing(); | |
2413 return; | |
2414 } | |
2415 | |
2416 // Process beforeunload tabs first. When that queue is empty, process | |
2417 // unload tabs. | |
2418 if (!tabs_needing_before_unload_fired_.empty()) { | |
2419 WebContents* web_contents = *(tabs_needing_before_unload_fired_.begin()); | |
2420 // Null check render_view_host here as this gets called on a PostTask and | |
2421 // the tab's render_view_host may have been nulled out. | |
2422 if (web_contents->GetRenderViewHost()) { | |
2423 web_contents->GetRenderViewHost()->FirePageBeforeUnload(false); | |
2424 } else { | |
2425 ClearUnloadState(web_contents, true); | |
2426 } | |
2427 } else if (!tabs_needing_unload_fired_.empty()) { | |
2428 // We've finished firing all beforeunload events and can proceed with unload | |
2429 // events. | |
2430 // TODO(ojan): We should add a call to browser_shutdown::OnShutdownStarting | |
2431 // somewhere around here so that we have accurate measurements of shutdown | |
2432 // time. | |
2433 // TODO(ojan): We can probably fire all the unload events in parallel and | |
2434 // get a perf benefit from that in the cases where the tab hangs in it's | |
2435 // unload handler or takes a long time to page in. | |
2436 WebContents* web_contents = *(tabs_needing_unload_fired_.begin()); | |
2437 // Null check render_view_host here as this gets called on a PostTask and | |
2438 // the tab's render_view_host may have been nulled out. | |
2439 if (web_contents->GetRenderViewHost()) { | |
2440 web_contents->GetRenderViewHost()->ClosePage(); | |
2441 } else { | |
2442 ClearUnloadState(web_contents, true); | |
2443 } | |
2444 } else { | |
2445 NOTREACHED(); | |
2446 } | |
2447 } | |
2448 | |
2449 bool Browser::HasCompletedUnloadProcessing() const { | |
2450 return is_attempting_to_close_browser_ && | |
2451 tabs_needing_before_unload_fired_.empty() && | |
2452 tabs_needing_unload_fired_.empty(); | |
2453 } | |
2454 | |
2455 void Browser::CancelWindowClose() { | |
2456 // Closing of window can be canceled from a beforeunload handler. | |
2457 DCHECK(is_attempting_to_close_browser_); | |
2458 tabs_needing_before_unload_fired_.clear(); | |
2459 tabs_needing_unload_fired_.clear(); | |
2460 is_attempting_to_close_browser_ = false; | |
2461 | |
2462 content::NotificationService::current()->Notify( | |
2463 chrome::NOTIFICATION_BROWSER_CLOSE_CANCELLED, | |
2464 content::Source<Browser>(this), | |
2465 content::NotificationService::NoDetails()); | |
2466 } | |
2467 | |
2468 bool Browser::RemoveFromSet(UnloadListenerSet* set, WebContents* web_contents) { | |
2469 DCHECK(is_attempting_to_close_browser_); | |
2470 | |
2471 UnloadListenerSet::iterator iter = | |
2472 std::find(set->begin(), set->end(), web_contents); | |
2473 if (iter != set->end()) { | |
2474 set->erase(iter); | |
2475 return true; | |
2476 } | |
2477 return false; | |
2478 } | |
2479 | |
2480 void Browser::ClearUnloadState(WebContents* web_contents, bool process_now) { | |
2481 if (is_attempting_to_close_browser_) { | |
2482 RemoveFromSet(&tabs_needing_before_unload_fired_, web_contents); | |
2483 RemoveFromSet(&tabs_needing_unload_fired_, web_contents); | |
2484 if (process_now) { | |
2485 ProcessPendingTabs(); | |
2486 } else { | |
2487 MessageLoop::current()->PostTask( | |
2488 FROM_HERE, | |
2489 base::Bind(&Browser::ProcessPendingTabs, weak_factory_.GetWeakPtr())); | |
2490 } | |
2491 } | |
2492 } | |
2493 | |
2494 /////////////////////////////////////////////////////////////////////////////// | |
2495 // Browser, In-progress download termination handling (private): | 2338 // Browser, In-progress download termination handling (private): |
2496 | 2339 |
2497 bool Browser::CanCloseWithInProgressDownloads() { | 2340 bool Browser::CanCloseWithInProgressDownloads() { |
2498 // If we've prompted, we need to hear from the user before we | 2341 // If we've prompted, we need to hear from the user before we |
2499 // can close. | 2342 // can close. |
2500 if (cancel_download_confirmation_state_ != NOT_PROMPTED) | 2343 if (cancel_download_confirmation_state_ != NOT_PROMPTED) |
2501 return cancel_download_confirmation_state_ != WAITING_FOR_RESPONSE; | 2344 return cancel_download_confirmation_state_ != WAITING_FOR_RESPONSE; |
2502 | 2345 |
2503 int num_downloads_blocking; | 2346 int num_downloads_blocking; |
2504 if (DOWNLOAD_CLOSE_OK == | 2347 if (DOWNLOAD_CLOSE_OK == |
(...skipping 47 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
2552 SyncHistoryWithTabs(0); | 2395 SyncHistoryWithTabs(0); |
2553 } | 2396 } |
2554 | 2397 |
2555 SetAsDelegate(contents, NULL); | 2398 SetAsDelegate(contents, NULL); |
2556 RemoveScheduledUpdatesFor(contents->web_contents()); | 2399 RemoveScheduledUpdatesFor(contents->web_contents()); |
2557 | 2400 |
2558 if (find_bar_controller_.get() && index == active_index()) { | 2401 if (find_bar_controller_.get() && index == active_index()) { |
2559 find_bar_controller_->ChangeTabContents(NULL); | 2402 find_bar_controller_->ChangeTabContents(NULL); |
2560 } | 2403 } |
2561 | 2404 |
2562 if (is_attempting_to_close_browser_) { | |
2563 // If this is the last tab with unload handlers, then ProcessPendingTabs | |
2564 // would call back into the TabStripModel (which is invoking this method on | |
2565 // us). Avoid that by passing in false so that the call to | |
2566 // ProcessPendingTabs is delayed. | |
2567 ClearUnloadState(contents->web_contents(), false); | |
2568 } | |
2569 | |
2570 // Stop observing search model changes for this tab. | 2405 // Stop observing search model changes for this tab. |
2571 search_delegate_->OnTabDetached(contents); | 2406 search_delegate_->OnTabDetached(contents); |
2572 | 2407 |
2573 registrar_.Remove(this, content::NOTIFICATION_INTERSTITIAL_ATTACHED, | 2408 registrar_.Remove(this, content::NOTIFICATION_INTERSTITIAL_ATTACHED, |
2574 content::Source<WebContents>(contents->web_contents())); | 2409 content::Source<WebContents>(contents->web_contents())); |
2575 registrar_.Remove(this, content::NOTIFICATION_INTERSTITIAL_DETACHED, | 2410 registrar_.Remove(this, content::NOTIFICATION_INTERSTITIAL_DETACHED, |
2576 content::Source<WebContents>(contents->web_contents())); | 2411 content::Source<WebContents>(contents->web_contents())); |
2577 registrar_.Remove(this, content::NOTIFICATION_WEB_CONTENTS_DISCONNECTED, | |
2578 content::Source<WebContents>(contents->web_contents())); | |
2579 } | 2412 } |
2580 | 2413 |
2581 bool Browser::SupportsWindowFeatureImpl(WindowFeature feature, | 2414 bool Browser::SupportsWindowFeatureImpl(WindowFeature feature, |
2582 bool check_fullscreen) const { | 2415 bool check_fullscreen) const { |
2583 // On Mac, fullscreen mode has most normal things (in a slide-down panel). On | 2416 // On Mac, fullscreen mode has most normal things (in a slide-down panel). On |
2584 // other platforms, we hide some controls when in fullscreen mode. | 2417 // other platforms, we hide some controls when in fullscreen mode. |
2585 bool hide_ui_for_fullscreen = false; | 2418 bool hide_ui_for_fullscreen = false; |
2586 #if !defined(OS_MACOSX) | 2419 #if !defined(OS_MACOSX) |
2587 hide_ui_for_fullscreen = check_fullscreen && window_ && | 2420 hide_ui_for_fullscreen = check_fullscreen && window_ && |
2588 window_->IsFullscreen(); | 2421 window_->IsFullscreen(); |
(...skipping 142 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
2731 if (contents && !allow_js_access) { | 2564 if (contents && !allow_js_access) { |
2732 contents->web_contents()->GetController().LoadURL( | 2565 contents->web_contents()->GetController().LoadURL( |
2733 target_url, | 2566 target_url, |
2734 content::Referrer(), | 2567 content::Referrer(), |
2735 content::PAGE_TRANSITION_LINK, | 2568 content::PAGE_TRANSITION_LINK, |
2736 std::string()); // No extra headers. | 2569 std::string()); // No extra headers. |
2737 } | 2570 } |
2738 | 2571 |
2739 return contents != NULL; | 2572 return contents != NULL; |
2740 } | 2573 } |
OLD | NEW |