constrained_window_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 "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
16using web_modal::ModalDialogHost;
17using web_modal::ModalDialogHostObserver;
18
19namespace {
20// The name of a key to store on the window handle to associate
21// BrowserModalDialogHostObserverViews with the Widget.
22const char* const kBrowserModalDialogHostObserverViewsKey =
23    "__BROWSER_MODAL_DIALOG_HOST_OBSERVER_VIEWS__";
24
25// Applies positioning changes from the ModalDialogHost to the Widget.
26class 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
72void 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
99void 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
115void UpdateBrowserModalDialogPosition(views::Widget* widget,
116                                      web_modal::ModalDialogHost* dialog_host) {
117  UpdateModalDialogPosition(widget, dialog_host,
118                            widget->GetRootView()->GetPreferredSize());
119}
120
121views::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
142views::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