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.
5 #include "ui/views/controls/menu/menu_host.h"
7 #include "base/auto_reset.h"
8 #include "base/trace_event/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"
23 ////////////////////////////////////////////////////////////////////////////////
26 MenuHost::MenuHost(SubmenuView
* submenu
)
29 ignore_capture_lost_(false) {
30 set_auto_release_capture(false);
33 MenuHost::~MenuHost() {
36 void MenuHost::InitMenuHost(Widget
* parent
,
37 const gfx::Rect
& bounds
,
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
;
57 SetContentsView(contents_view
);
58 ShowMenuHost(do_capture
);
61 bool MenuHost::IsMenuHostVisible() {
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);
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()->CancelActiveTouchesExcept(nullptr);
74 native_widget_private()->SetCapture();
78 void MenuHost::HideMenuHost() {
79 ignore_capture_lost_
= true;
80 ReleaseMenuHostCapture();
82 ignore_capture_lost_
= false;
85 void MenuHost::DestroyMenuHost() {
88 static_cast<MenuHostRootView
*>(GetRootView())->ClearSubmenu();
92 void MenuHost::SetMenuHostBounds(const gfx::Rect
& bounds
) {
96 void MenuHost::ReleaseMenuHostCapture() {
97 if (native_widget_private()->HasCapture())
98 native_widget_private()->ReleaseCapture();
101 ////////////////////////////////////////////////////////////////////////////////
102 // MenuHost, Widget overrides:
104 internal::RootView
* MenuHost::CreateRootView() {
105 return new MenuHostRootView(this, submenu_
);
108 void MenuHost::OnMouseCaptureLost() {
109 if (destroying_
|| ignore_capture_lost_
)
111 MenuController
* menu_controller
=
112 submenu_
->GetMenuItem()->GetMenuController();
113 if (menu_controller
&& !menu_controller
->drag_in_progress())
114 menu_controller
->CancelAll();
115 Widget::OnMouseCaptureLost();
118 void MenuHost::OnNativeWidgetDestroyed() {
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();
125 Widget::OnNativeWidgetDestroyed();
128 void MenuHost::OnOwnerClosing() {
132 MenuController
* menu_controller
=
133 submenu_
->GetMenuItem()->GetMenuController();
134 if (menu_controller
&& !menu_controller
->drag_in_progress())
135 menu_controller
->CancelAll();
138 void MenuHost::OnDragWillStart() {
139 MenuController
* menu_controller
=
140 submenu_
->GetMenuItem()->GetMenuController();
141 DCHECK(menu_controller
);
142 menu_controller
->OnDragWillStart();
145 void MenuHost::OnDragComplete() {
146 MenuController
* menu_controller
=
147 submenu_
->GetMenuItem()->GetMenuController();
148 if (destroying_
|| !menu_controller
)
151 bool should_close
= true;
152 // If the view came from outside menu code (i.e., not a MenuItemView), we
153 // should consult the MenuDelegate to determine whether or not to close on
155 if (!menu_controller
->did_initiate_drag()) {
156 MenuDelegate
* menu_delegate
= submenu_
->GetMenuItem()->GetDelegate();
158 menu_delegate
? menu_delegate
->ShouldCloseOnDragComplete() : should_close
;
160 menu_controller
->OnDragComplete(should_close
);
162 // We may have lost capture in the drag and drop, but are remaining open.
163 // Return capture so we get MouseCaptureLost events.
165 native_widget_private()->SetCapture();