15821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Copyright (c) 2012 The Chromium Authors. All rights reserved.
25821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Use of this source code is governed by a BSD-style license that can be
35821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// found in the LICENSE file.
45821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
55821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "chrome/browser/ui/views/constrained_window_views.h"
65821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
75821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include <algorithm>
85821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
97d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)#include "chrome/browser/ui/browser_finder.h"
10116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch#include "components/web_modal/popup_manager.h"
1190dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)#include "components/web_modal/web_contents_modal_dialog_host.h"
121320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci#include "extensions/browser/guest_view/guest_view_base.h"
13b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)#include "ui/views/border.h"
145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "ui/views/widget/widget.h"
15c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)#include "ui/views/widget/widget_observer.h"
165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "ui/views/window/dialog_delegate.h"
175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
184e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)using web_modal::ModalDialogHost;
194e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)using web_modal::ModalDialogHostObserver;
205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
21c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)namespace {
22c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)// The name of a key to store on the window handle to associate
234e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)// BrowserModalDialogHostObserverViews with the Widget.
244e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)const char* const kBrowserModalDialogHostObserverViewsKey =
254e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)    "__BROWSER_MODAL_DIALOG_HOST_OBSERVER_VIEWS__";
26c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)
274e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)// Applies positioning changes from the ModalDialogHost to the Widget.
284e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)class BrowserModalDialogHostObserverViews
29c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    : public views::WidgetObserver,
304e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)      public ModalDialogHostObserver {
31c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) public:
32f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)  BrowserModalDialogHostObserverViews(ModalDialogHost* host,
33f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)                                      views::Widget* target_widget,
34f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)                                      const char *const native_window_property)
35c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)      : host_(host),
36c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)        target_widget_(target_widget),
37c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)        native_window_property_(native_window_property) {
38c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    DCHECK(host_);
39c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    DCHECK(target_widget_);
40c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    host_->AddObserver(this);
41c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    target_widget_->AddObserver(this);
42c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  }
43c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)
444e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)  virtual ~BrowserModalDialogHostObserverViews() {
453551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)    if (host_)
463551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)      host_->RemoveObserver(this);
47c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    target_widget_->RemoveObserver(this);
48f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)    target_widget_->SetNativeWindowProperty(native_window_property_, NULL);
49c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  }
50c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)
51c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  // WidgetObserver overrides
52c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  virtual void OnWidgetClosing(views::Widget* widget) OVERRIDE {
53c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    delete this;
54c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  }
55c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)
56c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  // WebContentsModalDialogHostObserver overrides
57c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  virtual void OnPositionRequiresUpdate() OVERRIDE {
584e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)    UpdateBrowserModalDialogPosition(target_widget_, host_);
593551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)  }
607d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)
613551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)  virtual void OnHostDestroying() OVERRIDE {
623551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)    host_->RemoveObserver(this);
633551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)    host_ = NULL;
64c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  }
65c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)
66c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) private:
674e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)  ModalDialogHost* host_;
68c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  views::Widget* target_widget_;
69c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  const char* const native_window_property_;
70c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)
714e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)  DISALLOW_COPY_AND_ASSIGN(BrowserModalDialogHostObserverViews);
72c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)};
73c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)
74f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)void UpdateModalDialogPosition(views::Widget* widget,
75f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)                               web_modal::ModalDialogHost* dialog_host,
76f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)                               const gfx::Size& size) {
778bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)  // Do not forcibly update the dialog widget position if it is being dragged.
788bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)  if (widget->HasCapture())
798bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)    return;
808bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)
814e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)  gfx::Point position = dialog_host->GetDialogPosition(size);
82f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)  views::Border* border = widget->non_client_view()->frame_view()->border();
834e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)  // Border may be null during widget initialization.
844e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)  if (border) {
854e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)    // Align the first row of pixels inside the border. This is the apparent
864e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)    // top of the dialog.
874e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)    position.set_y(position.y() - border->GetInsets().top());
884e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)  }
894e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)
904e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)  if (widget->is_top_level()) {
914e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)    position +=
924e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)        views::Widget::GetWidgetForNativeView(dialog_host->GetHostView())->
934e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)            GetClientAreaBoundsInScreen().OffsetFromOrigin();
944e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)  }
954e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)
964e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)  widget->SetBounds(gfx::Rect(position, size));
974e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)}
984e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)
99c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)}  // namespace
100c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)
1013551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)void UpdateWebContentsModalDialogPosition(
1023551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)    views::Widget* widget,
1033551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)    web_modal::WebContentsModalDialogHost* dialog_host) {
10458537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)  gfx::Size size = widget->GetRootView()->GetPreferredSize();
10558537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)  gfx::Size max_size = dialog_host->GetMaximumDialogSize();
10658537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)  // Enlarge the max size by the top border, as the dialog will be shifted
1074e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)  // outside the area specified by the dialog host by this amount later.
1084e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)  views::Border* border =
1094e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)      widget->non_client_view()->frame_view()->border();
1103551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)  // Border may be null during widget initialization.
11158537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)  if (border)
11258537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)    max_size.Enlarge(0, border->GetInsets().top());
11358537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)  size.SetToMin(max_size);
1144e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)  UpdateModalDialogPosition(widget, dialog_host, size);
1154e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)}
11658537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)
117f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)void UpdateBrowserModalDialogPosition(views::Widget* widget,
118f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)                                      web_modal::ModalDialogHost* dialog_host) {
119f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)  UpdateModalDialogPosition(widget, dialog_host,
1204e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)                            widget->GetRootView()->GetPreferredSize());
1215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
1225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
123f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)views::Widget* ShowWebModalDialogViews(
124f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)    views::WidgetDelegate* dialog,
125f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)    content::WebContents* initiator_web_contents) {
1261320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  extensions::GuestViewBase* guest_view =
1271320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci      extensions::GuestViewBase::FromWebContents(initiator_web_contents);
128f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)  // For embedded WebContents, use the embedder's WebContents for constrained
129f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)  // window.
130f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)  content::WebContents* web_contents =
1311320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci      guest_view && guest_view->embedder_web_contents() ?
1321320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci          guest_view->embedder_web_contents() : initiator_web_contents;
13346d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)  views::Widget* widget = CreateWebModalDialogViews(dialog, web_contents);
134116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch  web_modal::PopupManager* popup_manager =
135116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch      web_modal::PopupManager::FromWebContents(web_contents);
136116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch  popup_manager->ShowModalDialog(widget->GetNativeWindow(), web_contents);
13746d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)  return widget;
13846d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)}
13946d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)
14046d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)views::Widget* CreateWebModalDialogViews(views::WidgetDelegate* dialog,
14146d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)                                         content::WebContents* web_contents) {
14246d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)  DCHECK_EQ(ui::MODAL_TYPE_CHILD, dialog->GetModalType());
143116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch  web_modal::PopupManager* popup_manager =
144116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch      web_modal::PopupManager::FromWebContents(web_contents);
145116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch  const gfx::NativeWindow parent = popup_manager->GetHostView();
14646d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)  return views::DialogDelegate::CreateDialogWidget(dialog, NULL, parent);
14746d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)}
14846d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)
149116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch// TODO(gbillock): Replace this with PopupManager calls.
1507d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)views::Widget* CreateBrowserModalDialogViews(views::DialogDelegate* dialog,
1517d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)                                             gfx::NativeWindow parent) {
1527d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)  views::Widget* widget =
1537d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)      views::DialogDelegate::CreateDialogWidget(dialog, NULL, parent);
1547d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)  if (!dialog->UseNewStyleForThisDialog())
1557d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)    return widget;
1567d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)
1577d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)  // Get the browser dialog management and hosting components from |parent|.
1587d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)  Browser* browser = chrome::FindBrowserWithWindow(parent);
1597d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)  if (browser) {
1607d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)    ChromeWebModalDialogManagerDelegate* manager = browser;
1614e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)    ModalDialogHost* host = manager->GetWebContentsModalDialogHost();
1627d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)    DCHECK_EQ(parent, host->GetHostView());
1634e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)    ModalDialogHostObserver* dialog_host_observer =
1644e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)        new BrowserModalDialogHostObserverViews(
1654e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)            host, widget, kBrowserModalDialogHostObserverViewsKey);
1667d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)    dialog_host_observer->OnPositionRequiresUpdate();
1677d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)  }
1687d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)  return widget;
1697d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)}
170