summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--chrome/browser/browser.scons1
-rw-r--r--chrome/browser/gtk/menu_gtk.cc51
-rw-r--r--chrome/browser/gtk/menu_gtk.h9
-rw-r--r--chrome/browser/gtk/standard_menus.h4
-rw-r--r--chrome/browser/tab_contents/render_view_context_menu_gtk.cc106
-rw-r--r--chrome/browser/tab_contents/render_view_context_menu_gtk.h57
-rw-r--r--chrome/browser/tab_contents/web_contents_view_gtk.cc4
-rw-r--r--chrome/browser/tab_contents/web_contents_view_gtk.h7
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);
};