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