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