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 37using web_modal::NativeWebContentsModalDialog; 38using web_modal::SingleWebContentsDialogManager; 39using web_modal::SingleWebContentsDialogManagerDelegate; 40using web_modal::WebContentsModalDialogHost; 41using web_modal::ModalDialogHostObserver; 42 43namespace { 44 45class 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 252namespace web_modal { 253 254SingleWebContentsDialogManager* WebContentsModalDialogManager:: 255CreateNativeWebModalManager( 256 NativeWebContentsModalDialog dialog, 257 SingleWebContentsDialogManagerDelegate* native_delegate) { 258 return new NativeWebContentsModalDialogManagerViews(dialog, native_delegate); 259} 260 261} // namespace web_modal 262