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 "chrome/browser/ui/views/constrained_window_views.h" 6 7 #include <algorithm> 8 9 #include "chrome/browser/ui/browser_finder.h" 10 #include "components/web_modal/web_contents_modal_dialog_host.h" 11 #include "ui/views/border.h" 12 #include "ui/views/widget/widget.h" 13 #include "ui/views/widget/widget_observer.h" 14 #include "ui/views/window/dialog_delegate.h" 15 16 using web_modal::ModalDialogHost; 17 using web_modal::ModalDialogHostObserver; 18 19 namespace { 20 // The name of a key to store on the window handle to associate 21 // BrowserModalDialogHostObserverViews with the Widget. 22 const char* const kBrowserModalDialogHostObserverViewsKey = 23 "__BROWSER_MODAL_DIALOG_HOST_OBSERVER_VIEWS__"; 24 25 // Applies positioning changes from the ModalDialogHost to the Widget. 26 class BrowserModalDialogHostObserverViews 27 : public views::WidgetObserver, 28 public ModalDialogHostObserver { 29 public: 30 BrowserModalDialogHostObserverViews(ModalDialogHost* host, 31 views::Widget* target_widget, 32 const char *const native_window_property) 33 : host_(host), 34 target_widget_(target_widget), 35 native_window_property_(native_window_property) { 36 DCHECK(host_); 37 DCHECK(target_widget_); 38 host_->AddObserver(this); 39 target_widget_->AddObserver(this); 40 } 41 42 virtual ~BrowserModalDialogHostObserverViews() { 43 if (host_) 44 host_->RemoveObserver(this); 45 target_widget_->RemoveObserver(this); 46 target_widget_->SetNativeWindowProperty(native_window_property_, NULL); 47 } 48 49 // WidgetObserver overrides 50 virtual void OnWidgetClosing(views::Widget* widget) OVERRIDE { 51 delete this; 52 } 53 54 // WebContentsModalDialogHostObserver overrides 55 virtual void OnPositionRequiresUpdate() OVERRIDE { 56 UpdateBrowserModalDialogPosition(target_widget_, host_); 57 } 58 59 virtual void OnHostDestroying() OVERRIDE { 60 host_->RemoveObserver(this); 61 host_ = NULL; 62 } 63 64 private: 65 ModalDialogHost* host_; 66 views::Widget* target_widget_; 67 const char* const native_window_property_; 68 69 DISALLOW_COPY_AND_ASSIGN(BrowserModalDialogHostObserverViews); 70 }; 71 72 void UpdateModalDialogPosition(views::Widget* widget, 73 web_modal::ModalDialogHost* dialog_host, 74 const gfx::Size& size) { 75 // Do not forcibly update the dialog widget position if it is being dragged. 76 if (widget->HasCapture()) 77 return; 78 79 gfx::Point position = dialog_host->GetDialogPosition(size); 80 views::Border* border = widget->non_client_view()->frame_view()->border(); 81 // Border may be null during widget initialization. 82 if (border) { 83 // Align the first row of pixels inside the border. This is the apparent 84 // top of the dialog. 85 position.set_y(position.y() - border->GetInsets().top()); 86 } 87 88 if (widget->is_top_level()) { 89 position += 90 views::Widget::GetWidgetForNativeView(dialog_host->GetHostView())-> 91 GetClientAreaBoundsInScreen().OffsetFromOrigin(); 92 } 93 94 widget->SetBounds(gfx::Rect(position, size)); 95 } 96 97 } // namespace 98 99 void UpdateWebContentsModalDialogPosition( 100 views::Widget* widget, 101 web_modal::WebContentsModalDialogHost* dialog_host) { 102 gfx::Size size = widget->GetRootView()->GetPreferredSize(); 103 gfx::Size max_size = dialog_host->GetMaximumDialogSize(); 104 // Enlarge the max size by the top border, as the dialog will be shifted 105 // outside the area specified by the dialog host by this amount later. 106 views::Border* border = 107 widget->non_client_view()->frame_view()->border(); 108 // Border may be null during widget initialization. 109 if (border) 110 max_size.Enlarge(0, border->GetInsets().top()); 111 size.SetToMin(max_size); 112 UpdateModalDialogPosition(widget, dialog_host, size); 113 } 114 115 void UpdateBrowserModalDialogPosition(views::Widget* widget, 116 web_modal::ModalDialogHost* dialog_host) { 117 UpdateModalDialogPosition(widget, dialog_host, 118 widget->GetRootView()->GetPreferredSize()); 119 } 120 121 views::Widget* CreateBrowserModalDialogViews(views::DialogDelegate* dialog, 122 gfx::NativeWindow parent) { 123 views::Widget* widget = 124 views::DialogDelegate::CreateDialogWidget(dialog, NULL, parent); 125 if (!dialog->UseNewStyleForThisDialog()) 126 return widget; 127 128 // Get the browser dialog management and hosting components from |parent|. 129 Browser* browser = chrome::FindBrowserWithWindow(parent); 130 if (browser) { 131 ChromeWebModalDialogManagerDelegate* manager = browser; 132 ModalDialogHost* host = manager->GetWebContentsModalDialogHost(); 133 DCHECK_EQ(parent, host->GetHostView()); 134 ModalDialogHostObserver* dialog_host_observer = 135 new BrowserModalDialogHostObserverViews( 136 host, widget, kBrowserModalDialogHostObserverViewsKey); 137 dialog_host_observer->OnPositionRequiresUpdate(); 138 } 139 return widget; 140 } 141 142 views::NonClientFrameView* CreateConstrainedStyleNonClientFrameView( 143 views::Widget* widget, 144 content::BrowserContext* browser_context) { 145 bool force_opaque = true; 146 #if defined(USE_AURA) 147 force_opaque = false; 148 #endif 149 return views::DialogDelegate::CreateDialogFrameView(widget, force_opaque); 150 } 151