summaryrefslogtreecommitdiffstats
path: root/views
diff options
context:
space:
mode:
authorsky@chromium.org <sky@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2011-04-26 20:42:39 +0000
committersky@chromium.org <sky@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2011-04-26 20:42:39 +0000
commit0773e2f2a00620b996aa1f802eec4006d061a088 (patch)
tree6d65a55af2cd51c9c25e37963a88cdb9a099839a /views
parent5e80615a54f16a9ef0a877001cfd1ea887001ee6 (diff)
downloadchromium_src-0773e2f2a00620b996aa1f802eec4006d061a088.zip
chromium_src-0773e2f2a00620b996aa1f802eec4006d061a088.tar.gz
chromium_src-0773e2f2a00620b996aa1f802eec4006d061a088.tar.bz2
Fixes crash in menu code that would happen if you attempted to show a
context menu while a context menu was already shown. The code would end up attempting to access an object that was since deleted (the MenuItemView). In fixing the crash I realized the logic wasn't quite right for this case either, so fixed that too and added a test. BUG=80392 TEST=see bug R=ben@chromium.org Review URL: http://codereview.chromium.org/6905033 git-svn-id: svn://svn.chromium.org/chrome/trunk/src@83066 0039d316-1c4b-4281-b951-d872f2087c98
Diffstat (limited to 'views')
-rw-r--r--views/controls/menu/menu_controller.cc44
-rw-r--r--views/controls/menu/menu_controller.h15
-rw-r--r--views/controls/menu/menu_host.cc4
-rw-r--r--views/controls/menu/menu_host_root_view.cc2
-rw-r--r--views/controls/menu/menu_host_root_view.h2
5 files changed, 42 insertions, 25 deletions
diff --git a/views/controls/menu/menu_controller.cc b/views/controls/menu/menu_controller.cc
index 2533cef..5703d69 100644
--- a/views/controls/menu/menu_controller.cc
+++ b/views/controls/menu/menu_controller.cc
@@ -400,7 +400,7 @@ void MenuController::OnMousePressed(SubmenuView* source,
DCHECK(!active_mouse_view_);
- MenuPart part = GetMenuPartByScreenCoordinate(source, event.x(), event.y());
+ MenuPart part = GetMenuPart(source, event.location());
if (part.is_scroll())
return; // Ignore presses on scroll buttons.
@@ -418,7 +418,18 @@ void MenuController::OnMousePressed(SubmenuView* source,
#endif
// And close.
- Cancel(EXIT_ALL);
+ ExitType exit_type = EXIT_ALL;
+ if (!menu_stack_.empty()) {
+ // We're running nested menus. Only exit all if the mouse wasn't over one
+ // of the menus from the last run.
+ gfx::Point screen_loc(event.location());
+ View::ConvertPointToScreen(source->GetScrollViewContainer(), &screen_loc);
+ MenuPart last_part = GetMenuPartByScreenCoordinateUsingMenu(
+ menu_stack_.back().item, screen_loc);
+ if (last_part.type != MenuPart::NONE)
+ exit_type = EXIT_OUTERMOST;
+ }
+ Cancel(exit_type);
return;
}
@@ -441,7 +452,7 @@ void MenuController::OnMousePressed(SubmenuView* source,
void MenuController::OnMouseDragged(SubmenuView* source,
const MouseEvent& event) {
- MenuPart part = GetMenuPartByScreenCoordinate(source, event.x(), event.y());
+ MenuPart part = GetMenuPart(source, event.location());
UpdateScrolling(part);
if (!blocking_run_)
@@ -503,7 +514,7 @@ void MenuController::OnMouseReleased(SubmenuView* source,
DCHECK(state_.item);
possible_drag_ = false;
DCHECK(blocking_run_);
- MenuPart part = GetMenuPartByScreenCoordinate(source, event.x(), event.y());
+ MenuPart part = GetMenuPart(source, event.location());
if (event.IsRightMouseButton() && (part.type == MenuPart::MENU_ITEM &&
part.menu)) {
// Set the selection immediately, making sure the submenu is only open
@@ -550,7 +561,7 @@ void MenuController::OnMouseMoved(SubmenuView* source,
if (showing_submenu_)
return;
- MenuPart part = GetMenuPartByScreenCoordinate(source, event.x(), event.y());
+ MenuPart part = GetMenuPart(source, event.location());
UpdateScrolling(part);
@@ -582,7 +593,7 @@ void MenuController::OnMouseEntered(SubmenuView* source,
#if defined(OS_LINUX)
bool MenuController::OnMouseWheel(SubmenuView* source,
const MouseWheelEvent& event) {
- MenuPart part = GetMenuPartByScreenCoordinate(source, event.x(), event.y());
+ MenuPart part = GetMenuPart(source, event.location());
return part.submenu && part.submenu->OnMouseWheel(event);
}
#endif
@@ -1151,25 +1162,26 @@ bool MenuController::IsScrollButtonAt(SubmenuView* source,
return false;
}
-MenuController::MenuPart MenuController::GetMenuPartByScreenCoordinate(
+MenuController::MenuPart MenuController::GetMenuPart(
SubmenuView* source,
- int source_x,
- int source_y) {
- MenuPart part;
-
- gfx::Point screen_loc(source_x, source_y);
+ const gfx::Point& source_loc) {
+ gfx::Point screen_loc(source_loc);
View::ConvertPointToScreen(source->GetScrollViewContainer(), &screen_loc);
+ return GetMenuPartByScreenCoordinateUsingMenu(state_.item, screen_loc);
+}
- MenuItemView* item = state_.item;
+MenuController::MenuPart MenuController::GetMenuPartByScreenCoordinateUsingMenu(
+ MenuItemView* item,
+ const gfx::Point& screen_loc) {
+ MenuPart part;
while (item) {
if (item->HasSubmenu() && item->GetSubmenu()->IsShowing() &&
- GetMenuPartByScreenCoordinateImpl(item->GetSubmenu(), screen_loc,
- &part)) {
+ GetMenuPartByScreenCoordinateImpl(
+ item->GetSubmenu(), screen_loc, &part)) {
return part;
}
item = item->GetParentMenuItem();
}
-
return part;
}
diff --git a/views/controls/menu/menu_controller.h b/views/controls/menu/menu_controller.h
index 177a460..17a5dc0 100644
--- a/views/controls/menu/menu_controller.h
+++ b/views/controls/menu/menu_controller.h
@@ -157,8 +157,7 @@ class MenuController : public MessageLoopForUI::Dispatcher {
gfx::Rect monitor_bounds;
};
- // Used by GetMenuPartByScreenCoordinate to indicate the menu part at a
- // particular location.
+ // Used by GetMenuPart to indicate the menu part at a particular location.
struct MenuPart {
// Type of part.
enum Type {
@@ -264,10 +263,14 @@ class MenuController : public MessageLoopForUI::Dispatcher {
int y,
MenuPart::Type* part);
- // Returns the target for the mouse event.
- MenuPart GetMenuPartByScreenCoordinate(SubmenuView* source,
- int source_x,
- int source_y);
+ // Returns the target for the mouse event. The coordinates are in terms of
+ // source's scroll view container.
+ MenuPart GetMenuPart(SubmenuView* source, const gfx::Point& source_loc);
+
+ // Returns the target for mouse events. The search is done through |item| and
+ // all its parents.
+ MenuPart GetMenuPartByScreenCoordinateUsingMenu(MenuItemView* item,
+ const gfx::Point& screen_loc);
// Implementation of GetMenuPartByScreenCoordinate for a single menu. Returns
// true if the supplied SubmenuView contains the location in terms of the
diff --git a/views/controls/menu/menu_host.cc b/views/controls/menu/menu_host.cc
index dd4db60..1b0f3a6 100644
--- a/views/controls/menu/menu_host.cc
+++ b/views/controls/menu/menu_host.cc
@@ -63,6 +63,7 @@ void MenuHost::HideMenuHost() {
void MenuHost::DestroyMenuHost() {
HideMenuHost();
destroying_ = true;
+ static_cast<MenuHostRootView*>(GetWidget()->GetRootView())->ClearSubmenu();
GetWidget()->Close();
}
@@ -100,8 +101,7 @@ void MenuHost::OnNativeMenuHostCancelCapture() {
return;
MenuController* menu_controller =
submenu_->GetMenuItem()->GetMenuController();
- if (menu_controller &&
- !menu_controller->drag_in_progress())
+ if (menu_controller && !menu_controller->drag_in_progress())
menu_controller->CancelAll();
}
diff --git a/views/controls/menu/menu_host_root_view.cc b/views/controls/menu/menu_host_root_view.cc
index 405eaf8..061d682 100644
--- a/views/controls/menu/menu_host_root_view.cc
+++ b/views/controls/menu/menu_host_root_view.cc
@@ -73,7 +73,7 @@ bool MenuHostRootView::OnMouseWheel(const MouseWheelEvent& event) {
}
MenuController* MenuHostRootView::GetMenuController() {
- return submenu_->GetMenuItem()->GetMenuController();
+ return submenu_ ? submenu_->GetMenuItem()->GetMenuController() : NULL;
}
} // namespace views
diff --git a/views/controls/menu/menu_host_root_view.h b/views/controls/menu/menu_host_root_view.h
index 6ff0c16..12e7cc9 100644
--- a/views/controls/menu/menu_host_root_view.h
+++ b/views/controls/menu/menu_host_root_view.h
@@ -24,6 +24,8 @@ class MenuHostRootView : public RootView {
MenuHostRootView(Widget* widget, SubmenuView* submenu);
~MenuHostRootView();
+ void ClearSubmenu() { submenu_ = NULL; }
+
// Overridden from View:
virtual bool OnMousePressed(const MouseEvent& event) OVERRIDE;
virtual bool OnMouseDragged(const MouseEvent& event) OVERRIDE;