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:
BrowserModalDialogHostObserverViews(ModalDialogHost * host,views::Widget * target_widget,const char * const native_window_property)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
~BrowserModalDialogHostObserverViews()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
OnWidgetClosing(views::Widget * widget)50 virtual void OnWidgetClosing(views::Widget* widget) OVERRIDE {
51 delete this;
52 }
53
54 // WebContentsModalDialogHostObserver overrides
OnPositionRequiresUpdate()55 virtual void OnPositionRequiresUpdate() OVERRIDE {
56 UpdateBrowserModalDialogPosition(target_widget_, host_);
57 }
58
OnHostDestroying()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
UpdateModalDialogPosition(views::Widget * widget,web_modal::ModalDialogHost * dialog_host,const gfx::Size & size)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
UpdateWebContentsModalDialogPosition(views::Widget * widget,web_modal::WebContentsModalDialogHost * dialog_host)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
UpdateBrowserModalDialogPosition(views::Widget * widget,web_modal::ModalDialogHost * dialog_host)115 void UpdateBrowserModalDialogPosition(views::Widget* widget,
116 web_modal::ModalDialogHost* dialog_host) {
117 UpdateModalDialogPosition(widget, dialog_host,
118 widget->GetRootView()->GetPreferredSize());
119 }
120
CreateBrowserModalDialogViews(views::DialogDelegate * dialog,gfx::NativeWindow parent)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
CreateConstrainedStyleNonClientFrameView(views::Widget * widget,content::BrowserContext * browser_context)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