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