Home | History | Annotate | Download | only in views
      1 // Copyright 2014 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 "apps/ui/views/native_app_window_views.h"
      6 
      7 #include "apps/app_window.h"
      8 #include "base/threading/sequenced_worker_pool.h"
      9 #include "content/public/browser/render_view_host.h"
     10 #include "content/public/browser/render_widget_host_view.h"
     11 #include "content/public/browser/web_contents.h"
     12 #include "extensions/common/draggable_region.h"
     13 #include "third_party/skia/include/core/SkRegion.h"
     14 #include "ui/gfx/path.h"
     15 #include "ui/views/controls/webview/webview.h"
     16 #include "ui/views/widget/widget.h"
     17 #include "ui/views/window/non_client_view.h"
     18 
     19 #if defined(USE_AURA)
     20 #include "ui/aura/window.h"
     21 #endif
     22 
     23 namespace apps {
     24 
     25 NativeAppWindowViews::NativeAppWindowViews()
     26     : app_window_(NULL),
     27       web_view_(NULL),
     28       widget_(NULL),
     29       frameless_(false),
     30       resizable_(false) {}
     31 
     32 void NativeAppWindowViews::Init(AppWindow* app_window,
     33                                 const AppWindow::CreateParams& create_params) {
     34   app_window_ = app_window;
     35   frameless_ = create_params.frame == AppWindow::FRAME_NONE;
     36   resizable_ = create_params.resizable;
     37   size_constraints_.set_minimum_size(
     38       create_params.GetContentMinimumSize(gfx::Insets()));
     39   size_constraints_.set_maximum_size(
     40       create_params.GetContentMaximumSize(gfx::Insets()));
     41   Observe(app_window_->web_contents());
     42 
     43   widget_ = new views::Widget;
     44   InitializeWindow(app_window, create_params);
     45 
     46   OnViewWasResized();
     47   widget_->AddObserver(this);
     48 }
     49 
     50 NativeAppWindowViews::~NativeAppWindowViews() {
     51   web_view_->SetWebContents(NULL);
     52 }
     53 
     54 void NativeAppWindowViews::OnCanHaveAlphaEnabledChanged() {
     55   app_window_->OnNativeWindowChanged();
     56 }
     57 
     58 void NativeAppWindowViews::InitializeWindow(
     59     AppWindow* app_window,
     60     const AppWindow::CreateParams& create_params) {
     61   // Stub implementation. See also ChromeNativeAppWindowViews.
     62   views::Widget::InitParams init_params(views::Widget::InitParams::TYPE_WINDOW);
     63   init_params.delegate = this;
     64   init_params.keep_on_top = create_params.always_on_top;
     65   widget_->Init(init_params);
     66   widget_->CenterWindow(
     67       create_params.GetInitialWindowBounds(gfx::Insets()).size());
     68 }
     69 
     70 // ui::BaseWindow implementation.
     71 
     72 bool NativeAppWindowViews::IsActive() const { return widget_->IsActive(); }
     73 
     74 bool NativeAppWindowViews::IsMaximized() const {
     75   return widget_->IsMaximized();
     76 }
     77 
     78 bool NativeAppWindowViews::IsMinimized() const {
     79   return widget_->IsMinimized();
     80 }
     81 
     82 bool NativeAppWindowViews::IsFullscreen() const {
     83   return widget_->IsFullscreen();
     84 }
     85 
     86 gfx::NativeWindow NativeAppWindowViews::GetNativeWindow() {
     87   return widget_->GetNativeWindow();
     88 }
     89 
     90 gfx::Rect NativeAppWindowViews::GetRestoredBounds() const {
     91   return widget_->GetRestoredBounds();
     92 }
     93 
     94 ui::WindowShowState NativeAppWindowViews::GetRestoredState() const {
     95   // Stub implementation. See also ChromeNativeAppWindowViews.
     96   if (IsMaximized())
     97     return ui::SHOW_STATE_MAXIMIZED;
     98   if (IsFullscreen())
     99     return ui::SHOW_STATE_FULLSCREEN;
    100   return ui::SHOW_STATE_NORMAL;
    101 }
    102 
    103 gfx::Rect NativeAppWindowViews::GetBounds() const {
    104   return widget_->GetWindowBoundsInScreen();
    105 }
    106 
    107 void NativeAppWindowViews::Show() {
    108   if (widget_->IsVisible()) {
    109     widget_->Activate();
    110     return;
    111   }
    112   widget_->Show();
    113 }
    114 
    115 void NativeAppWindowViews::ShowInactive() {
    116   if (widget_->IsVisible())
    117     return;
    118 
    119   widget_->ShowInactive();
    120 }
    121 
    122 void NativeAppWindowViews::Hide() { widget_->Hide(); }
    123 
    124 void NativeAppWindowViews::Close() { widget_->Close(); }
    125 
    126 void NativeAppWindowViews::Activate() { widget_->Activate(); }
    127 
    128 void NativeAppWindowViews::Deactivate() { widget_->Deactivate(); }
    129 
    130 void NativeAppWindowViews::Maximize() { widget_->Maximize(); }
    131 
    132 void NativeAppWindowViews::Minimize() { widget_->Minimize(); }
    133 
    134 void NativeAppWindowViews::Restore() { widget_->Restore(); }
    135 
    136 void NativeAppWindowViews::SetBounds(const gfx::Rect& bounds) {
    137   widget_->SetBounds(bounds);
    138 }
    139 
    140 void NativeAppWindowViews::FlashFrame(bool flash) {
    141   widget_->FlashFrame(flash);
    142 }
    143 
    144 bool NativeAppWindowViews::IsAlwaysOnTop() const {
    145   // Stub implementation. See also ChromeNativeAppWindowViews.
    146   return widget_->IsAlwaysOnTop();
    147 }
    148 
    149 void NativeAppWindowViews::SetAlwaysOnTop(bool always_on_top) {
    150   widget_->SetAlwaysOnTop(always_on_top);
    151 }
    152 
    153 gfx::NativeView NativeAppWindowViews::GetHostView() const {
    154   return widget_->GetNativeView();
    155 }
    156 
    157 gfx::Point NativeAppWindowViews::GetDialogPosition(const gfx::Size& size) {
    158   gfx::Size app_window_size = widget_->GetWindowBoundsInScreen().size();
    159   return gfx::Point(app_window_size.width() / 2 - size.width() / 2,
    160                     app_window_size.height() / 2 - size.height() / 2);
    161 }
    162 
    163 gfx::Size NativeAppWindowViews::GetMaximumDialogSize() {
    164   return widget_->GetWindowBoundsInScreen().size();
    165 }
    166 
    167 void NativeAppWindowViews::AddObserver(
    168     web_modal::ModalDialogHostObserver* observer) {
    169   observer_list_.AddObserver(observer);
    170 }
    171 void NativeAppWindowViews::RemoveObserver(
    172     web_modal::ModalDialogHostObserver* observer) {
    173   observer_list_.RemoveObserver(observer);
    174 }
    175 
    176 void NativeAppWindowViews::OnViewWasResized() {
    177   FOR_EACH_OBSERVER(web_modal::ModalDialogHostObserver,
    178                     observer_list_,
    179                     OnPositionRequiresUpdate());
    180 }
    181 
    182 // WidgetDelegate implementation.
    183 
    184 void NativeAppWindowViews::OnWidgetMove() {
    185   app_window_->OnNativeWindowChanged();
    186 }
    187 
    188 views::View* NativeAppWindowViews::GetInitiallyFocusedView() {
    189   return web_view_;
    190 }
    191 
    192 bool NativeAppWindowViews::CanResize() const {
    193   return resizable_ && !size_constraints_.HasFixedSize();
    194 }
    195 
    196 bool NativeAppWindowViews::CanMaximize() const {
    197   return resizable_ && !size_constraints_.HasMaximumSize() &&
    198          !app_window_->window_type_is_panel();
    199 }
    200 
    201 base::string16 NativeAppWindowViews::GetWindowTitle() const {
    202   return app_window_->GetTitle();
    203 }
    204 
    205 bool NativeAppWindowViews::ShouldShowWindowTitle() const {
    206   return app_window_->window_type() == AppWindow::WINDOW_TYPE_V1_PANEL;
    207 }
    208 
    209 bool NativeAppWindowViews::ShouldShowWindowIcon() const {
    210   return app_window_->window_type() == AppWindow::WINDOW_TYPE_V1_PANEL;
    211 }
    212 
    213 void NativeAppWindowViews::SaveWindowPlacement(const gfx::Rect& bounds,
    214                                                ui::WindowShowState show_state) {
    215   views::WidgetDelegate::SaveWindowPlacement(bounds, show_state);
    216   app_window_->OnNativeWindowChanged();
    217 }
    218 
    219 void NativeAppWindowViews::DeleteDelegate() {
    220   widget_->RemoveObserver(this);
    221   app_window_->OnNativeClose();
    222 }
    223 
    224 views::Widget* NativeAppWindowViews::GetWidget() { return widget_; }
    225 
    226 const views::Widget* NativeAppWindowViews::GetWidget() const { return widget_; }
    227 
    228 views::View* NativeAppWindowViews::GetContentsView() {
    229   return this;
    230 }
    231 
    232 bool NativeAppWindowViews::ShouldDescendIntoChildForEventHandling(
    233     gfx::NativeView child,
    234     const gfx::Point& location) {
    235 #if defined(USE_AURA)
    236   if (child->Contains(web_view_->web_contents()->GetNativeView())) {
    237     // App window should claim mouse events that fall within the draggable
    238     // region.
    239     return !draggable_region_.get() ||
    240            !draggable_region_->contains(location.x(), location.y());
    241   }
    242 #endif
    243 
    244   return true;
    245 }
    246 
    247 // WidgetObserver implementation.
    248 
    249 void NativeAppWindowViews::OnWidgetVisibilityChanged(views::Widget* widget,
    250                                                      bool visible) {
    251   app_window_->OnNativeWindowChanged();
    252 }
    253 
    254 void NativeAppWindowViews::OnWidgetActivationChanged(views::Widget* widget,
    255                                                      bool active) {
    256   app_window_->OnNativeWindowChanged();
    257   if (active)
    258     app_window_->OnNativeWindowActivated();
    259 }
    260 
    261 // WebContentsObserver implementation.
    262 
    263 void NativeAppWindowViews::RenderViewCreated(
    264     content::RenderViewHost* render_view_host) {
    265   if (app_window_->requested_transparent_background() &&
    266       CanHaveAlphaEnabled()) {
    267     content::RenderWidgetHostView* view = render_view_host->GetView();
    268     DCHECK(view);
    269     view->SetBackgroundOpaque(false);
    270   }
    271 }
    272 
    273 void NativeAppWindowViews::RenderViewHostChanged(
    274     content::RenderViewHost* old_host,
    275     content::RenderViewHost* new_host) {
    276   OnViewWasResized();
    277 }
    278 
    279 // views::View implementation.
    280 
    281 void NativeAppWindowViews::Layout() {
    282   DCHECK(web_view_);
    283   web_view_->SetBounds(0, 0, width(), height());
    284   OnViewWasResized();
    285 }
    286 
    287 void NativeAppWindowViews::ViewHierarchyChanged(
    288     const ViewHierarchyChangedDetails& details) {
    289   if (details.is_add && details.child == this) {
    290     web_view_ = new views::WebView(NULL);
    291     AddChildView(web_view_);
    292     web_view_->SetWebContents(app_window_->web_contents());
    293   }
    294 }
    295 
    296 gfx::Size NativeAppWindowViews::GetMinimumSize() const {
    297   return size_constraints_.GetMinimumSize();
    298 }
    299 
    300 gfx::Size NativeAppWindowViews::GetMaximumSize() const {
    301   return size_constraints_.GetMaximumSize();
    302 }
    303 
    304 void NativeAppWindowViews::OnFocus() {
    305   web_view_->RequestFocus();
    306 }
    307 
    308 // NativeAppWindow implementation.
    309 
    310 void NativeAppWindowViews::SetFullscreen(int fullscreen_types) {
    311   // Stub implementation. See also ChromeNativeAppWindowViews.
    312   widget_->SetFullscreen(fullscreen_types != AppWindow::FULLSCREEN_TYPE_NONE);
    313 }
    314 
    315 bool NativeAppWindowViews::IsFullscreenOrPending() const {
    316   // Stub implementation. See also ChromeNativeAppWindowViews.
    317   return widget_->IsFullscreen();
    318 }
    319 
    320 bool NativeAppWindowViews::IsDetached() const {
    321   // Stub implementation. See also ChromeNativeAppWindowViews.
    322   return false;
    323 }
    324 
    325 void NativeAppWindowViews::UpdateWindowIcon() { widget_->UpdateWindowIcon(); }
    326 
    327 void NativeAppWindowViews::UpdateWindowTitle() { widget_->UpdateWindowTitle(); }
    328 
    329 void NativeAppWindowViews::UpdateBadgeIcon() {
    330   // Stub implementation. See also ChromeNativeAppWindowViews.
    331 }
    332 
    333 void NativeAppWindowViews::UpdateDraggableRegions(
    334     const std::vector<extensions::DraggableRegion>& regions) {
    335   // Draggable region is not supported for non-frameless window.
    336   if (!frameless_)
    337     return;
    338 
    339   draggable_region_.reset(AppWindow::RawDraggableRegionsToSkRegion(regions));
    340   OnViewWasResized();
    341 }
    342 
    343 SkRegion* NativeAppWindowViews::GetDraggableRegion() {
    344   return draggable_region_.get();
    345 }
    346 
    347 void NativeAppWindowViews::UpdateShape(scoped_ptr<SkRegion> region) {
    348   // Stub implementation. See also ChromeNativeAppWindowViews.
    349 }
    350 
    351 void NativeAppWindowViews::HandleKeyboardEvent(
    352     const content::NativeWebKeyboardEvent& event) {
    353   unhandled_keyboard_event_handler_.HandleKeyboardEvent(event,
    354                                                         GetFocusManager());
    355 }
    356 
    357 bool NativeAppWindowViews::IsFrameless() const { return frameless_; }
    358 
    359 bool NativeAppWindowViews::HasFrameColor() const { return false; }
    360 
    361 SkColor NativeAppWindowViews::ActiveFrameColor() const {
    362   return SK_ColorBLACK;
    363 }
    364 
    365 SkColor NativeAppWindowViews::InactiveFrameColor() const {
    366   return SK_ColorBLACK;
    367 }
    368 
    369 gfx::Insets NativeAppWindowViews::GetFrameInsets() const {
    370   if (frameless_)
    371     return gfx::Insets();
    372 
    373   // The pretend client_bounds passed in need to be large enough to ensure that
    374   // GetWindowBoundsForClientBounds() doesn't decide that it needs more than
    375   // the specified amount of space to fit the window controls in, and return a
    376   // number larger than the real frame insets. Most window controls are smaller
    377   // than 1000x1000px, so this should be big enough.
    378   gfx::Rect client_bounds = gfx::Rect(1000, 1000);
    379   gfx::Rect window_bounds =
    380       widget_->non_client_view()->GetWindowBoundsForClientBounds(client_bounds);
    381   return window_bounds.InsetsFrom(client_bounds);
    382 }
    383 
    384 void NativeAppWindowViews::HideWithApp() {}
    385 
    386 void NativeAppWindowViews::ShowWithApp() {}
    387 
    388 void NativeAppWindowViews::UpdateShelfMenu() {}
    389 
    390 gfx::Size NativeAppWindowViews::GetContentMinimumSize() const {
    391   return size_constraints_.GetMinimumSize();
    392 }
    393 
    394 gfx::Size NativeAppWindowViews::GetContentMaximumSize() const {
    395   return size_constraints_.GetMaximumSize();
    396 }
    397 
    398 void NativeAppWindowViews::SetContentSizeConstraints(
    399     const gfx::Size& min_size, const gfx::Size& max_size) {
    400   size_constraints_.set_minimum_size(min_size);
    401   size_constraints_.set_maximum_size(max_size);
    402 }
    403 
    404 bool NativeAppWindowViews::CanHaveAlphaEnabled() const {
    405   return widget_->IsTranslucentWindowOpacitySupported();
    406 }
    407 
    408 }  // namespace apps
    409