summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--chrome/browser/views/bookmark_bar_view.cc148
-rw-r--r--chrome/browser/views/bookmark_bar_view.h39
-rw-r--r--chrome/browser/views/bookmark_bar_view_test.cc3
-rw-r--r--chrome/browser/views/bookmark_context_menu.cc2
-rw-r--r--chrome/browser/views/bookmark_manager_view.cc4
-rw-r--r--chrome/browser/views/bookmark_menu_button.cc6
-rw-r--r--chrome/browser/views/bookmark_menu_controller_views.cc117
-rw-r--r--chrome/browser/views/bookmark_menu_controller_views.h41
-rw-r--r--views/controls/button/menu_button.cc1
-rw-r--r--views/controls/menu/menu_controller.cc117
-rw-r--r--views/controls/menu/menu_controller.h11
-rw-r--r--views/controls/menu/menu_delegate.h16
-rw-r--r--views/controls/menu/menu_host_gtk.cc69
-rw-r--r--views/controls/menu/menu_host_gtk.h1
-rw-r--r--views/controls/menu/menu_host_win.cc19
-rw-r--r--views/controls/menu/menu_host_win.h1
-rw-r--r--views/controls/menu/menu_item_view.cc25
-rw-r--r--views/controls/menu/menu_item_view.h2
-rw-r--r--views/controls/menu/submenu_view.cc2
-rw-r--r--views/screen.h3
-rw-r--r--views/screen_gtk.cc14
-rw-r--r--views/screen_win.cc5
22 files changed, 437 insertions, 209 deletions
diff --git a/chrome/browser/views/bookmark_bar_view.cc b/chrome/browser/views/bookmark_bar_view.cc
index 5eba994..1eb8d63 100644
--- a/chrome/browser/views/bookmark_bar_view.cc
+++ b/chrome/browser/views/bookmark_bar_view.cc
@@ -38,6 +38,8 @@
#include "grit/generated_resources.h"
#include "grit/theme_resources.h"
#include "views/controls/button/menu_button.h"
+#include "views/controls/label.h"
+#include "views/controls/button/menu_button.h"
#include "views/controls/menu/menu_item_view.h"
#include "views/drag_utils.h"
#include "views/view_constants.h"
@@ -797,6 +799,71 @@ views::MenuItemView* BookmarkBarView::GetDropMenu() {
return bookmark_drop_menu_ ? bookmark_drop_menu_->menu() : NULL;
}
+const BookmarkNode* BookmarkBarView::GetNodeForButtonAt(const gfx::Point& loc,
+ int* start_index) {
+ *start_index = 0;
+
+ if (loc.x() < 0 || loc.x() >= width() || loc.y() < 0 || loc.y() >= height())
+ return NULL;
+
+ // Check the buttons first.
+ for (int i = 0; i < GetBookmarkButtonCount(); ++i) {
+ views::View* child = GetChildViewAt(i);
+ if (!child->IsVisible())
+ break;
+ if (child->bounds().Contains(loc))
+ return model_->GetBookmarkBarNode()->GetChild(i);
+ }
+
+ // Then the overflow button.
+ if (overflow_button_->IsVisible() &&
+ overflow_button_->bounds().Contains(loc)) {
+ *start_index = GetFirstHiddenNodeIndex();
+ return model_->GetBookmarkBarNode();
+ }
+
+ // And finally the other folder.
+ if (other_bookmarked_button_->bounds().Contains(loc))
+ return model_->other_node();
+
+ return NULL;
+}
+
+views::MenuButton* BookmarkBarView::GetMenuButtonForNode(
+ const BookmarkNode* node) {
+ if (node == model_->other_node())
+ return other_bookmarked_button_;
+ if (node == model_->GetBookmarkBarNode())
+ return overflow_button_;
+ int index = model_->GetBookmarkBarNode()->IndexOfChild(node);
+ if (index == -1 || !node->is_folder())
+ return NULL;
+ return static_cast<views::MenuButton*>(GetChildViewAt(index));
+}
+
+void BookmarkBarView::GetAnchorPositionAndStartIndexForButton(
+ views::MenuButton* button,
+ MenuItemView::AnchorPosition* anchor,
+ int* start_index) {
+ if (button == other_bookmarked_button_ || button == overflow_button_)
+ *anchor = MenuItemView::TOPRIGHT;
+ else
+ *anchor = MenuItemView::TOPLEFT;
+
+ // Invert orientation if right to left.
+ if (UILayoutIsRightToLeft()) {
+ if (*anchor == MenuItemView::TOPRIGHT)
+ *anchor = MenuItemView::TOPLEFT;
+ else
+ *anchor = MenuItemView::TOPRIGHT;
+ }
+
+ if (button == overflow_button_)
+ *start_index = GetFirstHiddenNodeIndex();
+ else
+ *start_index = 0;
+}
+
void BookmarkBarView::Init() {
// Note that at this point we're not in a hierarchy so GetThemeProvider() will
// return NULL. When we're inserted into a hierarchy, we'll call
@@ -1072,55 +1139,24 @@ int BookmarkBarView::GetDragOperations(View* sender, int x, int y) {
void BookmarkBarView::RunMenu(views::View* view, const gfx::Point& pt) {
const BookmarkNode* node;
- MenuItemView::AnchorPosition anchor_point = MenuItemView::TOPLEFT;
-
- // When we set the menu's position, we must take into account the mirrored
- // position of the View relative to its parent. This can be easily done by
- // passing the right flag to View::x().
- int x = view->GetX(APPLY_MIRRORING_TRANSFORMATION);
- int bar_height = height() - kMenuOffset;
-
- if (IsDetached())
- bar_height -= kNewtabVerticalPadding;
int start_index = 0;
if (view == other_bookmarked_button_) {
- UserMetrics::RecordAction(L"BookmarkBar_ShowOtherBookmarks", profile_);
-
node = model_->other_node();
- if (UILayoutIsRightToLeft())
- anchor_point = MenuItemView::TOPLEFT;
- else
- anchor_point = MenuItemView::TOPRIGHT;
} else if (view == overflow_button_) {
node = model_->GetBookmarkBarNode();
start_index = GetFirstHiddenNodeIndex();
- if (UILayoutIsRightToLeft())
- anchor_point = MenuItemView::TOPLEFT;
- else
- anchor_point = MenuItemView::TOPRIGHT;
} else {
int button_index = GetChildIndex(view);
DCHECK_NE(-1, button_index);
node = model_->GetBookmarkBarNode()->GetChild(button_index);
-
- // When the UI layout is RTL, the bookmarks are laid out from right to left
- // and therefore when we display the menu we want it to be aligned with the
- // bottom right corner of the bookmark item.
- if (UILayoutIsRightToLeft())
- anchor_point = MenuItemView::TOPRIGHT;
- else
- anchor_point = MenuItemView::TOPLEFT;
}
- gfx::Point screen_loc(x, 0);
- View::ConvertPointToScreen(this, &screen_loc);
+
bookmark_menu_ = new BookmarkMenuController(
browser_, profile_, page_navigator_, GetWindow()->GetNativeWindow(),
node, start_index, false);
bookmark_menu_->set_observer(this);
- bookmark_menu_->RunMenuAt(gfx::Rect(screen_loc.x(), screen_loc.y(),
- view->width(), bar_height),
- anchor_point, false);
+ bookmark_menu_->RunMenuAt(this, false);
}
void BookmarkBarView::ButtonPressed(views::Button* sender,
@@ -1298,54 +1334,20 @@ void BookmarkBarView::ShowDropFolderForNode(const BookmarkNode* node) {
bookmark_drop_menu_->Cancel();
}
+ views::MenuButton* menu_button = GetMenuButtonForNode(node);
+ if (!menu_button)
+ return;
+
int start_index = 0;
- View* view_to_position_menu_from;
-
- // Note that both the anchor position and the position of the menu itself
- // change depending on the locale. Also note that we must apply the
- // mirroring transformation when querying for the child View bounds
- // (View::x(), specifically) so that we end up with the correct screen
- // coordinates if the View in question is mirrored.
- MenuItemView::AnchorPosition anchor = MenuItemView::TOPLEFT;
- if (node == model_->other_node()) {
- view_to_position_menu_from = other_bookmarked_button_;
- if (!UILayoutIsRightToLeft())
- anchor = MenuItemView::TOPRIGHT;
- } else if (node == model_->GetBookmarkBarNode()) {
- DCHECK(overflow_button_->IsVisible());
- view_to_position_menu_from = overflow_button_;
+ if (node == model_->GetBookmarkBarNode())
start_index = GetFirstHiddenNodeIndex();
- if (!UILayoutIsRightToLeft())
- anchor = MenuItemView::TOPRIGHT;
- } else {
- // Make sure node is still valid.
- int index = -1;
- const BookmarkNode* bb_node = model_->GetBookmarkBarNode();
- for (int i = 0; i < GetBookmarkButtonCount(); ++i) {
- if (bb_node->GetChild(i) == node) {
- index = i;
- break;
- }
- }
- if (index == -1)
- return;
- view_to_position_menu_from = GetBookmarkButton(index);
- if (UILayoutIsRightToLeft())
- anchor = MenuItemView::TOPRIGHT;
- }
drop_info_->is_menu_showing = true;
bookmark_drop_menu_ = new BookmarkMenuController(
browser_, profile_, page_navigator_, GetWindow()->GetNativeWindow(),
node, start_index, false);
bookmark_drop_menu_->set_observer(this);
- gfx::Point screen_loc;
- View::ConvertPointToScreen(view_to_position_menu_from, &screen_loc);
- bookmark_drop_menu_->RunMenuAt(
- gfx::Rect(screen_loc.x(), screen_loc.y(),
- view_to_position_menu_from->width(),
- view_to_position_menu_from->height()),
- anchor, true);
+ bookmark_drop_menu_->RunMenuAt(this, true);
}
void BookmarkBarView::StopShowFolderDropMenuTimer() {
diff --git a/chrome/browser/views/bookmark_bar_view.h b/chrome/browser/views/bookmark_bar_view.h
index c7008fb7..0d79cc6 100644
--- a/chrome/browser/views/bookmark_bar_view.h
+++ b/chrome/browser/views/bookmark_bar_view.h
@@ -13,18 +13,19 @@
#include "chrome/browser/views/bookmark_menu_controller_views.h"
#include "chrome/browser/views/detachable_toolbar_view.h"
#include "chrome/common/notification_registrar.h"
-#include "views/controls/button/menu_button.h"
-#include "views/controls/label.h"
+#include "views/controls/button/button.h"
#include "views/controls/menu/view_menu_delegate.h"
-#include "views/view.h"
-#include "third_party/skia/include/core/SkRect.h"
class Browser;
class PageNavigator;
class PrefService;
namespace views {
+class CustomButton;
+class Label;
+class MenuButton;
class MenuItemView;
+class TextButton;
}
// BookmarkBarView renders the BookmarkModel. Each starred entry on the
@@ -173,7 +174,7 @@ class BookmarkBarView : public DetachableToolbarView,
// Returns the button responsible for showing bookmarks in the other bookmark
// folder.
- views::TextButton* other_bookmarked_button() const {
+ views::MenuButton* other_bookmarked_button() const {
return other_bookmarked_button_;
}
@@ -187,7 +188,25 @@ class BookmarkBarView : public DetachableToolbarView,
views::MenuItemView* GetContextMenu();
// Returns the button used when not all the items on the bookmark bar fit.
- views::TextButton* overflow_button() const { return overflow_button_; }
+ views::MenuButton* overflow_button() const { return overflow_button_; }
+
+ // If |loc| is over a bookmark button the node is returned corresponding
+ // to the button and |start_index| is set to 0. If a overflow button is
+ // showing and |loc| is over the overflow button, the bookmark bar node is
+ // returned and |start_index| is set to the index of the first node
+ // contained in the overflow menu.
+ const BookmarkNode* GetNodeForButtonAt(const gfx::Point& loc,
+ int* start_index);
+
+ // Returns the MenuButton for node.
+ views::MenuButton* GetMenuButtonForNode(const BookmarkNode* node);
+
+ // Returns the position to anchor the menu for |button| at, the index of the
+ // first child of the node to build the menu from.
+ void GetAnchorPositionAndStartIndexForButton(
+ views::MenuButton* button,
+ views::MenuItemView::AnchorPosition* anchor,
+ int* start_index);
// Maximum size of buttons on the bookmark bar.
static const int kMaxButtonWidth;
@@ -317,12 +336,8 @@ class BookmarkBarView : public DetachableToolbarView,
// Returns the drag operations for the specified button.
virtual int GetDragOperations(views::View* sender, int x, int y);
- // ViewMenuDelegate method. 3 types of menus may be shown:
- // . the menu allowing the user to choose when the bookmark bar is visible.
- // . most recently bookmarked menu
- // . menu for star groups.
- // The latter two are handled by a MenuRunner, which builds the appropriate
- // menu.
+ // ViewMenuDelegate method. Ends up creating a BookmarkMenuController to
+ // show the menu.
virtual void RunMenu(views::View* view, const gfx::Point& pt);
// Invoked when a star entry corresponding to a URL on the bookmark bar is
diff --git a/chrome/browser/views/bookmark_bar_view_test.cc b/chrome/browser/views/bookmark_bar_view_test.cc
index 751a1ec..cedfd19 100644
--- a/chrome/browser/views/bookmark_bar_view_test.cc
+++ b/chrome/browser/views/bookmark_bar_view_test.cc
@@ -14,6 +14,7 @@
#include "chrome/common/pref_service.h"
#include "chrome/test/testing_profile.h"
#include "chrome/test/interactive_ui/view_event_test_base.h"
+#include "views/controls/button/menu_button.h"
#include "views/controls/button/text_button.h"
#include "views/controls/menu/menu_controller.h"
#include "views/controls/menu/menu_item_view.h"
@@ -279,7 +280,7 @@ class BookmarkBarViewTest3 : public BookmarkBarViewEventTestBase {
virtual void DoTestOnMessageLoop() {
// Move the mouse to the first folder on the bookmark bar and press the
// mouse.
- views::TextButton* button = bb_view_->other_bookmarked_button();
+ views::MenuButton* button = bb_view_->other_bookmarked_button();
ui_controls::MoveMouseToCenterAndPress(button, ui_controls::LEFT,
ui_controls::DOWN | ui_controls::UP,
CreateEventTask(this, &BookmarkBarViewTest3::Step2));
diff --git a/chrome/browser/views/bookmark_context_menu.cc b/chrome/browser/views/bookmark_context_menu.cc
index ddb0d5b..a3f3a15 100644
--- a/chrome/browser/views/bookmark_context_menu.cc
+++ b/chrome/browser/views/bookmark_context_menu.cc
@@ -37,7 +37,7 @@ void BookmarkContextMenu::RunMenuAt(const gfx::Point& point) {
views::MenuItemView::AnchorPosition anchor =
(l10n_util::GetTextDirection() == l10n_util::RIGHT_TO_LEFT) ?
views::MenuItemView::TOPRIGHT : views::MenuItemView::TOPLEFT;
- menu_->RunMenuAt(parent_window_, gfx::Rect(point.x(), point.y(), 0, 0),
+ menu_->RunMenuAt(parent_window_, NULL, gfx::Rect(point.x(), point.y(), 0, 0),
anchor, true);
}
diff --git a/chrome/browser/views/bookmark_manager_view.cc b/chrome/browser/views/bookmark_manager_view.cc
index fafa228..ce40b28 100644
--- a/chrome/browser/views/bookmark_manager_view.cc
+++ b/chrome/browser/views/bookmark_manager_view.cc
@@ -795,8 +795,8 @@ void BookmarkManagerView::ShowToolsMenu(int x, int y) {
views::MenuItemView::AnchorPosition anchor =
UILayoutIsRightToLeft() ? views::MenuItemView::TOPRIGHT :
views::MenuItemView::TOPLEFT;
- menu.RunMenuAt(GetWidget()->GetNativeView(), gfx::Rect(x, y, 0, 0), anchor,
- true);
+ menu.RunMenuAt(GetWidget()->GetNativeView(), NULL, gfx::Rect(x, y, 0, 0),
+ anchor, true);
}
void BookmarkManagerView::ShowImportBookmarksFileChooser() {
diff --git a/chrome/browser/views/bookmark_menu_button.cc b/chrome/browser/views/bookmark_menu_button.cc
index 4255ffd..988f1f0 100644
--- a/chrome/browser/views/bookmark_menu_button.cc
+++ b/chrome/browser/views/bookmark_menu_button.cc
@@ -133,15 +133,11 @@ void BookmarkMenuButton::RunMenu(views::View* source,
views::MenuItemView::AnchorPosition anchor = views::MenuItemView::TOPRIGHT;
if (UILayoutIsRightToLeft())
anchor = views::MenuItemView::TOPLEFT;
- gfx::Point button_origin;
- ConvertPointToScreen(this, &button_origin);
- gfx::Rect menu_bounds(button_origin.x(), button_origin.y(), width(),
- height());
if (for_drop) {
bookmark_drop_menu_ = menu;
bookmark_drop_menu_->set_observer(this);
}
- menu->RunMenuAt(menu_bounds, views::MenuItemView::TOPRIGHT, for_drop);
+ menu->RunMenuAt(this, views::MenuItemView::TOPRIGHT, for_drop);
}
BookmarkModel* BookmarkMenuButton::GetBookmarkModel() {
diff --git a/chrome/browser/views/bookmark_menu_controller_views.cc b/chrome/browser/views/bookmark_menu_controller_views.cc
index 58ff604..80bf767 100644
--- a/chrome/browser/views/bookmark_menu_controller_views.cc
+++ b/chrome/browser/views/bookmark_menu_controller_views.cc
@@ -7,16 +7,21 @@
#include "app/l10n_util.h"
#include "app/os_exchange_data.h"
#include "app/resource_bundle.h"
+#include "base/stl_util-inl.h"
#include "chrome/browser/bookmarks/bookmark_drag_data.h"
#include "chrome/browser/bookmarks/bookmark_utils.h"
#include "chrome/browser/metrics/user_metrics.h"
#include "chrome/browser/profile.h"
#include "chrome/browser/tab_contents/page_navigator.h"
+#include "chrome/browser/views/bookmark_bar_view.h"
#include "chrome/browser/views/event_utils.h"
#include "chrome/common/page_transition_types.h"
#include "grit/app_resources.h"
#include "grit/generated_resources.h"
#include "grit/theme_resources.h"
+#include "views/controls/button/menu_button.h"
+
+using views::MenuItemView;
BookmarkMenuController::BookmarkMenuController(Browser* browser,
Profile* profile,
@@ -30,28 +35,45 @@ BookmarkMenuController::BookmarkMenuController(Browser* browser,
page_navigator_(navigator),
parent_(parent),
node_(node),
+ menu_(NULL),
observer_(NULL),
for_drop_(false),
- show_other_folder_(show_other_folder) {
- menu_.reset(new views::MenuItemView(this));
- int next_menu_id = 1;
- menu_id_to_node_map_[menu_->GetCommand()] = node;
- menu_->set_has_icons(true);
- BuildMenu(node, start_child_index, menu_.get(), &next_menu_id);
- if (show_other_folder)
- BuildOtherFolderMenu(&next_menu_id);
+ show_other_folder_(show_other_folder),
+ bookmark_bar_(NULL),
+ next_menu_id_(1) {
+ menu_ = CreateMenu(node, start_child_index);
+}
+
+void BookmarkMenuController::RunMenuAt(BookmarkBarView* bookmark_bar,
+ bool for_drop) {
+ bookmark_bar_ = bookmark_bar;
+ views::MenuButton* menu_button = bookmark_bar_->GetMenuButtonForNode(node_);
+ DCHECK(menu_button);
+ MenuItemView::AnchorPosition anchor;
+ int start_index;
+ bookmark_bar_->GetAnchorPositionAndStartIndexForButton(
+ menu_button, &anchor, &start_index);
+ RunMenuAt(menu_button, anchor, for_drop);
}
void BookmarkMenuController::RunMenuAt(
- const gfx::Rect& bounds,
- views::MenuItemView::AnchorPosition position,
+ views::MenuButton* button,
+ MenuItemView::AnchorPosition position,
bool for_drop) {
+ gfx::Point screen_loc;
+ views::View::ConvertPointToScreen(button, &screen_loc);
+ // Subtract 1 from the height to make the popup flush with the button border.
+ gfx::Rect bounds(screen_loc.x(), screen_loc.y(), button->width(),
+ button->height() - 1);
for_drop_ = for_drop;
profile_->GetBookmarkModel()->AddObserver(this);
+ // The constructor creates the initial menu and that is all we should have
+ // at this point.
+ DCHECK(node_to_menu_map_.size() == 1);
if (for_drop) {
menu_->RunMenuForDropAt(parent_, bounds, position);
} else {
- menu_->RunMenuAt(parent_, bounds, position, false);
+ menu_->RunMenuAt(parent_, button, bounds, position, false);
delete this;
}
}
@@ -74,7 +96,7 @@ void BookmarkMenuController::ExecuteCommand(int id, int mouse_event_flags) {
}
bool BookmarkMenuController::GetDropFormats(
- views::MenuItemView* menu,
+ MenuItemView* menu,
int* formats,
std::set<OSExchangeData::CustomFormat>* custom_formats) {
*formats = OSExchangeData::URL;
@@ -82,11 +104,11 @@ bool BookmarkMenuController::GetDropFormats(
return true;
}
-bool BookmarkMenuController::AreDropTypesRequired(views::MenuItemView* menu) {
+bool BookmarkMenuController::AreDropTypesRequired(MenuItemView* menu) {
return true;
}
-bool BookmarkMenuController::CanDrop(views::MenuItemView* menu,
+bool BookmarkMenuController::CanDrop(MenuItemView* menu,
const OSExchangeData& data) {
// Only accept drops of 1 node, which is the case for all data dragged from
// bookmark bar and menus.
@@ -113,7 +135,7 @@ bool BookmarkMenuController::CanDrop(views::MenuItemView* menu,
}
int BookmarkMenuController::GetDropOperation(
- views::MenuItemView* item,
+ MenuItemView* item,
const views::DropTargetEvent& event,
DropPosition* position) {
// Should only get here if we have drop data.
@@ -138,7 +160,7 @@ int BookmarkMenuController::GetDropOperation(
profile_, event, drop_data_, drop_parent, index_to_drop_at);
}
-int BookmarkMenuController::OnPerformDrop(views::MenuItemView* menu,
+int BookmarkMenuController::OnPerformDrop(MenuItemView* menu,
DropPosition position,
const views::DropTargetEvent& event) {
const BookmarkNode* drop_node = menu_id_to_node_map_[menu->GetCommand()];
@@ -163,7 +185,7 @@ int BookmarkMenuController::OnPerformDrop(views::MenuItemView* menu,
return result;
}
-bool BookmarkMenuController::ShowContextMenu(views::MenuItemView* source,
+bool BookmarkMenuController::ShowContextMenu(MenuItemView* source,
int id,
int x,
int y,
@@ -183,17 +205,17 @@ bool BookmarkMenuController::ShowContextMenu(views::MenuItemView* source,
return true;
}
-void BookmarkMenuController::DropMenuClosed(views::MenuItemView* menu) {
+void BookmarkMenuController::DropMenuClosed(MenuItemView* menu) {
delete this;
}
-bool BookmarkMenuController::CanDrag(views::MenuItemView* menu) {
+bool BookmarkMenuController::CanDrag(MenuItemView* menu) {
const BookmarkNode* node = menu_id_to_node_map_[menu->GetCommand()];
// Don't let users drag the other folder.
return node->GetParent() != profile_->GetBookmarkModel()->root_node();
}
-void BookmarkMenuController::WriteDragData(views::MenuItemView* sender,
+void BookmarkMenuController::WriteDragData(MenuItemView* sender,
OSExchangeData* data) {
DCHECK(sender && data);
@@ -203,11 +225,41 @@ void BookmarkMenuController::WriteDragData(views::MenuItemView* sender,
drag_data.Write(profile_, data);
}
-int BookmarkMenuController::GetDragOperations(views::MenuItemView* sender) {
+int BookmarkMenuController::GetDragOperations(MenuItemView* sender) {
return bookmark_utils::BookmarkDragOperation(
menu_id_to_node_map_[sender->GetCommand()]);
}
+views::MenuItemView* BookmarkMenuController::GetSiblingMenu(
+ views::MenuItemView* menu,
+ const gfx::Point& screen_point,
+ views::MenuItemView::AnchorPosition* anchor,
+ bool* has_mnemonics,
+ views::MenuButton** button) {
+ if (show_other_folder_ || !bookmark_bar_ || for_drop_)
+ return NULL;
+ gfx::Point bookmark_bar_loc(screen_point);
+ views::View::ConvertPointToView(NULL, bookmark_bar_, &bookmark_bar_loc);
+ int start_index;
+ const BookmarkNode* node =
+ bookmark_bar_->GetNodeForButtonAt(bookmark_bar_loc, &start_index);
+ if (!node || !node->is_folder())
+ return NULL;
+
+ MenuItemView* alt_menu = node_to_menu_map_[node];
+ if (!alt_menu)
+ alt_menu = CreateMenu(node, start_index);
+
+ if (alt_menu)
+ menu_ = alt_menu;
+
+ *button = bookmark_bar_->GetMenuButtonForNode(node);
+ bookmark_bar_->GetAnchorPositionAndStartIndexForButton(
+ *button, anchor, &start_index);
+ *has_mnemonics = false;
+ return alt_menu;
+}
+
void BookmarkMenuController::BookmarkModelChanged() {
menu_->Cancel();
}
@@ -218,13 +270,27 @@ void BookmarkMenuController::BookmarkNodeFavIconLoaded(
menu_->SetIcon(model->GetFavIcon(node), node_to_menu_id_map_[node]);
}
-void BookmarkMenuController::BuildOtherFolderMenu(int* next_menu_id) {
+MenuItemView* BookmarkMenuController::CreateMenu(const BookmarkNode* parent,
+ int start_child_index) {
+ MenuItemView* menu = new MenuItemView(this);
+ menu->SetCommand(next_menu_id_++);
+ menu_id_to_node_map_[menu->GetCommand()] = parent;
+ menu->set_has_icons(true);
+ BuildMenu(parent, start_child_index, menu, &next_menu_id_);
+ if (show_other_folder_)
+ BuildOtherFolderMenu(menu, &next_menu_id_);
+ node_to_menu_map_[parent] = menu;
+ return menu;
+}
+
+void BookmarkMenuController::BuildOtherFolderMenu(
+ MenuItemView* menu, int* next_menu_id) {
const BookmarkNode* other_folder = profile_->GetBookmarkModel()->other_node();
int id = *next_menu_id;
(*next_menu_id)++;
SkBitmap* folder_icon = ResourceBundle::GetSharedInstance().
GetBitmapNamed(IDR_BOOKMARK_BAR_FOLDER);
- views::MenuItemView* submenu = menu_->AppendSubMenuWithIcon(
+ MenuItemView* submenu = menu->AppendSubMenuWithIcon(
id, l10n_util::GetString(IDS_BOOMARK_BAR_OTHER_BOOKMARKED), *folder_icon);
BuildMenu(other_folder, 0, submenu, next_menu_id);
menu_id_to_node_map_[id] = other_folder;
@@ -232,7 +298,7 @@ void BookmarkMenuController::BuildOtherFolderMenu(int* next_menu_id) {
void BookmarkMenuController::BuildMenu(const BookmarkNode* parent,
int start_child_index,
- views::MenuItemView* menu,
+ MenuItemView* menu,
int* next_menu_id) {
DCHECK(!parent->GetChildCount() ||
start_child_index < parent->GetChildCount());
@@ -252,7 +318,7 @@ void BookmarkMenuController::BuildMenu(const BookmarkNode* parent,
} else if (node->is_folder()) {
SkBitmap* folder_icon = ResourceBundle::GetSharedInstance().
GetBitmapNamed(IDR_BOOKMARK_BAR_FOLDER);
- views::MenuItemView* submenu =
+ MenuItemView* submenu =
menu->AppendSubMenuWithIcon(id, node->GetTitle(), *folder_icon);
BuildMenu(node, 0, submenu, next_menu_id);
} else {
@@ -266,4 +332,5 @@ BookmarkMenuController::~BookmarkMenuController() {
profile_->GetBookmarkModel()->RemoveObserver(this);
if (observer_)
observer_->BookmarkMenuDeleted(this);
+ STLDeleteValues(&node_to_menu_map_);
}
diff --git a/chrome/browser/views/bookmark_menu_controller_views.h b/chrome/browser/views/bookmark_menu_controller_views.h
index fa6462f..f19c3cc 100644
--- a/chrome/browser/views/bookmark_menu_controller_views.h
+++ b/chrome/browser/views/bookmark_menu_controller_views.h
@@ -16,8 +16,13 @@
namespace gfx {
class Rect;
-}
+} // namespace gfx
+namespace views {
+class MenuButton;
+} // namespace views
+
+class BookmarkBarView;
class BookmarkContextMenu;
class BookmarkNode;
class Browser;
@@ -48,8 +53,10 @@ class BookmarkMenuController : public BaseBookmarkModelObserver,
int start_child_index,
bool show_other_folder);
+ void RunMenuAt(BookmarkBarView* bookmark_bar, bool for_drop);
+
// Shows the menu.
- void RunMenuAt(const gfx::Rect& bounds,
+ void RunMenuAt(views::MenuButton* button,
views::MenuItemView::AnchorPosition position,
bool for_drop);
@@ -60,7 +67,7 @@ class BookmarkMenuController : public BaseBookmarkModelObserver,
const BookmarkNode* node() const { return node_; }
// Returns the menu.
- views::MenuItemView* menu() const { return menu_.get(); }
+ views::MenuItemView* menu() const { return menu_; }
// Returns the context menu, or NULL if the context menu isn't showing.
views::MenuItemView* context_menu() const {
@@ -93,7 +100,14 @@ class BookmarkMenuController : public BaseBookmarkModelObserver,
virtual bool CanDrag(views::MenuItemView* menu);
virtual void WriteDragData(views::MenuItemView* sender, OSExchangeData* data);
virtual int GetDragOperations(views::MenuItemView* sender);
+ virtual views::MenuItemView* GetSiblingMenu(
+ views::MenuItemView* menu,
+ const gfx::Point& screen_point,
+ views::MenuItemView::AnchorPosition* anchor,
+ bool* has_mnemonics,
+ views::MenuButton** button);
+ // BookmarkModelObserver methods.
virtual void BookmarkModelChanged();
virtual void BookmarkNodeFavIconLoaded(BookmarkModel* model,
const BookmarkNode* node);
@@ -102,9 +116,14 @@ class BookmarkMenuController : public BaseBookmarkModelObserver,
// BookmarkMenuController deletes itself as necessary.
~BookmarkMenuController();
+ // Creates a menu and adds it to node_to_menu_id_map_. This uses
+ // BuildMenu to recursively populate the menu.
+ views::MenuItemView* CreateMenu(const BookmarkNode* parent,
+ int start_child_index);
+
// Builds the menu for the other bookmarks folder. This is added as the last
// item to menu_.
- void BuildOtherFolderMenu(int* next_menu_id);
+ void BuildOtherFolderMenu(views::MenuItemView* menu, int* next_menu_id);
// Creates an entry in menu for each child node of |parent| starting at
// |start_child_index|.
@@ -132,8 +151,8 @@ class BookmarkMenuController : public BaseBookmarkModelObserver,
// URL.
std::map<const BookmarkNode*, int> node_to_menu_id_map_;
- // The menu.
- scoped_ptr<views::MenuItemView> menu_;
+ // Current menu.
+ views::MenuItemView* menu_;
// Data for the drop.
BookmarkDragData drop_data_;
@@ -150,6 +169,16 @@ class BookmarkMenuController : public BaseBookmarkModelObserver,
// Should the other folder be shown?
bool show_other_folder_;
+ // The bookmark bar. This is only non-null if we're showing a menu item
+ // for a folder on the bookmark bar and not for drop.
+ BookmarkBarView* bookmark_bar_;
+
+ typedef std::map<const BookmarkNode*, views::MenuItemView*> NodeToMenuMap;
+ NodeToMenuMap node_to_menu_map_;
+
+ // ID of the next menu item.
+ int next_menu_id_;
+
DISALLOW_COPY_AND_ASSIGN(BookmarkMenuController);
};
diff --git a/views/controls/button/menu_button.cc b/views/controls/button/menu_button.cc
index 5dc59cb..e457304 100644
--- a/views/controls/button/menu_button.cc
+++ b/views/controls/button/menu_button.cc
@@ -47,7 +47,6 @@ MenuButton::MenuButton(ButtonListener* listener,
bool show_menu_marker)
: TextButton(listener, text),
menu_visible_(false),
- menu_closed_time_(),
menu_delegate_(menu_delegate),
show_menu_marker_(show_menu_marker) {
if (kMenuMarker == NULL) {
diff --git a/views/controls/menu/menu_controller.cc b/views/controls/menu/menu_controller.cc
index 6175e62..4388d91 100644
--- a/views/controls/menu/menu_controller.cc
+++ b/views/controls/menu/menu_controller.cc
@@ -9,6 +9,7 @@
#include "app/os_exchange_data.h"
#include "base/keyboard_codes.h"
#include "base/time.h"
+#include "views/controls/button/menu_button.h"
#include "views/controls/menu/menu_scroll_view_container.h"
#include "views/controls/menu/submenu_view.h"
#include "views/drag_utils.h"
@@ -143,6 +144,7 @@ static int nested_depth = 0;
#endif
MenuItemView* MenuController::Run(gfx::NativeWindow parent,
+ MenuButton* button,
MenuItemView* root,
const gfx::Rect& bounds,
MenuItemView::AnchorPosition position,
@@ -168,19 +170,9 @@ MenuItemView* MenuController::Run(gfx::NativeWindow parent,
// Reset current state.
pending_state_ = State();
state_ = State();
- pending_state_.initial_bounds = bounds;
- if (bounds.height() > 1) {
- // Inset the bounds slightly, otherwise drag coordinates don't line up
- // nicely and menus close prematurely.
- pending_state_.initial_bounds.Inset(0, 1);
- }
- pending_state_.anchor = position;
- owner_ = parent;
+ UpdateInitialLocation(bounds, position);
- // Calculate the bounds of the monitor we'll show menus on. Do this once to
- // avoid repeated system queries for the info.
- pending_state_.monitor_bounds = Screen::GetMonitorAreaNearestPoint(
- bounds.origin());
+ owner_ = parent;
// Set the selection, which opens the initial menu.
SetSelection(root, true, true);
@@ -190,6 +182,8 @@ MenuItemView* MenuController::Run(gfx::NativeWindow parent,
// notification when the drag has finished.
StartCancelAllTimer();
return NULL;
+ } else if (button) {
+ menu_button_ = button;
}
#ifdef DEBUG_MENU
@@ -245,6 +239,11 @@ MenuItemView* MenuController::Run(gfx::NativeWindow parent,
exit_all_ = true;
}
+ if (menu_button_) {
+ menu_button_->SetState(CustomButton::BS_NORMAL);
+ menu_button_->SchedulePaint();
+ }
+
return result;
}
@@ -316,8 +315,7 @@ void MenuController::OnMousePressed(SubmenuView* source,
if (!blocking_run_)
return;
- MenuPart part =
- GetMenuPartByScreenCoordinate(source, event.x(), event.y());
+ MenuPart part = GetMenuPartByScreenCoordinate(source, event.x(), event.y());
if (part.is_scroll())
return; // Ignore presses on scroll buttons.
@@ -362,8 +360,7 @@ void MenuController::OnMouseDragged(SubmenuView* source,
#ifdef DEBUG_MENU
DLOG(INFO) << "OnMouseDragged source=" << source;
#endif
- MenuPart part =
- GetMenuPartByScreenCoordinate(source, event.x(), event.y());
+ MenuPart part = GetMenuPartByScreenCoordinate(source, event.x(), event.y());
UpdateScrolling(part);
if (!blocking_run_)
@@ -409,6 +406,8 @@ void MenuController::OnMouseDragged(SubmenuView* source,
if (!part.menu)
part.menu = source->GetMenuItem();
SetSelection(part.menu ? part.menu : state_.item, true, false);
+ } else if (part.type == MenuPart::NONE) {
+ ShowSiblingMenu(source, event);
}
}
@@ -423,8 +422,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 = GetMenuPartByScreenCoordinate(source, event.x(), event.y());
if (event.IsRightMouseButton() && (part.type == MenuPart::MENU_ITEM &&
part.menu)) {
// Set the selection immediately, making sure the submenu is only open
@@ -460,14 +458,16 @@ void MenuController::OnMouseMoved(SubmenuView* source,
if (showing_submenu_)
return;
- MenuPart part =
- GetMenuPartByScreenCoordinate(source, event.x(), event.y());
+ MenuPart part = GetMenuPartByScreenCoordinate(source, event.x(), event.y());
UpdateScrolling(part);
if (!blocking_run_)
return;
+ if (part.type == MenuPart::NONE && ShowSiblingMenu(source, event))
+ return;
+
if (part.type == MenuPart::MENU_ITEM && part.menu) {
SetSelection(part.menu, true, false);
} else if (!part.is_scroll() && pending_state_.item &&
@@ -803,7 +803,8 @@ MenuController::MenuController(bool blocking)
owner_(NULL),
possible_drag_(false),
valid_drop_coordinates_(false),
- showing_submenu_(false) {
+ showing_submenu_(false),
+ menu_button_(NULL) {
#ifdef DEBUG_MENU
instance_count++;
DLOG(INFO) << "created MC, count=" << instance_count;
@@ -820,6 +821,23 @@ MenuController::~MenuController() {
#endif
}
+void MenuController::UpdateInitialLocation(
+ const gfx::Rect& bounds,
+ MenuItemView::AnchorPosition position) {
+ pending_state_.initial_bounds = bounds;
+ if (bounds.height() > 1) {
+ // Inset the bounds slightly, otherwise drag coordinates don't line up
+ // nicely and menus close prematurely.
+ pending_state_.initial_bounds.Inset(0, 1);
+ }
+ pending_state_.anchor = position;
+
+ // Calculate the bounds of the monitor we'll show menus on. Do this once to
+ // avoid repeated system queries for the info.
+ pending_state_.monitor_bounds = Screen::GetMonitorAreaNearestPoint(
+ bounds.origin());
+}
+
void MenuController::Accept(MenuItemView* item, int mouse_event_flags) {
DCHECK(IsBlockingRun());
result_ = item;
@@ -827,6 +845,63 @@ void MenuController::Accept(MenuItemView* item, int mouse_event_flags) {
result_mouse_event_flags_ = mouse_event_flags;
}
+bool MenuController::ShowSiblingMenu(SubmenuView* source, const MouseEvent& e) {
+ if (!menu_stack_.empty() || !menu_button_)
+ return false;
+
+ View* source_view = source->GetScrollViewContainer();
+ if (e.x() >= 0 && e.x() < source_view->width() && e.y() >= 0 &&
+ e.y() < source_view->height()) {
+ // The mouse is over the menu, no need to continue.
+ return false;
+ }
+
+ gfx::NativeWindow window_under_mouse = Screen::GetWindowAtCursorScreenPoint();
+ if (window_under_mouse != owner_)
+ return false;
+
+ // The user moved the mouse outside the menu and over the owning window. See
+ // if there is a sibling menu we should show.
+ gfx::Point screen_point(e.location());
+ View::ConvertPointToScreen(source_view, &screen_point);
+ MenuItemView::AnchorPosition anchor;
+ bool has_mnemonics;
+ MenuButton* button = NULL;
+ MenuItemView* alt_menu = source->GetMenuItem()->GetDelegate()->
+ GetSiblingMenu(source->GetMenuItem()->GetRootMenuItem(),
+ screen_point, &anchor, &has_mnemonics, &button);
+ if (!alt_menu || alt_menu == state_.item)
+ return false;
+
+ if (!button) {
+ // If the delegate returns a menu, they must also return a button.
+ NOTREACHED();
+ return false;
+ }
+
+ // There is a sibling menu, update the button state, hide the current menu
+ // and show the new one.
+ menu_button_->SetState(CustomButton::BS_NORMAL);
+ menu_button_->SchedulePaint();
+ menu_button_ = button;
+ menu_button_->SetState(CustomButton::BS_PUSHED);
+ menu_button_->SchedulePaint();
+
+ // Need to reset capture when we show the menu again, otherwise we aren't
+ // going to get any events.
+ did_capture_ = false;
+ gfx::Point screen_menu_loc;
+ View::ConvertPointToScreen(button, &screen_menu_loc);
+ // Subtract 1 from the height to make the popup flush with the button border.
+ UpdateInitialLocation(gfx::Rect(screen_menu_loc.x(), screen_menu_loc.y(),
+ button->width(), button->height() - 1),
+ anchor);
+ alt_menu->PrepareForRun(has_mnemonics);
+ alt_menu->controller_ = this;
+ SetSelection(alt_menu, true, true);
+ return true;
+}
+
void MenuController::CloseAllNestedMenus() {
for (std::list<State>::iterator i = menu_stack_.begin();
i != menu_stack_.end(); ++i) {
diff --git a/views/controls/menu/menu_controller.h b/views/controls/menu/menu_controller.h
index bc57036..2ef1bb7 100644
--- a/views/controls/menu/menu_controller.h
+++ b/views/controls/menu/menu_controller.h
@@ -22,6 +22,7 @@ class OSExchangeData;
namespace views {
class DropTargetEvent;
+class MenuButton;
class MenuHostRootView;
class MouseEvent;
class SubmenuView;
@@ -44,6 +45,7 @@ class MenuController : public MessageLoopForUI::Dispatcher {
// block, the selected item is returned. If the menu does not block this
// returns NULL immediately.
MenuItemView* Run(gfx::NativeWindow parent,
+ MenuButton* button,
MenuItemView* root,
const gfx::Rect& bounds,
MenuItemView::AnchorPosition position,
@@ -182,10 +184,15 @@ class MenuController : public MessageLoopForUI::Dispatcher {
~MenuController();
+ void UpdateInitialLocation(const gfx::Rect& bounds,
+ MenuItemView::AnchorPosition position);
+
// Invoked when the user accepts the selected item. This is only used
// when blocking. This schedules the loop to quit.
void Accept(MenuItemView* item, int mouse_event_flags);
+ bool ShowSiblingMenu(SubmenuView* source, const MouseEvent& e);
+
// Closes all menus, including any menus of nested invocations of Run.
void CloseAllNestedMenus();
@@ -330,7 +337,7 @@ class MenuController : public MessageLoopForUI::Dispatcher {
MenuItemView* result_;
// The mouse event flags when the user clicked on a menu. Is 0 if the
- // user did not use the mousee to select the menu.
+ // user did not use the mouse to select the menu.
int result_mouse_event_flags_;
// If not empty, it means we're nested. When Run is invoked from within
@@ -376,6 +383,8 @@ class MenuController : public MessageLoopForUI::Dispatcher {
// underway.
scoped_ptr<MenuScrollTask> scroll_task_;
+ MenuButton* menu_button_;
+
DISALLOW_COPY_AND_ASSIGN(MenuController);
};
diff --git a/views/controls/menu/menu_delegate.h b/views/controls/menu/menu_delegate.h
index ec66a4f..2f7cd66 100644
--- a/views/controls/menu/menu_delegate.h
+++ b/views/controls/menu/menu_delegate.h
@@ -12,12 +12,13 @@
#include "app/os_exchange_data.h"
#include "base/logging.h"
#include "views/controls/menu/controller.h"
+#include "views/controls/menu/menu_item_view.h"
#include "views/event.h"
namespace views {
class DropTargetEvent;
-class MenuItemView;
+class MenuButton;
// MenuDelegate --------------------------------------------------------------
@@ -180,6 +181,19 @@ class MenuDelegate : Controller {
// Notification that the user has highlighted the specified item.
virtual void SelectionChanged(MenuItemView* menu) {
}
+
+ // If the user drags the mouse outside the bounds of the menu the delegate
+ // is queried for a sibling menu to show. If this returns non-null the
+ // current menu is hidden, and the menu returned from this method is shown.
+ //
+ // The delegate owns the returned menu, not the controller.
+ virtual MenuItemView* GetSiblingMenu(MenuItemView* menu,
+ const gfx::Point& screen_point,
+ MenuItemView::AnchorPosition* anchor,
+ bool* has_mnemonics,
+ MenuButton** button) {
+ return NULL;
+ }
};
} // namespace views
diff --git a/views/controls/menu/menu_host_gtk.cc b/views/controls/menu/menu_host_gtk.cc
index 11033c4..38945e5 100644
--- a/views/controls/menu/menu_host_gtk.cc
+++ b/views/controls/menu/menu_host_gtk.cc
@@ -19,14 +19,13 @@ MenuHost::MenuHost(SubmenuView* submenu)
closed_(false),
submenu_(submenu),
did_pointer_grab_(false) {
- GdkModifierType current_event_mod;
- if (gtk_get_current_event_state(&current_event_mod)) {
- set_mouse_down(
- (current_event_mod & GDK_BUTTON1_MASK) ||
- (current_event_mod & GDK_BUTTON2_MASK) ||
- (current_event_mod & GDK_BUTTON3_MASK) ||
- (current_event_mod & GDK_BUTTON4_MASK) ||
- (current_event_mod & GDK_BUTTON5_MASK));
+ GdkEvent* event = gtk_get_current_event();
+ if (event) {
+ if (event->type == GDK_BUTTON_PRESS || event->type == GDK_2BUTTON_PRESS ||
+ event->type == GDK_3BUTTON_PRESS) {
+ set_mouse_down(true);
+ }
+ gdk_event_free(event);
}
}
@@ -36,33 +35,9 @@ void MenuHost::Init(gfx::NativeWindow parent,
bool do_capture) {
WidgetGtk::Init(GTK_WIDGET(parent), bounds);
SetContentsView(contents_view);
- // TODO(sky): see if there is some way to show without changing focus.
Show();
- if (do_capture) {
- // Release the current grab.
- GtkWidget* current_grab_window = gtk_grab_get_current();
- if (current_grab_window)
- gtk_grab_remove(current_grab_window);
-
- // Make sure all app mouse events are targetted at us only.
- DoGrab();
-
- // And do a grab.
- // NOTE: we do this to ensure we get mouse events from other apps, a grab
- // done with gtk_grab_add doesn't get events from other apps.
- GdkGrabStatus grab_status =
- gdk_pointer_grab(window_contents()->window, FALSE,
- static_cast<GdkEventMask>(
- GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK |
- GDK_POINTER_MOTION_MASK),
- NULL, NULL, GDK_CURRENT_TIME);
- did_pointer_grab_ = (grab_status == GDK_GRAB_SUCCESS);
- DCHECK(did_pointer_grab_);
- // need keyboard grab.
-#ifdef DEBUG_MENU
- DLOG(INFO) << "Doing capture";
-#endif
- }
+ if (do_capture)
+ DoCapture();
}
gfx::NativeWindow MenuHost::GetNativeWindow() {
@@ -95,6 +70,32 @@ void MenuHost::HideWindow() {
WidgetGtk::Hide();
}
+void MenuHost::DoCapture() {
+ // Release the current grab.
+ GtkWidget* current_grab_window = gtk_grab_get_current();
+ if (current_grab_window)
+ gtk_grab_remove(current_grab_window);
+
+ // Make sure all app mouse events are targetted at us only.
+ DoGrab();
+
+ // And do a grab.
+ // NOTE: we do this to ensure we get mouse events from other apps, a grab
+ // done with gtk_grab_add doesn't get events from other apps.
+ GdkGrabStatus grab_status =
+ gdk_pointer_grab(window_contents()->window, FALSE,
+ static_cast<GdkEventMask>(
+ GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK |
+ GDK_POINTER_MOTION_MASK),
+ NULL, NULL, GDK_CURRENT_TIME);
+ did_pointer_grab_ = (grab_status == GDK_GRAB_SUCCESS);
+ DCHECK(did_pointer_grab_);
+ // need keyboard grab.
+#ifdef DEBUG_MENU
+ DLOG(INFO) << "Doing capture";
+#endif
+}
+
void MenuHost::ReleaseCapture() {
ReleaseGrab();
}
diff --git a/views/controls/menu/menu_host_gtk.h b/views/controls/menu/menu_host_gtk.h
index 8e69ce8..4ae1b77 100644
--- a/views/controls/menu/menu_host_gtk.h
+++ b/views/controls/menu/menu_host_gtk.h
@@ -27,6 +27,7 @@ class MenuHost : public WidgetGtk {
void Show();
virtual void Hide();
virtual void HideWindow();
+ void DoCapture();
void ReleaseCapture();
protected:
diff --git a/views/controls/menu/menu_host_win.cc b/views/controls/menu/menu_host_win.cc
index d6fd655..f2c2c2c 100644
--- a/views/controls/menu/menu_host_win.cc
+++ b/views/controls/menu/menu_host_win.cc
@@ -37,14 +37,8 @@ void MenuHost::Init(HWND parent,
WidgetWin::Init(parent, bounds);
SetContentsView(contents_view);
Show();
- owns_capture_ = do_capture;
- if (do_capture) {
- SetCapture();
- has_capture_ = true;
-#ifdef DEBUG_MENU
- DLOG(INFO) << "Doing capture";
-#endif
- }
+ if (do_capture)
+ DoCapture();
}
void MenuHost::Show() {
@@ -82,6 +76,15 @@ void MenuHost::OnCaptureChanged(HWND hwnd) {
#endif
}
+void MenuHost::DoCapture() {
+ owns_capture_ = true;
+ SetCapture();
+ has_capture_ = true;
+#ifdef DEBUG_MENU
+ DLOG(INFO) << "Doing capture";
+#endif
+}
+
void MenuHost::ReleaseCapture() {
if (owns_capture_) {
#ifdef DEBUG_MENU
diff --git a/views/controls/menu/menu_host_win.h b/views/controls/menu/menu_host_win.h
index 6e645d2..ec5d060 100644
--- a/views/controls/menu/menu_host_win.h
+++ b/views/controls/menu/menu_host_win.h
@@ -28,6 +28,7 @@ class MenuHost : public WidgetWin {
virtual void Hide();
virtual void HideWindow();
virtual void OnCaptureChanged(HWND hwnd);
+ void DoCapture();
void ReleaseCapture();
protected:
diff --git a/views/controls/menu/menu_item_view.cc b/views/controls/menu/menu_item_view.cc
index 4d5b3ae..2734788 100644
--- a/views/controls/menu/menu_item_view.cc
+++ b/views/controls/menu/menu_item_view.cc
@@ -66,23 +66,15 @@ MenuItemView::MenuItemView(MenuDelegate* delegate) {
}
MenuItemView::~MenuItemView() {
- if (controller_) {
- // We're currently showing.
-
- // We can't delete ourselves while we're blocking.
- DCHECK(!controller_->IsBlockingRun());
-
- // Invoking Cancel is going to call us back and notify the delegate.
- // Notifying the delegate from the destructor can be problematic. To avoid
- // this the delegate is set to NULL.
- delegate_ = NULL;
-
- controller_->Cancel(true);
- }
+ // TODO(sky): ownership is bit wrong now. In particular if a nested message
+ // loop is running deletion can't be done, otherwise the stack gets
+ // thoroughly screwed. The destructor should be made private, and
+ // MenuController should be the only place handling deletion of the menu.
delete submenu_;
}
void MenuItemView::RunMenuAt(gfx::NativeWindow parent,
+ MenuButton* button,
const gfx::Rect& bounds,
AnchorPosition anchor,
bool has_mnemonics) {
@@ -115,7 +107,7 @@ void MenuItemView::RunMenuAt(gfx::NativeWindow parent,
// Run the loop.
MenuItemView* result =
- controller->Run(parent, this, bounds, anchor, &mouse_event_flags);
+ controller->Run(parent, button, this, bounds, anchor, &mouse_event_flags);
RemoveEmptyMenus();
@@ -151,7 +143,7 @@ void MenuItemView::RunMenuForDropAt(gfx::NativeWindow parent,
// Set the instance, that way it can be canceled by another menu.
MenuController::SetActiveInstance(controller_);
- controller_->Run(parent, this, bounds, anchor, NULL);
+ controller_->Run(parent, NULL, this, bounds, anchor, NULL);
}
void MenuItemView::Cancel() {
@@ -337,9 +329,6 @@ void MenuItemView::PrepareForRun(bool has_mnemonics) {
// Currently we only support showing the root.
DCHECK(!parent_menu_item_);
- // Don't invoke run from within run on the same menu.
- DCHECK(!controller_);
-
// Force us to have a submenu.
CreateSubmenu();
diff --git a/views/controls/menu/menu_item_view.h b/views/controls/menu/menu_item_view.h
index ecb3b78..a85e265 100644
--- a/views/controls/menu/menu_item_view.h
+++ b/views/controls/menu/menu_item_view.h
@@ -10,6 +10,7 @@
namespace views {
+class MenuButton;
class MenuController;
class MenuDelegate;
class SubmenuView;
@@ -82,6 +83,7 @@ class MenuItemView : public View {
// whether the items have mnemonics. Mnemonics are identified by way of the
// character following the '&'.
void RunMenuAt(gfx::NativeWindow parent,
+ MenuButton* button,
const gfx::Rect& bounds,
AnchorPosition anchor,
bool has_mnemonics);
diff --git a/views/controls/menu/submenu_view.cc b/views/controls/menu/submenu_view.cc
index d08de6f..3b315ef 100644
--- a/views/controls/menu/submenu_view.cc
+++ b/views/controls/menu/submenu_view.cc
@@ -221,6 +221,8 @@ void SubmenuView::ShowAt(gfx::NativeWindow parent,
bool do_capture) {
if (host_) {
host_->Show();
+ if (do_capture)
+ host_->DoCapture();
return;
}
diff --git a/views/screen.h b/views/screen.h
index f7c023c..f95b368 100644
--- a/views/screen.h
+++ b/views/screen.h
@@ -27,6 +27,9 @@ class Screen {
// Returns the monitor area (not the work area, but the complete bounds) of
// the monitor nearest the specified point.
static gfx::Rect GetMonitorAreaNearestPoint(const gfx::Point& point);
+
+ // Returns the window under the cursor.
+ static gfx::NativeWindow GetWindowAtCursorScreenPoint();
};
} // namespace views
diff --git a/views/screen_gtk.cc b/views/screen_gtk.cc
index 9302853..a0daa19 100644
--- a/views/screen_gtk.cc
+++ b/views/screen_gtk.cc
@@ -58,5 +58,19 @@ gfx::Rect Screen::GetMonitorAreaNearestPoint(const gfx::Point& point) {
return gfx::Rect(bounds);
}
+gfx::NativeWindow Screen::GetWindowAtCursorScreenPoint() {
+ GdkWindow* window = gdk_window_at_pointer(NULL, NULL);
+ if (!window)
+ return NULL;
+
+ gpointer data = NULL;
+ gdk_window_get_user_data(window, &data);
+ GtkWidget* widget = reinterpret_cast<GtkWidget*>(data);
+ if (!widget)
+ return NULL;
+ widget = gtk_widget_get_toplevel(widget);
+ return GTK_IS_WINDOW(widget) ? GTK_WINDOW(widget) : NULL;
+}
+
} // namespace
diff --git a/views/screen_win.cc b/views/screen_win.cc
index 82e95e6..4ddb7c1 100644
--- a/views/screen_win.cc
+++ b/views/screen_win.cc
@@ -46,5 +46,10 @@ gfx::Rect Screen::GetMonitorAreaNearestPoint(const gfx::Point& point) {
return gfx::Rect(mi.rcMonitor);
}
+gfx::NativeWindow Screen::GetWindowAtCursorScreenPoint() {
+ POINT location;
+ return GetCursorPos(&location) ? WindowFromPoint(location) : NULL;
+}
+
} // namespace