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/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" 22 23#if defined(USE_AURA) 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" 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::ModalDialogHostObserver; 43 44namespace { 45 46class NativeWebContentsModalDialogManagerViews 47 : public NativeWebContentsModalDialogManager, 48 public ModalDialogHostObserver, 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 views::corewm::SetWindowVisibilityAnimationType( 81 widget->GetNativeWindow(), 82 views::corewm::WINDOW_VISIBILITY_ANIMATION_TYPE_ROTATE); 83#endif 84 85#if defined(USE_ASH) 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); 92 } 93 94 views::corewm::SetModalParent( 95 widget->GetNativeWindow(), 96 platform_util::GetParent(widget->GetNativeView())); 97#endif 98 } 99 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())); 107 } 108#endif 109 // Host may be NULL during tab drag on Views/Win32. 110 if (host_) 111 UpdateWebContentsModalDialogPosition(widget, host_); 112 widget->Show(); 113 FocusDialog(dialog); 114 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); 120#endif 121 } 122 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())); 129#endif 130 widget->Hide(); 131 } 132 133 virtual void CloseDialog(NativeWebContentsModalDialog dialog) OVERRIDE { 134 GetWidget(dialog)->Close(); 135 } 136 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(); 142#if defined(USE_ASH) 143 // We don't necessarily have a RootWindow yet. 144 if (widget->GetNativeView()->GetRootWindow()) 145 widget->GetNativeView()->Focus(); 146#endif 147 } 148 149 virtual void PulseDialog(NativeWebContentsModalDialog dialog) OVERRIDE { 150 } 151 152 // WebContentsModalDialogHostObserver overrides 153 virtual void OnPositionRequiresUpdate() OVERRIDE { 154 DCHECK(host_); 155 156 for (std::set<views::Widget*>::iterator it = observed_widgets_.begin(); 157 it != observed_widgets_.end(); 158 ++it) { 159 UpdateWebContentsModalDialogPosition(*it, host_); 160 } 161 } 162 163 virtual void OnHostDestroying() OVERRIDE { 164 host_->RemoveObserver(this); 165 host_ = NULL; 166 } 167 168 // views::WidgetObserver overrides 169 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); 180 } 181 182 virtual void OnWidgetDestroying(views::Widget* widget) OVERRIDE { 183 WidgetClosing(widget); 184 } 185 186 virtual void HostChanged( 187 web_modal::WebContentsModalDialogHost* new_host) OVERRIDE { 188 if (host_) 189 host_->RemoveObserver(this); 190 191 host_ = new_host; 192 193 // |host_| may be null during WebContents destruction or Win32 tab dragging. 194 if (host_) { 195 host_->AddObserver(this); 196 197 for (std::set<views::Widget*>::iterator it = observed_widgets_.begin(); 198 it != observed_widgets_.end(); 199 ++it) { 200 views::Widget::ReparentNativeView((*it)->GetNativeView(), 201 host_->GetHostView()); 202 } 203 204 OnPositionRequiresUpdate(); 205 } 206 } 207 208 private: 209 static views::Widget* GetWidget(NativeWebContentsModalDialog dialog) { 210 views::Widget* widget = views::Widget::GetWidgetForNativeWindow(dialog); 211 DCHECK(widget); 212 return widget; 213 } 214 215 void WidgetClosing(views::Widget* widget) { 216#if defined(USE_ASH) 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); 221#endif 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); 227#endif 228 } 229 230 NativeWebContentsModalDialogManagerDelegate* native_delegate_; 231 WebContentsModalDialogHost* host_; 232 std::set<views::Widget*> observed_widgets_; 233 std::set<views::Widget*> shown_widgets_; 234 235 DISALLOW_COPY_AND_ASSIGN(NativeWebContentsModalDialogManagerViews); 236}; 237 238} // namespace 239 240namespace web_modal { 241 242NativeWebContentsModalDialogManager* WebContentsModalDialogManager:: 243CreateNativeManager( 244 NativeWebContentsModalDialogManagerDelegate* native_delegate) { 245 return new NativeWebContentsModalDialogManagerViews(native_delegate); 246} 247 248} // namespace web_modal 249