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