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.
7 #include "base/memory/scoped_ptr.h"
8 #include "chrome/browser/platform_util.h"
9 #include "components/constrained_window/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/geometry/point.h"
14 #include "ui/gfx/geometry/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"
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"
30 using web_modal::SingleWebContentsDialogManager
;
31 using web_modal::SingleWebContentsDialogManagerDelegate
;
32 using web_modal::WebContentsModalDialogHost
;
33 using web_modal::ModalDialogHostObserver
;
37 class NativeWebContentsModalDialogManagerViews
38 : public SingleWebContentsDialogManager
,
39 public ModalDialogHostObserver
,
40 public views::WidgetObserver
{
42 NativeWebContentsModalDialogManagerViews(
43 gfx::NativeWindow dialog
,
44 SingleWebContentsDialogManagerDelegate
* native_delegate
)
45 : native_delegate_(native_delegate
),
51 ~NativeWebContentsModalDialogManagerViews() override
{
53 host_
->RemoveObserver(this);
55 for (std::set
<views::Widget
*>::iterator it
= observed_widgets_
.begin();
56 it
!= observed_widgets_
.end();
58 (*it
)->RemoveObserver(this);
62 // Sets up this object to manage the dialog_. Registers for closing events
63 // in order to notify the delegate.
64 virtual void ManageDialog() {
65 views::Widget
* widget
= GetWidget(dialog());
66 widget
->AddObserver(this);
67 observed_widgets_
.insert(widget
);
68 widget
->set_movement_disabled(true);
71 // TODO(wittman): remove once the new visual style is complete
72 widget
->GetNativeWindow()->SetProperty(aura::client::kConstrainedWindowKey
,
75 wm::SetWindowVisibilityAnimationType(
76 widget
->GetNativeWindow(),
77 wm::WINDOW_VISIBILITY_ANIMATION_TYPE_ROTATE
);
79 gfx::NativeView parent
= platform_util::GetParent(widget
->GetNativeView());
80 wm::SetChildWindowVisibilityChangesAnimated(parent
);
81 // No animations should get performed on the window since that will re-order
82 // the window stack which will then cause many problems.
83 if (parent
&& parent
->parent()) {
84 parent
->parent()->SetProperty(aura::client::kAnimationsDisabledKey
, true);
88 widget
->GetNativeWindow(),
89 platform_util::GetParent(widget
->GetNativeView()));
93 // SingleWebContentsDialogManager overrides
94 void Show() override
{
95 views::Widget
* widget
= GetWidget(dialog());
97 scoped_ptr
<wm::SuspendChildWindowVisibilityAnimations
> suspend
;
98 if (shown_widgets_
.find(widget
) != shown_widgets_
.end()) {
99 suspend
.reset(new wm::SuspendChildWindowVisibilityAnimations(
100 widget
->GetNativeWindow()->parent()));
103 // Host may be NULL during tab drag on Views/Win32.
105 constrained_window::UpdateWebContentsModalDialogPosition(widget
, host_
);
109 #if defined(USE_AURA)
110 // TODO(pkotwicz): Control the z-order of the constrained dialog via
111 // views::kHostViewKey. We will need to ensure that the parent window's
112 // shadows are below the constrained dialog in z-order when we do this.
113 shown_widgets_
.insert(widget
);
117 void Hide() override
{
118 views::Widget
* widget
= GetWidget(dialog());
119 #if defined(USE_AURA)
120 scoped_ptr
<wm::SuspendChildWindowVisibilityAnimations
> suspend
;
121 suspend
.reset(new wm::SuspendChildWindowVisibilityAnimations(
122 widget
->GetNativeWindow()->parent()));
127 void Close() override
{ GetWidget(dialog())->Close(); }
129 void Focus() override
{
130 views::Widget
* widget
= GetWidget(dialog());
131 if (widget
->widget_delegate() &&
132 widget
->widget_delegate()->GetInitiallyFocusedView())
133 widget
->widget_delegate()->GetInitiallyFocusedView()->RequestFocus();
134 #if defined(USE_AURA)
135 // We don't necessarily have a RootWindow yet.
136 if (widget
->GetNativeView()->GetRootWindow())
137 widget
->GetNativeView()->Focus();
141 void Pulse() override
{}
143 // WebContentsModalDialogHostObserver overrides
144 void OnPositionRequiresUpdate() override
{
147 for (std::set
<views::Widget
*>::iterator it
= observed_widgets_
.begin();
148 it
!= observed_widgets_
.end();
150 constrained_window::UpdateWebContentsModalDialogPosition(*it
, host_
);
154 void OnHostDestroying() override
{
155 host_
->RemoveObserver(this);
159 // views::WidgetObserver overrides
161 // NOTE(wittman): OnWidgetClosing is overriden to ensure that, when the widget
162 // is explicitly closed, the destruction occurs within the same call
163 // stack. This avoids event races that lead to non-deterministic destruction
164 // ordering in e.g. the print preview dialog. OnWidgetDestroying is overridden
165 // because OnWidgetClosing is *only* invoked on explicit close, not when the
166 // widget is implicitly destroyed due to its parent being closed. This
167 // situation occurs with app windows. WidgetClosing removes the observer, so
168 // only one of these two functions is ever invoked for a given widget.
169 void OnWidgetClosing(views::Widget
* widget
) override
{
170 WidgetClosing(widget
);
173 void OnWidgetDestroying(views::Widget
* widget
) override
{
174 WidgetClosing(widget
);
177 void HostChanged(web_modal::WebContentsModalDialogHost
* new_host
) override
{
179 host_
->RemoveObserver(this);
183 // |host_| may be null during WebContents destruction or Win32 tab dragging.
185 host_
->AddObserver(this);
187 for (std::set
<views::Widget
*>::iterator it
= observed_widgets_
.begin();
188 it
!= observed_widgets_
.end();
190 views::Widget::ReparentNativeView((*it
)->GetNativeView(),
191 host_
->GetHostView());
194 OnPositionRequiresUpdate();
198 gfx::NativeWindow
dialog() override
{ return dialog_
; }
201 static views::Widget
* GetWidget(gfx::NativeWindow dialog
) {
202 views::Widget
* widget
= views::Widget::GetWidgetForNativeWindow(dialog
);
207 void WidgetClosing(views::Widget
* widget
) {
208 #if defined(USE_AURA)
209 gfx::NativeView view
= platform_util::GetParent(widget
->GetNativeView());
210 // Allow the parent to animate again.
211 if (view
&& view
->parent())
212 view
->parent()->ClearProperty(aura::client::kAnimationsDisabledKey
);
214 widget
->RemoveObserver(this);
215 observed_widgets_
.erase(widget
);
217 #if defined(USE_AURA)
218 shown_widgets_
.erase(widget
);
221 // Will cause this object to be deleted.
222 native_delegate_
->WillClose(widget
->GetNativeWindow());
225 SingleWebContentsDialogManagerDelegate
* native_delegate_
;
226 gfx::NativeWindow dialog_
;
227 WebContentsModalDialogHost
* host_
;
228 std::set
<views::Widget
*> observed_widgets_
;
229 std::set
<views::Widget
*> shown_widgets_
;
231 DISALLOW_COPY_AND_ASSIGN(NativeWebContentsModalDialogManagerViews
);
236 namespace web_modal
{
238 SingleWebContentsDialogManager
*
239 WebContentsModalDialogManager::CreateNativeWebModalManager(
240 gfx::NativeWindow dialog
,
241 SingleWebContentsDialogManagerDelegate
* native_delegate
) {
242 return new NativeWebContentsModalDialogManagerViews(dialog
, native_delegate
);
245 } // namespace web_modal