• 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 #if defined(USE_AURA)
22 #include "ui/views/corewm/shadow_types.h"
23 #endif
24 
25 namespace views {
26 
27 ////////////////////////////////////////////////////////////////////////////////
28 // MenuHost, public:
29 
MenuHost(SubmenuView * submenu)30 MenuHost::MenuHost(SubmenuView* submenu)
31     : submenu_(submenu),
32       destroying_(false),
33       ignore_capture_lost_(false) {
34   set_auto_release_capture(false);
35 }
36 
~MenuHost()37 MenuHost::~MenuHost() {
38 }
39 
InitMenuHost(Widget * parent,const gfx::Rect & bounds,View * contents_view,bool do_capture)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 
IsMenuHostVisible()71 bool MenuHost::IsMenuHostVisible() {
72   return IsVisible();
73 }
74 
ShowMenuHost(bool do_capture)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 
HideMenuHost()90 void MenuHost::HideMenuHost() {
91   ignore_capture_lost_ = true;
92   ReleaseMenuHostCapture();
93   Hide();
94   ignore_capture_lost_ = false;
95 }
96 
DestroyMenuHost()97 void MenuHost::DestroyMenuHost() {
98   HideMenuHost();
99   destroying_ = true;
100   static_cast<MenuHostRootView*>(GetRootView())->ClearSubmenu();
101   Close();
102 }
103 
SetMenuHostBounds(const gfx::Rect & bounds)104 void MenuHost::SetMenuHostBounds(const gfx::Rect& bounds) {
105   SetBounds(bounds);
106 }
107 
ReleaseMenuHostCapture()108 void MenuHost::ReleaseMenuHostCapture() {
109   if (native_widget_private()->HasCapture())
110     native_widget_private()->ReleaseCapture();
111 }
112 
113 ////////////////////////////////////////////////////////////////////////////////
114 // MenuHost, Widget overrides:
115 
CreateRootView()116 internal::RootView* MenuHost::CreateRootView() {
117   return new MenuHostRootView(this, submenu_);
118 }
119 
OnMouseCaptureLost()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 
OnNativeWidgetDestroyed()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 
OnOwnerClosing()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