Home | History | Annotate | Download | only in web_modal
      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
      3 // found in the LICENSE file.
      4 
      5 #include "components/web_modal/web_contents_modal_dialog_manager.h"
      6 
      7 #include "components/web_modal/web_contents_modal_dialog_manager_delegate.h"
      8 #include "content/public/browser/navigation_details.h"
      9 #include "content/public/browser/navigation_entry.h"
     10 #include "content/public/browser/notification_details.h"
     11 #include "content/public/browser/notification_source.h"
     12 #include "content/public/browser/notification_types.h"
     13 #include "content/public/browser/render_view_host.h"
     14 #include "content/public/browser/web_contents.h"
     15 #include "content/public/browser/web_contents_view.h"
     16 #include "net/base/registry_controlled_domains/registry_controlled_domain.h"
     17 
     18 using content::WebContents;
     19 
     20 DEFINE_WEB_CONTENTS_USER_DATA_KEY(web_modal::WebContentsModalDialogManager);
     21 
     22 namespace web_modal {
     23 
     24 WebContentsModalDialogManager::~WebContentsModalDialogManager() {
     25   DCHECK(child_dialogs_.empty());
     26 }
     27 
     28 void WebContentsModalDialogManager::ShowDialog(
     29     NativeWebContentsModalDialog dialog) {
     30   child_dialogs_.push_back(dialog);
     31 
     32   native_manager_->ManageDialog(dialog);
     33 
     34   if (child_dialogs_.size() == 1) {
     35     if (delegate_ && delegate_->IsWebContentsVisible(web_contents()))
     36       native_manager_->ShowDialog(dialog);
     37     BlockWebContentsInteraction(true);
     38   }
     39 }
     40 
     41 bool WebContentsModalDialogManager::IsShowingDialog() const {
     42   return !child_dialogs_.empty();
     43 }
     44 
     45 void WebContentsModalDialogManager::FocusTopmostDialog() {
     46   DCHECK(!child_dialogs_.empty());
     47   native_manager_->FocusDialog(child_dialogs_.front());
     48 }
     49 
     50 content::WebContents* WebContentsModalDialogManager::GetWebContents() const {
     51   return web_contents();
     52 }
     53 
     54 void WebContentsModalDialogManager::WillClose(
     55     NativeWebContentsModalDialog dialog) {
     56   WebContentsModalDialogList::iterator i(
     57       std::find(child_dialogs_.begin(), child_dialogs_.end(), dialog));
     58 
     59   // The Views tab contents modal dialog calls WillClose twice.  Ignore the
     60   // second invocation.
     61   if (i == child_dialogs_.end())
     62     return;
     63 
     64   bool removed_topmost_dialog = i == child_dialogs_.begin();
     65   child_dialogs_.erase(i);
     66   if (!child_dialogs_.empty() && removed_topmost_dialog &&
     67       !closing_all_dialogs_)
     68     native_manager_->ShowDialog(child_dialogs_.front());
     69 
     70   BlockWebContentsInteraction(!child_dialogs_.empty());
     71 }
     72 
     73 void WebContentsModalDialogManager::Observe(
     74     int type,
     75     const content::NotificationSource& source,
     76     const content::NotificationDetails& details) {
     77   DCHECK(type == content::NOTIFICATION_WEB_CONTENTS_VISIBILITY_CHANGED);
     78 
     79   if (child_dialogs_.empty())
     80     return;
     81 
     82   bool visible = *content::Details<bool>(details).ptr();
     83   if (visible)
     84     native_manager_->ShowDialog(child_dialogs_.front());
     85   else
     86     native_manager_->HideDialog(child_dialogs_.front());
     87 }
     88 
     89 WebContentsModalDialogManager::WebContentsModalDialogManager(
     90     content::WebContents* web_contents)
     91     : content::WebContentsObserver(web_contents),
     92       delegate_(NULL),
     93       native_manager_(CreateNativeManager(this)),
     94       closing_all_dialogs_(false) {
     95   DCHECK(native_manager_);
     96   registrar_.Add(this,
     97                  content::NOTIFICATION_WEB_CONTENTS_VISIBILITY_CHANGED,
     98                  content::Source<content::WebContents>(web_contents));
     99 }
    100 
    101 void WebContentsModalDialogManager::BlockWebContentsInteraction(bool blocked) {
    102   WebContents* contents = web_contents();
    103   if (!contents) {
    104     // The WebContents has already disconnected.
    105     return;
    106   }
    107 
    108   // RenderViewHost may be NULL during shutdown.
    109   content::RenderViewHost* host = contents->GetRenderViewHost();
    110   if (host)
    111     host->SetIgnoreInputEvents(blocked);
    112   if (delegate_)
    113     delegate_->SetWebContentsBlocked(contents, blocked);
    114 }
    115 
    116 void WebContentsModalDialogManager::CloseAllDialogs() {
    117   closing_all_dialogs_ = true;
    118 
    119   // Clear out any dialogs since we are leaving this page entirely.
    120   while (!child_dialogs_.empty())
    121     native_manager_->CloseDialog(child_dialogs_.front());
    122 
    123   closing_all_dialogs_ = false;
    124 }
    125 
    126 void WebContentsModalDialogManager::DidNavigateMainFrame(
    127     const content::LoadCommittedDetails& details,
    128     const content::FrameNavigateParams& params) {
    129   // Close constrained windows if necessary.
    130   if (!net::registry_controlled_domains::SameDomainOrHost(
    131           details.previous_url, details.entry->GetURL(),
    132           net::registry_controlled_domains::EXCLUDE_PRIVATE_REGISTRIES))
    133     CloseAllDialogs();
    134 }
    135 
    136 void WebContentsModalDialogManager::DidGetIgnoredUIEvent() {
    137   if (!child_dialogs_.empty())
    138     native_manager_->FocusDialog(child_dialogs_.front());
    139 }
    140 
    141 void WebContentsModalDialogManager::WebContentsDestroyed(WebContents* tab) {
    142   // First cleanly close all child dialogs.
    143   // TODO(mpcomplete): handle case if MaybeCloseChildWindows() already asked
    144   // some of these to close.  CloseAllDialogs is async, so it might get called
    145   // twice before it runs.
    146   CloseAllDialogs();
    147 }
    148 
    149 }  // namespace web_modal
    150