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/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:
     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 
     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 
     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 
    115 void UpdateBrowserModalDialogPosition(views::Widget* widget,
    116                                       web_modal::ModalDialogHost* dialog_host) {
    117   UpdateModalDialogPosition(widget, dialog_host,
    118                             widget->GetRootView()->GetPreferredSize());
    119 }
    120 
    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 
    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