Home | History | Annotate | Download | only in menu
      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 "ui/views/controls/menu/menu_host.h"
      6 
      7 #include "base/auto_reset.h"
      8 #include "base/debug/trace_event.h"
      9 #include "ui/events/gestures/gesture_recognizer.h"
     10 #include "ui/gfx/path.h"
     11 #include "ui/native_theme/native_theme.h"
     12 #include "ui/views/controls/menu/menu_controller.h"
     13 #include "ui/views/controls/menu/menu_host_root_view.h"
     14 #include "ui/views/controls/menu/menu_item_view.h"
     15 #include "ui/views/controls/menu/menu_scroll_view_container.h"
     16 #include "ui/views/controls/menu/submenu_view.h"
     17 #include "ui/views/round_rect_painter.h"
     18 #include "ui/views/widget/native_widget_private.h"
     19 #include "ui/views/widget/widget.h"
     20 
     21 #if defined(USE_AURA)
     22 #include "ui/views/corewm/shadow_types.h"
     23 #endif
     24 
     25 namespace views {
     26 
     27 ////////////////////////////////////////////////////////////////////////////////
     28 // MenuHost, public:
     29 
     30 MenuHost::MenuHost(SubmenuView* submenu)
     31     : submenu_(submenu),
     32       destroying_(false),
     33       ignore_capture_lost_(false) {
     34   set_auto_release_capture(false);
     35 }
     36 
     37 MenuHost::~MenuHost() {
     38 }
     39 
     40 void MenuHost::InitMenuHost(Widget* parent,
     41                             const gfx::Rect& bounds,
     42                             View* contents_view,
     43                             bool do_capture) {
     44   TRACE_EVENT0("views", "MenuHost::InitMenuHost");
     45   Widget::InitParams params(Widget::InitParams::TYPE_MENU);
     46   const MenuController* menu_controller =
     47       submenu_->GetMenuItem()->GetMenuController();
     48   const MenuConfig& menu_config = submenu_->GetMenuItem()->GetMenuConfig();
     49   bool rounded_border = menu_controller && menu_config.corner_radius > 0;
     50   bool bubble_border = submenu_->GetScrollViewContainer() &&
     51                        submenu_->GetScrollViewContainer()->HasBubbleBorder();
     52   params.has_dropshadow = !bubble_border;
     53   params.opacity = (bubble_border || rounded_border) ?
     54       Widget::InitParams::TRANSLUCENT_WINDOW :
     55       Widget::InitParams::OPAQUE_WINDOW;
     56   params.parent = parent ? parent->GetNativeView() : NULL;
     57   params.bounds = bounds;
     58   Init(params);
     59 
     60 #if defined(USE_AURA)
     61   if (bubble_border)
     62     SetShadowType(GetNativeView(), views::corewm::SHADOW_TYPE_NONE);
     63 #endif
     64 
     65   SetContentsView(contents_view);
     66   if (bubble_border || rounded_border)
     67     SetOpacity(0);
     68   ShowMenuHost(do_capture);
     69 }
     70 
     71 bool MenuHost::IsMenuHostVisible() {
     72   return IsVisible();
     73 }
     74 
     75 void MenuHost::ShowMenuHost(bool do_capture) {
     76   // Doing a capture may make us get capture lost. Ignore it while we're in the
     77   // process of showing.
     78   base::AutoReset<bool> reseter(&ignore_capture_lost_, true);
     79   Show();
     80   if (do_capture) {
     81 #if defined(USE_AURA)
     82     // Cancel existing touches, so we don't miss some touch release/cancel
     83     // events due to the menu taking capture.
     84     ui::GestureRecognizer::Get()->TransferEventsTo(GetNativeWindow(), NULL);
     85 #endif  // USE_AURA
     86     native_widget_private()->SetCapture();
     87   }
     88 }
     89 
     90 void MenuHost::HideMenuHost() {
     91   ignore_capture_lost_ = true;
     92   ReleaseMenuHostCapture();
     93   Hide();
     94   ignore_capture_lost_ = false;
     95 }
     96 
     97 void MenuHost::DestroyMenuHost() {
     98   HideMenuHost();
     99   destroying_ = true;
    100   static_cast<MenuHostRootView*>(GetRootView())->ClearSubmenu();
    101   Close();
    102 }
    103 
    104 void MenuHost::SetMenuHostBounds(const gfx::Rect& bounds) {
    105   SetBounds(bounds);
    106 }
    107 
    108 void MenuHost::ReleaseMenuHostCapture() {
    109   if (native_widget_private()->HasCapture())
    110     native_widget_private()->ReleaseCapture();
    111 }
    112 
    113 ////////////////////////////////////////////////////////////////////////////////
    114 // MenuHost, Widget overrides:
    115 
    116 internal::RootView* MenuHost::CreateRootView() {
    117   return new MenuHostRootView(this, submenu_);
    118 }
    119 
    120 void MenuHost::OnMouseCaptureLost() {
    121   if (destroying_ || ignore_capture_lost_)
    122     return;
    123   MenuController* menu_controller =
    124       submenu_->GetMenuItem()->GetMenuController();
    125   if (menu_controller && !menu_controller->drag_in_progress())
    126     menu_controller->CancelAll();
    127   Widget::OnMouseCaptureLost();
    128 }
    129 
    130 void MenuHost::OnNativeWidgetDestroyed() {
    131   if (!destroying_) {
    132     // We weren't explicitly told to destroy ourselves, which means the menu was
    133     // deleted out from under us (the window we're parented to was closed). Tell
    134     // the SubmenuView to drop references to us.
    135     submenu_->MenuHostDestroyed();
    136   }
    137   Widget::OnNativeWidgetDestroyed();
    138 }
    139 
    140 void MenuHost::OnOwnerClosing() {
    141   if (destroying_)
    142     return;
    143 
    144   MenuController* menu_controller =
    145       submenu_->GetMenuItem()->GetMenuController();
    146   if (menu_controller && !menu_controller->drag_in_progress())
    147     menu_controller->CancelAll();
    148 }
    149 
    150 }  // namespace views
    151