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.
5 #include "chrome/browser/ui/gtk/tab_contents/render_view_context_menu_gtk.h"
9 #include "base/strings/string_util.h"
10 #include "base/strings/utf_string_conversions.h"
11 #include "chrome/app/chrome_command_ids.h"
12 #include "chrome/browser/ui/gtk/gtk_util.h"
13 #include "content/public/browser/render_view_host.h"
14 #include "content/public/browser/render_widget_host_view.h"
15 #include "content/public/browser/web_contents.h"
16 #include "content/public/common/context_menu_params.h"
17 #include "grit/generated_resources.h"
18 #include "ui/base/accelerators/menu_label_accelerator_util_linux.h"
19 #include "ui/base/l10n/l10n_util.h"
21 using content::WebContents
;
25 // A callback function for gtk_container_foreach(). This callback just checks
26 // the menu ID and set the given user data if it is same as the specified ID.
27 struct GtkWidgetAtParam
{
32 void GtkWidgetAt(GtkWidget
* widget
, gpointer user_data
) {
33 GtkWidgetAtParam
* param
= reinterpret_cast<GtkWidgetAtParam
*>(user_data
);
35 gpointer data
= g_object_get_data(G_OBJECT(widget
), "menu-id");
36 if (data
&& (GPOINTER_TO_INT(data
) - 1) == param
->index
&&
37 GTK_IS_MENU_ITEM(widget
)) {
38 param
->widget
= widget
;
42 // Retrieves a GtkWidget which has the specified command_id. This function
43 // traverses the given |model| in the depth-first order. When this function
44 // finds an item whose command_id is the same as the given |command_id|, it
45 // returns the GtkWidget associated with the item. This function emulates
46 // views::MenuItemViews::GetMenuItemByID() for GTK.
47 GtkWidget
* GetMenuItemByID(ui::MenuModel
* model
,
53 for (int i
= 0; i
< model
->GetItemCount(); ++i
) {
54 if (model
->GetCommandIdAt(i
) == command_id
) {
55 GtkWidgetAtParam param
;
58 gtk_container_foreach(GTK_CONTAINER(menu
), &GtkWidgetAt
, ¶m
);
62 ui::MenuModel
* submenu
= model
->GetSubmenuModelAt(i
);
64 GtkWidget
* subitem
= GetMenuItemByID(
66 gtk_menu_item_get_submenu(GTK_MENU_ITEM(menu
)),
77 RenderViewContextMenuGtk::RenderViewContextMenuGtk(
78 WebContents
* web_contents
,
79 const content::ContextMenuParams
& params
,
80 content::RenderWidgetHostView
* view
)
81 : RenderViewContextMenu(web_contents
, params
),
82 bidi_submenu_model_(this) {
83 GdkEventButton
* event
= view
->GetLastMouseDown();
84 triggering_event_time_
= event
? event
->time
: GDK_CURRENT_TIME
;
87 RenderViewContextMenuGtk::~RenderViewContextMenuGtk() {
90 void RenderViewContextMenuGtk::PlatformInit() {
91 menu_gtk_
.reset(new MenuGtk(this, &menu_model_
));
93 if (params_
.is_editable
) {
94 content::RenderWidgetHostView
* rwhv
=
95 source_web_contents_
->GetRenderWidgetHostView();
97 MenuGtk
* menu
= menu_gtk_
.get();
98 gboolean show_input_method_menu
= TRUE
;
101 gtk_widget_get_settings(GTK_WIDGET(rwhv
->GetNativeView())),
102 "gtk-show-input-method-menu", &show_input_method_menu
, NULL
);
103 if (!show_input_method_menu
)
106 std::string label
= ui::ConvertAcceleratorsFromWindowsStyle(
107 l10n_util::GetStringUTF8(IDS_CONTENT_CONTEXT_INPUT_METHODS_MENU
));
108 GtkWidget
* menuitem
= gtk_menu_item_new_with_mnemonic(label
.c_str());
109 GtkWidget
* submenu
= rwhv
->BuildInputMethodsGtkMenu();
110 gtk_menu_item_set_submenu(GTK_MENU_ITEM(menuitem
), submenu
);
111 int inspect_element_index
=
112 menu_model_
.GetIndexOfCommandId(IDC_CONTENT_CONTEXT_INSPECTELEMENT
);
113 if (inspect_element_index
!= -1) {
114 menu
->InsertSeparator(inspect_element_index
- 1);
115 menu
->InsertMenuItem(IDC_INPUT_METHODS_MENU
, menuitem
,
116 inspect_element_index
);
118 menu
->AppendSeparator();
119 menu
->AppendMenuItem(IDC_INPUT_METHODS_MENU
, menuitem
);
125 void RenderViewContextMenuGtk::PlatformCancel() {
129 bool RenderViewContextMenuGtk::GetAcceleratorForCommandId(
131 ui::Accelerator
* accelerator
) {
135 void RenderViewContextMenuGtk::Popup(const gfx::Point
& point
) {
136 menu_gtk_
->PopupAsContext(point
, triggering_event_time_
);
139 bool RenderViewContextMenuGtk::AlwaysShowIconForCmd(int command_id
) const {
140 return command_id
>= IDC_EXTENSIONS_CONTEXT_CUSTOM_FIRST
&&
141 command_id
<= IDC_EXTENSIONS_CONTEXT_CUSTOM_LAST
;
144 void RenderViewContextMenuGtk::ExecuteCommand(int command_id
, int event_flags
) {
145 switch (command_id
) {
146 case IDC_WRITING_DIRECTION_DEFAULT
:
147 // WebKit's current behavior is for this menu item to always be disabled.
151 case IDC_WRITING_DIRECTION_RTL
:
152 case IDC_WRITING_DIRECTION_LTR
: {
153 content::RenderViewHost
* view_host
= GetRenderViewHost();
154 blink::WebTextDirection dir
= blink::WebTextDirectionLeftToRight
;
155 if (command_id
== IDC_WRITING_DIRECTION_RTL
)
156 dir
= blink::WebTextDirectionRightToLeft
;
157 view_host
->UpdateTextDirection(dir
);
158 view_host
->NotifyTextDirection();
163 RenderViewContextMenu::ExecuteCommand(command_id
, event_flags
);
168 bool RenderViewContextMenuGtk::IsCommandIdChecked(int command_id
) const {
169 switch (command_id
) {
170 case IDC_WRITING_DIRECTION_DEFAULT
:
171 return params_
.writing_direction_default
&
172 blink::WebContextMenuData::CheckableMenuItemChecked
;
173 case IDC_WRITING_DIRECTION_RTL
:
174 return params_
.writing_direction_right_to_left
&
175 blink::WebContextMenuData::CheckableMenuItemChecked
;
176 case IDC_WRITING_DIRECTION_LTR
:
177 return params_
.writing_direction_left_to_right
&
178 blink::WebContextMenuData::CheckableMenuItemChecked
;
181 return RenderViewContextMenu::IsCommandIdChecked(command_id
);
185 bool RenderViewContextMenuGtk::IsCommandIdEnabled(int command_id
) const {
186 switch (command_id
) {
187 case IDC_WRITING_DIRECTION_MENU
:
189 case IDC_WRITING_DIRECTION_DEFAULT
: // Provided to match OS defaults.
190 return params_
.writing_direction_default
&
191 blink::WebContextMenuData::CheckableMenuItemEnabled
;
192 case IDC_WRITING_DIRECTION_RTL
:
193 return params_
.writing_direction_right_to_left
&
194 blink::WebContextMenuData::CheckableMenuItemEnabled
;
195 case IDC_WRITING_DIRECTION_LTR
:
196 return params_
.writing_direction_left_to_right
&
197 blink::WebContextMenuData::CheckableMenuItemEnabled
;
200 return RenderViewContextMenu::IsCommandIdEnabled(command_id
);
204 void RenderViewContextMenuGtk::AppendPlatformEditableItems() {
205 // OS X and Linux provide a contextual menu to set writing direction for BiDi
207 // This functionality is exposed as a keyboard shortcut on Windows.
211 void RenderViewContextMenuGtk::AppendBidiSubMenu() {
212 bidi_submenu_model_
.AddCheckItem(IDC_WRITING_DIRECTION_DEFAULT
,
213 l10n_util::GetStringUTF16(IDS_CONTENT_CONTEXT_WRITING_DIRECTION_DEFAULT
));
214 bidi_submenu_model_
.AddCheckItem(IDC_WRITING_DIRECTION_LTR
,
215 l10n_util::GetStringUTF16(IDS_CONTENT_CONTEXT_WRITING_DIRECTION_LTR
));
216 bidi_submenu_model_
.AddCheckItem(IDC_WRITING_DIRECTION_RTL
,
217 l10n_util::GetStringUTF16(IDS_CONTENT_CONTEXT_WRITING_DIRECTION_RTL
));
219 menu_model_
.AddSubMenu(
220 IDC_WRITING_DIRECTION_MENU
,
221 l10n_util::GetStringUTF16(IDS_CONTENT_CONTEXT_WRITING_DIRECTION_MENU
),
222 &bidi_submenu_model_
);
225 void RenderViewContextMenuGtk::UpdateMenuItem(int command_id
,
228 const base::string16
& title
) {
229 GtkWidget
* item
= GetMenuItemByID(&menu_model_
, menu_gtk_
->widget(),
231 if (!item
|| !GTK_IS_MENU_ITEM(item
))
234 // Enable (or disable) the menu item and updates its text.
235 gtk_widget_set_sensitive(item
, enabled
);
237 gtk_widget_hide(item
);
239 gtk_widget_show(item
);
240 gtk_menu_item_set_label(GTK_MENU_ITEM(item
),
241 base::UTF16ToUTF8(title
).c_str());