web_contents_modal_dialog_manager_views.cc revision f2477e01787aa58f445919b809d89e252beef54f
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 // TODO(wittman): remove once the new visual style is complete 95 widget->GetNativeWindow()->SetProperty(ash::kConstrainedWindowKey, true); 96 views::corewm::SetModalParent( 97 widget->GetNativeWindow(), 98 platform_util::GetParent(widget->GetNativeView())); 99#endif 100 } 101 102 virtual void ShowDialog(NativeWebContentsModalDialog dialog) OVERRIDE { 103 views::Widget* widget = GetWidget(dialog); 104#if defined(USE_AURA) 105 scoped_ptr<views::corewm::SuspendChildWindowVisibilityAnimations> suspend; 106 if (shown_widgets_.find(widget) != shown_widgets_.end()) { 107 suspend.reset(new views::corewm::SuspendChildWindowVisibilityAnimations( 108 widget->GetNativeWindow()->parent())); 109 } 110#endif 111 // Host may be NULL during tab drag on Views/Win32. 112 if (host_) 113 UpdateWebContentsModalDialogPosition(widget, host_); 114 widget->Show(); 115 FocusDialog(dialog); 116 117#if defined(USE_AURA) 118 // TODO(pkotwicz): Control the z-order of the constrained dialog via 119 // views::kHostViewKey. We will need to ensure that the parent window's 120 // shadows are below the constrained dialog in z-order when we do this. 121 shown_widgets_.insert(widget); 122#endif 123 } 124 125 virtual void HideDialog(NativeWebContentsModalDialog dialog) OVERRIDE { 126 views::Widget* widget = GetWidget(dialog); 127#if defined(USE_AURA) 128 scoped_ptr<views::corewm::SuspendChildWindowVisibilityAnimations> suspend; 129 suspend.reset(new views::corewm::SuspendChildWindowVisibilityAnimations( 130 widget->GetNativeWindow()->parent())); 131#endif 132 widget->Hide(); 133 } 134 135 virtual void CloseDialog(NativeWebContentsModalDialog dialog) OVERRIDE { 136 GetWidget(dialog)->Close(); 137 } 138 139 virtual void FocusDialog(NativeWebContentsModalDialog dialog) OVERRIDE { 140 views::Widget* widget = GetWidget(dialog); 141 if (widget->widget_delegate() && 142 widget->widget_delegate()->GetInitiallyFocusedView()) 143 widget->widget_delegate()->GetInitiallyFocusedView()->RequestFocus(); 144#if defined(USE_ASH) 145 // We don't necessarily have a RootWindow yet. 146 if (widget->GetNativeView()->GetRootWindow()) 147 widget->GetNativeView()->Focus(); 148#endif 149 } 150 151 virtual void PulseDialog(NativeWebContentsModalDialog dialog) OVERRIDE { 152 } 153 154 // WebContentsModalDialogHostObserver overrides 155 virtual void OnPositionRequiresUpdate() OVERRIDE { 156 DCHECK(host_); 157 158 for (std::set<views::Widget*>::iterator it = observed_widgets_.begin(); 159 it != observed_widgets_.end(); 160 ++it) { 161 UpdateWebContentsModalDialogPosition(*it, host_); 162 } 163 } 164 165 virtual void OnHostDestroying() OVERRIDE { 166 host_->RemoveObserver(this); 167 host_ = NULL; 168 } 169 170 // views::WidgetObserver overrides 171 172 // NOTE(wittman): OnWidgetClosing is overriden to ensure that, when the widget 173 // is explicitly closed, the destruction occurs within the same call 174 // stack. This avoids event races that lead to non-deterministic destruction 175 // ordering in e.g. the print preview dialog. OnWidgetDestroying is overridden 176 // because OnWidgetClosing is *only* invoked on explicit close, not when the 177 // widget is implicitly destroyed due to its parent being closed. This 178 // situation occurs with app windows. WidgetClosing removes the observer, so 179 // only one of these two functions is ever invoked for a given widget. 180 virtual void OnWidgetClosing(views::Widget* widget) OVERRIDE { 181 WidgetClosing(widget); 182 } 183 184 virtual void OnWidgetDestroying(views::Widget* widget) OVERRIDE { 185 WidgetClosing(widget); 186 } 187 188 virtual void HostChanged( 189 web_modal::WebContentsModalDialogHost* new_host) OVERRIDE { 190 if (host_) 191 host_->RemoveObserver(this); 192 193 host_ = new_host; 194 195 // |host_| may be null during WebContents destruction or Win32 tab dragging. 196 if (host_) { 197 host_->AddObserver(this); 198 199 for (std::set<views::Widget*>::iterator it = observed_widgets_.begin(); 200 it != observed_widgets_.end(); 201 ++it) { 202 views::Widget::ReparentNativeView((*it)->GetNativeView(), 203 host_->GetHostView()); 204 } 205 206 OnPositionRequiresUpdate(); 207 } 208 } 209 210 private: 211 static views::Widget* GetWidget(NativeWebContentsModalDialog dialog) { 212 views::Widget* widget = views::Widget::GetWidgetForNativeWindow(dialog); 213 DCHECK(widget); 214 return widget; 215 } 216 217 void WidgetClosing(views::Widget* widget) { 218#if defined(USE_ASH) 219 gfx::NativeView view = platform_util::GetParent(widget->GetNativeView()); 220 // Allow the parent to animate again. 221 if (view && view->parent()) 222 view->parent()->ClearProperty(aura::client::kAnimationsDisabledKey); 223#endif 224 widget->RemoveObserver(this); 225 native_delegate_->WillClose(widget->GetNativeView()); 226 observed_widgets_.erase(widget); 227#if defined(USE_AURA) 228 shown_widgets_.erase(widget); 229#endif 230 } 231 232 NativeWebContentsModalDialogManagerDelegate* native_delegate_; 233 WebContentsModalDialogHost* host_; 234 std::set<views::Widget*> observed_widgets_; 235 std::set<views::Widget*> shown_widgets_; 236 237 DISALLOW_COPY_AND_ASSIGN(NativeWebContentsModalDialogManagerViews); 238}; 239 240} // namespace 241 242namespace web_modal { 243 244NativeWebContentsModalDialogManager* WebContentsModalDialogManager:: 245CreateNativeManager( 246 NativeWebContentsModalDialogManagerDelegate* native_delegate) { 247 return new NativeWebContentsModalDialogManagerViews(native_delegate); 248} 249 250} // namespace web_modal 251