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 "chrome/browser/ui/views/constrained_window_views.h"
10 #include "components/web_modal/native_web_contents_modal_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 "content/public/browser/web_contents_view.h"
14 #include "ui/gfx/point.h"
15 #include "ui/gfx/size.h"
16 #include "ui/views/border.h"
17 #include "ui/views/widget/widget.h"
18 #include "ui/views/widget/widget_delegate.h"
19 #include "ui/views/widget/widget_observer.h"
20 #include "ui/views/window/dialog_delegate.h"
21 #include "ui/views/window/non_client_view.h"
24 #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"
31 // TODO(wittman): this code should not depend on ash.
33 #include "ash/ash_constants.h"
34 #include "ash/shell.h"
35 #include "ash/wm/custom_frame_view_ash.h"
38 using web_modal::NativeWebContentsModalDialog
;
39 using web_modal::NativeWebContentsModalDialogManager
;
40 using web_modal::NativeWebContentsModalDialogManagerDelegate
;
41 using web_modal::WebContentsModalDialogHost
;
42 using web_modal::ModalDialogHostObserver
;
46 class NativeWebContentsModalDialogManagerViews
47 : public NativeWebContentsModalDialogManager
,
48 public ModalDialogHostObserver
,
49 public views::WidgetObserver
{
51 NativeWebContentsModalDialogManagerViews(
52 NativeWebContentsModalDialogManagerDelegate
* native_delegate
)
53 : native_delegate_(native_delegate
),
57 virtual ~NativeWebContentsModalDialogManagerViews() {
59 host_
->RemoveObserver(this);
61 for (std::set
<views::Widget
*>::iterator it
= observed_widgets_
.begin();
62 it
!= observed_widgets_
.end();
64 (*it
)->RemoveObserver(this);
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);
76 // TODO(wittman): remove once the new visual style is complete
77 widget
->GetNativeWindow()->SetProperty(aura::client::kConstrainedWindowKey
,
80 views::corewm::SetWindowVisibilityAnimationType(
81 widget
->GetNativeWindow(),
82 views::corewm::WINDOW_VISIBILITY_ANIMATION_TYPE_ROTATE
);
86 gfx::NativeView parent
= platform_util::GetParent(widget
->GetNativeView());
87 views::corewm::SetChildWindowVisibilityChangesAnimated(parent
);
88 // No animations should get performed on the window since that will re-order
89 // the window stack which will then cause many problems.
90 if (parent
&& parent
->parent()) {
91 parent
->parent()->SetProperty(aura::client::kAnimationsDisabledKey
, true);
94 views::corewm::SetModalParent(
95 widget
->GetNativeWindow(),
96 platform_util::GetParent(widget
->GetNativeView()));
100 virtual void ShowDialog(NativeWebContentsModalDialog dialog
) OVERRIDE
{
101 views::Widget
* widget
= GetWidget(dialog
);
102 #if defined(USE_AURA)
103 scoped_ptr
<views::corewm::SuspendChildWindowVisibilityAnimations
> suspend
;
104 if (shown_widgets_
.find(widget
) != shown_widgets_
.end()) {
105 suspend
.reset(new views::corewm::SuspendChildWindowVisibilityAnimations(
106 widget
->GetNativeWindow()->parent()));
109 // Host may be NULL during tab drag on Views/Win32.
111 UpdateWebContentsModalDialogPosition(widget
, host_
);
115 #if defined(USE_AURA)
116 // TODO(pkotwicz): Control the z-order of the constrained dialog via
117 // views::kHostViewKey. We will need to ensure that the parent window's
118 // shadows are below the constrained dialog in z-order when we do this.
119 shown_widgets_
.insert(widget
);
123 virtual void HideDialog(NativeWebContentsModalDialog dialog
) OVERRIDE
{
124 views::Widget
* widget
= GetWidget(dialog
);
125 #if defined(USE_AURA)
126 scoped_ptr
<views::corewm::SuspendChildWindowVisibilityAnimations
> suspend
;
127 suspend
.reset(new views::corewm::SuspendChildWindowVisibilityAnimations(
128 widget
->GetNativeWindow()->parent()));
133 virtual void CloseDialog(NativeWebContentsModalDialog dialog
) OVERRIDE
{
134 GetWidget(dialog
)->Close();
137 virtual void FocusDialog(NativeWebContentsModalDialog dialog
) OVERRIDE
{
138 views::Widget
* widget
= GetWidget(dialog
);
139 if (widget
->widget_delegate() &&
140 widget
->widget_delegate()->GetInitiallyFocusedView())
141 widget
->widget_delegate()->GetInitiallyFocusedView()->RequestFocus();
143 // We don't necessarily have a RootWindow yet.
144 if (widget
->GetNativeView()->GetRootWindow())
145 widget
->GetNativeView()->Focus();
149 virtual void PulseDialog(NativeWebContentsModalDialog dialog
) OVERRIDE
{
152 // WebContentsModalDialogHostObserver overrides
153 virtual void OnPositionRequiresUpdate() OVERRIDE
{
156 for (std::set
<views::Widget
*>::iterator it
= observed_widgets_
.begin();
157 it
!= observed_widgets_
.end();
159 UpdateWebContentsModalDialogPosition(*it
, host_
);
163 virtual void OnHostDestroying() OVERRIDE
{
164 host_
->RemoveObserver(this);
168 // views::WidgetObserver overrides
170 // NOTE(wittman): OnWidgetClosing is overriden to ensure that, when the widget
171 // is explicitly closed, the destruction occurs within the same call
172 // stack. This avoids event races that lead to non-deterministic destruction
173 // ordering in e.g. the print preview dialog. OnWidgetDestroying is overridden
174 // because OnWidgetClosing is *only* invoked on explicit close, not when the
175 // widget is implicitly destroyed due to its parent being closed. This
176 // situation occurs with app windows. WidgetClosing removes the observer, so
177 // only one of these two functions is ever invoked for a given widget.
178 virtual void OnWidgetClosing(views::Widget
* widget
) OVERRIDE
{
179 WidgetClosing(widget
);
182 virtual void OnWidgetDestroying(views::Widget
* widget
) OVERRIDE
{
183 WidgetClosing(widget
);
186 virtual void HostChanged(
187 web_modal::WebContentsModalDialogHost
* new_host
) OVERRIDE
{
189 host_
->RemoveObserver(this);
193 // |host_| may be null during WebContents destruction or Win32 tab dragging.
195 host_
->AddObserver(this);
197 for (std::set
<views::Widget
*>::iterator it
= observed_widgets_
.begin();
198 it
!= observed_widgets_
.end();
200 views::Widget::ReparentNativeView((*it
)->GetNativeView(),
201 host_
->GetHostView());
204 OnPositionRequiresUpdate();
209 static views::Widget
* GetWidget(NativeWebContentsModalDialog dialog
) {
210 views::Widget
* widget
= views::Widget::GetWidgetForNativeWindow(dialog
);
215 void WidgetClosing(views::Widget
* widget
) {
217 gfx::NativeView view
= platform_util::GetParent(widget
->GetNativeView());
218 // Allow the parent to animate again.
219 if (view
&& view
->parent())
220 view
->parent()->ClearProperty(aura::client::kAnimationsDisabledKey
);
222 widget
->RemoveObserver(this);
223 native_delegate_
->WillClose(widget
->GetNativeView());
224 observed_widgets_
.erase(widget
);
225 #if defined(USE_AURA)
226 shown_widgets_
.erase(widget
);
230 NativeWebContentsModalDialogManagerDelegate
* native_delegate_
;
231 WebContentsModalDialogHost
* host_
;
232 std::set
<views::Widget
*> observed_widgets_
;
233 std::set
<views::Widget
*> shown_widgets_
;
235 DISALLOW_COPY_AND_ASSIGN(NativeWebContentsModalDialogManagerViews
);
240 namespace web_modal
{
242 NativeWebContentsModalDialogManager
* WebContentsModalDialogManager::
244 NativeWebContentsModalDialogManagerDelegate
* native_delegate
) {
245 return new NativeWebContentsModalDialogManagerViews(native_delegate
);
248 } // namespace web_modal