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