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