Home | History | Annotate | Download | only in views
      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 <set>
      6 
      7 #include "base/memory/scoped_ptr.h"
      8 #include "chrome/browser/platform_util.h"
      9 #include "chrome/browser/ui/views/constrained_window_views.h"
     10 #include "components/web_modal/single_web_contents_dialog_manager.h"
     11 #include "components/web_modal/web_contents_modal_dialog_host.h"
     12 #include "components/web_modal/web_contents_modal_dialog_manager.h"
     13 #include "ui/gfx/point.h"
     14 #include "ui/gfx/size.h"
     15 #include "ui/views/border.h"
     16 #include "ui/views/widget/widget.h"
     17 #include "ui/views/widget/widget_delegate.h"
     18 #include "ui/views/widget/widget_observer.h"
     19 #include "ui/views/window/dialog_delegate.h"
     20 #include "ui/views/window/non_client_view.h"
     21 
     22 #if defined(USE_AURA)
     23 #include "ui/aura/client/aura_constants.h"
     24 #include "ui/aura/window.h"
     25 #include "ui/wm/core/visibility_controller.h"
     26 #include "ui/wm/core/window_animations.h"
     27 #include "ui/wm/core/window_modality_controller.h"
     28 #endif
     29 
     30 // TODO(wittman): this code should not depend on ash.
     31 #if defined(USE_ASH)
     32 #include "ash/ash_constants.h"
     33 #include "ash/frame/custom_frame_view_ash.h"
     34 #include "ash/shell.h"
     35 #endif
     36 
     37 using web_modal::NativeWebContentsModalDialog;
     38 using web_modal::SingleWebContentsDialogManager;
     39 using web_modal::SingleWebContentsDialogManagerDelegate;
     40 using web_modal::WebContentsModalDialogHost;
     41 using web_modal::ModalDialogHostObserver;
     42 
     43 namespace {
     44 
     45 class NativeWebContentsModalDialogManagerViews
     46     : public SingleWebContentsDialogManager,
     47       public ModalDialogHostObserver,
     48       public views::WidgetObserver {
     49  public:
     50   NativeWebContentsModalDialogManagerViews(
     51       NativeWebContentsModalDialog dialog,
     52       SingleWebContentsDialogManagerDelegate* native_delegate)
     53       : native_delegate_(native_delegate),
     54         dialog_(dialog),
     55         host_(NULL) {
     56     ManageDialog();
     57   }
     58 
     59   virtual ~NativeWebContentsModalDialogManagerViews() {
     60     if (host_)
     61       host_->RemoveObserver(this);
     62 
     63     for (std::set<views::Widget*>::iterator it = observed_widgets_.begin();
     64          it != observed_widgets_.end();
     65          ++it) {
     66       (*it)->RemoveObserver(this);
     67     }
     68   }
     69 
     70   // Sets up this object to manage the dialog_. Registers for closing events
     71   // in order to notify the delegate.
     72   virtual void ManageDialog() {
     73     views::Widget* widget = GetWidget(dialog());
     74     widget->AddObserver(this);
     75     observed_widgets_.insert(widget);
     76     widget->set_movement_disabled(true);
     77 
     78 #if defined(USE_AURA)
     79     // TODO(wittman): remove once the new visual style is complete
     80     widget->GetNativeWindow()->SetProperty(aura::client::kConstrainedWindowKey,
     81                                            true);
     82 
     83     wm::SetWindowVisibilityAnimationType(
     84         widget->GetNativeWindow(),
     85         wm::WINDOW_VISIBILITY_ANIMATION_TYPE_ROTATE);
     86 #endif
     87 
     88 #if defined(USE_ASH)
     89     gfx::NativeView parent = platform_util::GetParent(widget->GetNativeView());
     90     wm::SetChildWindowVisibilityChangesAnimated(parent);
     91     // No animations should get performed on the window since that will re-order
     92     // the window stack which will then cause many problems.
     93     if (parent && parent->parent()) {
     94       parent->parent()->SetProperty(aura::client::kAnimationsDisabledKey, true);
     95     }
     96 
     97     wm::SetModalParent(
     98         widget->GetNativeWindow(),
     99         platform_util::GetParent(widget->GetNativeView()));
    100 #endif
    101   }
    102 
    103   // SingleWebContentsDialogManager overrides
    104   virtual void Show() OVERRIDE {
    105     views::Widget* widget = GetWidget(dialog());
    106 #if defined(USE_AURA)
    107     scoped_ptr<wm::SuspendChildWindowVisibilityAnimations> suspend;
    108     if (shown_widgets_.find(widget) != shown_widgets_.end()) {
    109       suspend.reset(new wm::SuspendChildWindowVisibilityAnimations(
    110           widget->GetNativeWindow()->parent()));
    111     }
    112 #endif
    113     // Host may be NULL during tab drag on Views/Win32.
    114     if (host_)
    115       UpdateWebContentsModalDialogPosition(widget, host_);
    116     widget->Show();
    117     Focus();
    118 
    119 #if defined(USE_AURA)
    120     // TODO(pkotwicz): Control the z-order of the constrained dialog via
    121     // views::kHostViewKey. We will need to ensure that the parent window's
    122     // shadows are below the constrained dialog in z-order when we do this.
    123     shown_widgets_.insert(widget);
    124 #endif
    125   }
    126 
    127   virtual void Hide() OVERRIDE {
    128     views::Widget* widget = GetWidget(dialog());
    129 #if defined(USE_AURA)
    130     scoped_ptr<wm::SuspendChildWindowVisibilityAnimations> suspend;
    131     suspend.reset(new wm::SuspendChildWindowVisibilityAnimations(
    132         widget->GetNativeWindow()->parent()));
    133 #endif
    134     widget->Hide();
    135   }
    136 
    137   virtual void Close() OVERRIDE {
    138     GetWidget(dialog())->Close();
    139   }
    140 
    141   virtual void Focus() OVERRIDE {
    142     views::Widget* widget = GetWidget(dialog());
    143     if (widget->widget_delegate() &&
    144         widget->widget_delegate()->GetInitiallyFocusedView())
    145       widget->widget_delegate()->GetInitiallyFocusedView()->RequestFocus();
    146 #if defined(USE_ASH)
    147     // We don't necessarily have a RootWindow yet.
    148     if (widget->GetNativeView()->GetRootWindow())
    149       widget->GetNativeView()->Focus();
    150 #endif
    151   }
    152 
    153   virtual void Pulse() OVERRIDE {
    154   }
    155 
    156   // WebContentsModalDialogHostObserver overrides
    157   virtual void OnPositionRequiresUpdate() OVERRIDE {
    158     DCHECK(host_);
    159 
    160     for (std::set<views::Widget*>::iterator it = observed_widgets_.begin();
    161          it != observed_widgets_.end();
    162          ++it) {
    163       UpdateWebContentsModalDialogPosition(*it, host_);
    164     }
    165   }
    166 
    167   virtual void OnHostDestroying() OVERRIDE {
    168     host_->RemoveObserver(this);
    169     host_ = NULL;
    170   }
    171 
    172   // views::WidgetObserver overrides
    173 
    174   // NOTE(wittman): OnWidgetClosing is overriden to ensure that, when the widget
    175   // is explicitly closed, the destruction occurs within the same call
    176   // stack. This avoids event races that lead to non-deterministic destruction
    177   // ordering in e.g. the print preview dialog. OnWidgetDestroying is overridden
    178   // because OnWidgetClosing is *only* invoked on explicit close, not when the
    179   // widget is implicitly destroyed due to its parent being closed. This
    180   // situation occurs with app windows.  WidgetClosing removes the observer, so
    181   // only one of these two functions is ever invoked for a given widget.
    182   virtual void OnWidgetClosing(views::Widget* widget) OVERRIDE {
    183     WidgetClosing(widget);
    184   }
    185 
    186   virtual void OnWidgetDestroying(views::Widget* widget) OVERRIDE {
    187     WidgetClosing(widget);
    188   }
    189 
    190   virtual void HostChanged(
    191       web_modal::WebContentsModalDialogHost* new_host) OVERRIDE {
    192     if (host_)
    193       host_->RemoveObserver(this);
    194 
    195     host_ = new_host;
    196 
    197     // |host_| may be null during WebContents destruction or Win32 tab dragging.
    198     if (host_) {
    199       host_->AddObserver(this);
    200 
    201       for (std::set<views::Widget*>::iterator it = observed_widgets_.begin();
    202            it != observed_widgets_.end();
    203            ++it) {
    204         views::Widget::ReparentNativeView((*it)->GetNativeView(),
    205                                           host_->GetHostView());
    206       }
    207 
    208       OnPositionRequiresUpdate();
    209     }
    210   }
    211 
    212   virtual NativeWebContentsModalDialog dialog() OVERRIDE {
    213     return dialog_;
    214   }
    215 
    216  private:
    217   static views::Widget* GetWidget(NativeWebContentsModalDialog dialog) {
    218     views::Widget* widget = views::Widget::GetWidgetForNativeWindow(dialog);
    219     DCHECK(widget);
    220     return widget;
    221   }
    222 
    223   void WidgetClosing(views::Widget* widget) {
    224 #if defined(USE_ASH)
    225     gfx::NativeView view = platform_util::GetParent(widget->GetNativeView());
    226     // Allow the parent to animate again.
    227     if (view && view->parent())
    228       view->parent()->ClearProperty(aura::client::kAnimationsDisabledKey);
    229 #endif
    230     widget->RemoveObserver(this);
    231     observed_widgets_.erase(widget);
    232 
    233 #if defined(USE_AURA)
    234     shown_widgets_.erase(widget);
    235 #endif
    236 
    237     // Will cause this object to be deleted.
    238     native_delegate_->WillClose(widget->GetNativeView());
    239   }
    240 
    241   SingleWebContentsDialogManagerDelegate* native_delegate_;
    242   NativeWebContentsModalDialog dialog_;
    243   WebContentsModalDialogHost* host_;
    244   std::set<views::Widget*> observed_widgets_;
    245   std::set<views::Widget*> shown_widgets_;
    246 
    247   DISALLOW_COPY_AND_ASSIGN(NativeWebContentsModalDialogManagerViews);
    248 };
    249 
    250 }  // namespace
    251 
    252 namespace web_modal {
    253 
    254 SingleWebContentsDialogManager* WebContentsModalDialogManager::
    255 CreateNativeWebModalManager(
    256     NativeWebContentsModalDialog dialog,
    257     SingleWebContentsDialogManagerDelegate* native_delegate) {
    258   return new NativeWebContentsModalDialogManagerViews(dialog, native_delegate);
    259 }
    260 
    261 }  // namespace web_modal
    262