diff options
-rw-r--r-- | chrome/browser/browser.scons | 1 | ||||
-rw-r--r-- | chrome/browser/gtk/menu_gtk.cc | 51 | ||||
-rw-r--r-- | chrome/browser/gtk/menu_gtk.h | 9 | ||||
-rw-r--r-- | chrome/browser/gtk/standard_menus.h | 4 | ||||
-rw-r--r-- | chrome/browser/tab_contents/render_view_context_menu_gtk.cc | 106 | ||||
-rw-r--r-- | chrome/browser/tab_contents/render_view_context_menu_gtk.h | 57 | ||||
-rw-r--r-- | chrome/browser/tab_contents/web_contents_view_gtk.cc | 4 | ||||
-rw-r--r-- | chrome/browser/tab_contents/web_contents_view_gtk.h | 7 |
8 files changed, 220 insertions, 19 deletions
diff --git a/chrome/browser/browser.scons b/chrome/browser/browser.scons index ef38df4..0e6e74d 100644 --- a/chrome/browser/browser.scons +++ b/chrome/browser/browser.scons @@ -752,6 +752,7 @@ if env.Bit('linux'): 'process_singleton_linux.cc', 'renderer_host/render_widget_host_view_gtk.cc', 'tab_contents/web_contents_view_gtk.cc', + 'tab_contents/render_view_context_menu_gtk.cc', ]) if env.Bit('mac'): diff --git a/chrome/browser/gtk/menu_gtk.cc b/chrome/browser/gtk/menu_gtk.cc index d9a3860..8937a3a 100644 --- a/chrome/browser/gtk/menu_gtk.cc +++ b/chrome/browser/gtk/menu_gtk.cc @@ -12,16 +12,16 @@ namespace { // GTK uses _ for accelerators. Windows uses & with && as an escape for &. -std::wstring ConvertAcceleratorsFromWindowsStyle(const std::wstring& label) { - std::wstring ret; +std::string ConvertAcceleratorsFromWindowsStyle(const std::string& label) { + std::string ret; ret.reserve(label.length()); for (size_t i = 0; i < label.length(); ++i) { - if (L'&' == label[i]) { - if (i + 1 < label.length() && L'&' == label[i + 1]) { + if ('&' == label[i]) { + if (i + 1 < label.length() && '&' == label[i + 1]) { ret.push_back(label[i]); ++i; } else { - ret.push_back(L'_'); + ret.push_back('_'); } } else { ret.push_back(label[i]); @@ -110,35 +110,55 @@ void MenuGtk::Popup(GtkWidget* widget, gint button_type, guint32 timestamp) { button_type, timestamp); } +void MenuGtk::PopupAsContext() { + gtk_container_foreach(GTK_CONTAINER(menu_), SetMenuItemInfo, this); + + // TODO(estade): |button| value of 0 (6th argument) is not strictly true, + // but does it matter? + gtk_menu_popup(GTK_MENU(menu_), NULL, NULL, NULL, NULL, 0, + gtk_get_current_event_time()); +} + void MenuGtk::BuildMenuIn(GtkWidget* menu, const MenuCreateMaterial* menu_data) { - for (; menu_data->type != MENU_END; menu_data++) { + // We keep track of the last menu item in order to group radio items. + GtkWidget* last_menu_item = NULL; + for (; menu_data->type != MENU_END; ++menu_data) { GtkWidget* menu_item = NULL; - std::wstring label; + std::string label; if (menu_data->label_argument) { - label = l10n_util::GetStringF( + label = WideToUTF8(l10n_util::GetStringF( menu_data->label_id, - l10n_util::GetString(menu_data->label_argument)); + l10n_util::GetString(menu_data->label_argument))); } else if (menu_data->label_id) { - label = l10n_util::GetString(menu_data->label_id); - } else { - DCHECK(menu_data->type == MENU_SEPARATOR) << "Menu definition broken"; + label = WideToUTF8(l10n_util::GetString(menu_data->label_id)); + } else if (menu_data->type != MENU_SEPARATOR) { + label = delegate_->GetLabel(menu_data->id); + DCHECK(!label.empty()); } label = ConvertAcceleratorsFromWindowsStyle(label); switch (menu_data->type) { + case MENU_RADIO: + if (GTK_IS_RADIO_MENU_ITEM(last_menu_item)) { + menu_item = gtk_radio_menu_item_new_with_mnemonic_from_widget( + GTK_RADIO_MENU_ITEM(last_menu_item), label.c_str()); + } else { + menu_item = gtk_radio_menu_item_new_with_mnemonic( + NULL, label.c_str()); + } + break; case MENU_CHECKBOX: - menu_item = gtk_check_menu_item_new_with_mnemonic( - WideToUTF8(label).c_str()); + menu_item = gtk_check_menu_item_new_with_mnemonic(label.c_str()); break; case MENU_SEPARATOR: menu_item = gtk_separator_menu_item_new(); break; case MENU_NORMAL: default: - menu_item = gtk_menu_item_new_with_mnemonic(WideToUTF8(label).c_str()); + menu_item = gtk_menu_item_new_with_mnemonic(label.c_str()); break; } @@ -168,6 +188,7 @@ void MenuGtk::BuildMenuIn(GtkWidget* menu, gtk_widget_show(menu_item); gtk_menu_append(menu, menu_item); + last_menu_item = menu_item; } } diff --git a/chrome/browser/gtk/menu_gtk.h b/chrome/browser/gtk/menu_gtk.h index 6dd1d05..d55a8be 100644 --- a/chrome/browser/gtk/menu_gtk.h +++ b/chrome/browser/gtk/menu_gtk.h @@ -45,12 +45,17 @@ class MenuGtk { explicit MenuGtk(MenuGtk::Delegate* delegate); ~MenuGtk(); - // Displays the menu. |timestamp| is the time of activation. + // Displays the menu. |timestamp| is the time of activation. The popup is + // statically positioned at |widget|. void Popup(GtkWidget* widget, gint button_type, guint32 timestamp); - // Displays the menu using the button type and timestamp of |event|. + // Displays the menu using the button type and timestamp of |event|. The popup + // is statically positioned at |widget|. void Popup(GtkWidget* widget, GdkEvent* event); + // Displays the menu as a context menu, i.e. at the current cursor location. + void PopupAsContext(); + private: // A recursive function that transforms a MenuCreateMaterial tree into a set // of GtkMenuItems. diff --git a/chrome/browser/gtk/standard_menus.h b/chrome/browser/gtk/standard_menus.h index 90d289d..e022fa0 100644 --- a/chrome/browser/gtk/standard_menus.h +++ b/chrome/browser/gtk/standard_menus.h @@ -12,6 +12,7 @@ enum MenuItemType { MENU_NORMAL = 0, MENU_CHECKBOX, MENU_SEPARATOR, + MENU_RADIO, // Speical value to stop processing this MenuCreateMaterial. MENU_END @@ -28,7 +29,8 @@ struct MenuCreateMaterial { unsigned int label_id; // An argument to GetStringF(menu_label_id, ...). When 0, the value of - // menu_label_id is just passed to GetString(). + // label_id is just passed to GetString(). If both are 0, the menu delegate + // is responsible for implementing GetLabel(). unsigned int label_argument; // If non-NULL, a pointer to the struct we're supposed to use diff --git a/chrome/browser/tab_contents/render_view_context_menu_gtk.cc b/chrome/browser/tab_contents/render_view_context_menu_gtk.cc new file mode 100644 index 0000000..dad440a --- /dev/null +++ b/chrome/browser/tab_contents/render_view_context_menu_gtk.cc @@ -0,0 +1,106 @@ +// Copyright (c) 2009 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "chrome/browser/tab_contents/render_view_context_menu_gtk.h" + +#include "base/string_util.h" +#include "webkit/glue/context_menu.h" + +RenderViewContextMenuGtk::RenderViewContextMenuGtk( + WebContents* web_contents, + const ContextMenuParams& params) + : RenderViewContextMenu(web_contents, params), + making_submenu_(false) { + InitMenu(params.node); + DoneMakingMenu(&menu_); + gtk_menu_.reset(new MenuGtk(this, menu_.data(), NULL)); +} + +RenderViewContextMenuGtk::~RenderViewContextMenuGtk() { +} + +void RenderViewContextMenuGtk::Popup() { + gtk_menu_->PopupAsContext(); +} + +bool RenderViewContextMenuGtk::IsCommandEnabled(int id) const { + return IsItemCommandEnabled(id); +} + +bool RenderViewContextMenuGtk::IsItemChecked(int id) const { + return ItemIsChecked(id); +} + +void RenderViewContextMenuGtk::ExecuteCommand(int id) { + ExecuteItemCommand(id); +} + +std::string RenderViewContextMenuGtk::GetLabel(int id) const { + std::map<int, std::string>::const_iterator label = label_map_.find(id); + + if (label != label_map_.end()) + return label->second; + + return std::string(); +} + +void RenderViewContextMenuGtk::AppendMenuItem(int id) { + AppendItem(id, std::wstring(), MENU_NORMAL); +} + +void RenderViewContextMenuGtk::AppendMenuItem(int id, + const std::wstring& label) { + AppendItem(id, label, MENU_NORMAL); +} + +void RenderViewContextMenuGtk::AppendRadioMenuItem(int id, + const std::wstring& label) { + AppendItem(id, label, MENU_RADIO); +} + +void RenderViewContextMenuGtk::AppendCheckboxMenuItem(int id, + const std::wstring& label) { + AppendItem(id, label, MENU_CHECKBOX); +} + +void RenderViewContextMenuGtk::AppendSeparator() { + AppendItem(0, std::wstring(), MENU_SEPARATOR); +} + +void RenderViewContextMenuGtk::StartSubMenu(int id, const std::wstring& label) { + AppendItem(id, label, MENU_NORMAL); + making_submenu_ = true; +} + +void RenderViewContextMenuGtk::FinishSubMenu() { + DoneMakingMenu(&submenu_); + menu_[menu_.size() - 1].submenu = submenu_.data(); + making_submenu_ = false; +} + +void RenderViewContextMenuGtk::AppendItem( + int id, const std::wstring& label, MenuItemType type) { + MenuCreateMaterial menu_create_material = { + type, id, 0, 0, NULL + }; + + if (label.empty()) + menu_create_material.label_id = id; + else + label_map_[id] = WideToUTF8(label); + + std::vector<MenuCreateMaterial>* menu = + making_submenu_ ? &submenu_ : &menu_; + menu->push_back(menu_create_material); +} + +// static +void RenderViewContextMenuGtk::DoneMakingMenu( + std::vector<MenuCreateMaterial>* menu) { + static MenuCreateMaterial end_menu_item = { + MENU_END, 0, 0, 0, NULL + }; + menu->push_back(end_menu_item); +} + diff --git a/chrome/browser/tab_contents/render_view_context_menu_gtk.h b/chrome/browser/tab_contents/render_view_context_menu_gtk.h new file mode 100644 index 0000000..0776010 --- /dev/null +++ b/chrome/browser/tab_contents/render_view_context_menu_gtk.h @@ -0,0 +1,57 @@ +// Copyright (c) 2009 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef CHROME_BROWSER_TAB_CONTENTS_RENDER_VIEW_CONTEXT_MENU_GTK_H_ +#define CHROME_BROWSER_TAB_CONTENTS_RENDER_VIEW_CONTEXT_MENU_GTK_H_ + +#include <map> +#include <string> +#include <vector> + +#include "base/scoped_ptr.h" +#include "chrome/browser/gtk/menu_gtk.h" +#include "chrome/browser/tab_contents/render_view_context_menu.h" + +class ContextMenuParams; + +// TODO(port): we need accelerator support for this class. +class RenderViewContextMenuGtk : public RenderViewContextMenu, + public MenuGtk::Delegate { + public: + RenderViewContextMenuGtk(WebContents* web_contents, + const ContextMenuParams& params); + + ~RenderViewContextMenuGtk(); + + // Show the menu at the current cursor location. + void Popup(); + + // Menu::Delegate implementation --------------------------------------------- + virtual bool IsCommandEnabled(int id) const; + virtual bool IsItemChecked(int id) const; + virtual void ExecuteCommand(int id); + virtual std::string GetLabel(int id) const; + + protected: + // RenderViewContextMenu implementation -------------------------------------- + virtual void AppendMenuItem(int id); + virtual void AppendMenuItem(int id, const std::wstring& label); + virtual void AppendRadioMenuItem(int id, const std::wstring& label); + virtual void AppendCheckboxMenuItem(int id, const std::wstring& label); + virtual void AppendSeparator(); + virtual void StartSubMenu(int id, const std::wstring& label); + virtual void FinishSubMenu(); + + private: + void AppendItem(int id, const std::wstring& label, MenuItemType type); + static void DoneMakingMenu(std::vector<MenuCreateMaterial>* menu); + + scoped_ptr<MenuGtk> gtk_menu_; + std::map<int, std::string> label_map_; + std::vector<MenuCreateMaterial> menu_; + std::vector<MenuCreateMaterial> submenu_; + bool making_submenu_; +}; + +#endif // CHROME_BROWSER_TAB_CONTENTS_RENDER_VIEW_CONTEXT_MENU_GTK_H_ diff --git a/chrome/browser/tab_contents/web_contents_view_gtk.cc b/chrome/browser/tab_contents/web_contents_view_gtk.cc index d90c9ae..7c86751 100644 --- a/chrome/browser/tab_contents/web_contents_view_gtk.cc +++ b/chrome/browser/tab_contents/web_contents_view_gtk.cc @@ -12,6 +12,7 @@ #include "base/gfx/rect.h" #include "chrome/browser/renderer_host/render_view_host.h" #include "chrome/browser/renderer_host/render_widget_host_view_gtk.h" +#include "chrome/browser/tab_contents/render_view_context_menu_gtk.h" #include "chrome/browser/tab_contents/tab_contents_delegate.h" #include "chrome/browser/tab_contents/web_contents.h" @@ -183,7 +184,8 @@ void WebContentsViewGtk::OnFindReply(int request_id, } void WebContentsViewGtk::ShowContextMenu(const ContextMenuParams& params) { - NOTIMPLEMENTED(); + context_menu_.reset(new RenderViewContextMenuGtk(web_contents_, params)); + context_menu_->Popup(); } void WebContentsViewGtk::StartDragging(const WebDropData& drop_data) { diff --git a/chrome/browser/tab_contents/web_contents_view_gtk.h b/chrome/browser/tab_contents/web_contents_view_gtk.h index 8975ce6..d920b89 100644 --- a/chrome/browser/tab_contents/web_contents_view_gtk.h +++ b/chrome/browser/tab_contents/web_contents_view_gtk.h @@ -5,8 +5,11 @@ #ifndef CHROME_BROWSER_TAB_CONTENTS_WEB_CONTENTS_VIEW_GTK_H_ #define CHROME_BROWSER_TAB_CONTENTS_WEB_CONTENTS_VIEW_GTK_H_ +#include "base/scoped_ptr.h" #include "chrome/browser/tab_contents/web_contents_view.h" +class RenderViewContextMenuGtk; + class WebContentsViewGtk : public WebContentsView { public: // The corresponding WebContents is passed in the constructor, and manages our @@ -65,6 +68,10 @@ class WebContentsViewGtk : public WebContentsView { GtkWidget* vbox_; + // The context menu is reset every time we show it, but we keep a pointer to + // between uses so that it won't go out of scope before we're done with it. + scoped_ptr<RenderViewContextMenuGtk> context_menu_; + DISALLOW_COPY_AND_ASSIGN(WebContentsViewGtk); }; |