Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(31)

Side by Side Diff: chrome/browser/ui/gtk/menu_gtk.cc

Issue 6840068: GTK: Add Recently Closed tabs to the History menu in the global menu bar. (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src
Patch Set: Maybe abandoning this way Created 9 years, 8 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch | Annotate | Revision Log
OLDNEW
1 // Copyright (c) 2011 The Chromium Authors. All rights reserved. 1 // Copyright (c) 2011 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be 2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file. 3 // found in the LICENSE file.
4 4
5 #include "chrome/browser/ui/gtk/menu_gtk.h" 5 #include "chrome/browser/ui/gtk/menu_gtk.h"
6 6
7 #include <map> 7 #include <map>
8 8
9 #include "base/i18n/rtl.h" 9 #include "base/i18n/rtl.h"
10 #include "base/logging.h" 10 #include "base/logging.h"
11 #include "base/message_loop.h" 11 #include "base/message_loop.h"
12 #include "base/stl_util-inl.h" 12 #include "base/stl_util-inl.h"
13 #include "base/utf_string_conversions.h" 13 #include "base/utf_string_conversions.h"
14 #include "chrome/app/chrome_command_ids.h"
15 #include "chrome/browser/ui/gtk/gtk_custom_menu.h" 14 #include "chrome/browser/ui/gtk/gtk_custom_menu.h"
16 #include "chrome/browser/ui/gtk/gtk_custom_menu_item.h" 15 #include "chrome/browser/ui/gtk/gtk_custom_menu_item.h"
17 #include "chrome/browser/ui/gtk/gtk_util.h" 16 #include "chrome/browser/ui/gtk/gtk_util.h"
18 #include "third_party/skia/include/core/SkBitmap.h" 17 #include "third_party/skia/include/core/SkBitmap.h"
19 #include "ui/base/models/accelerator_gtk.h" 18 #include "ui/base/models/accelerator_gtk.h"
20 #include "ui/base/models/button_menu_item_model.h" 19 #include "ui/base/models/button_menu_item_model.h"
21 #include "ui/base/models/menu_model.h" 20 #include "ui/base/models/menu_model.h"
22 #include "ui/gfx/gtk_util.h" 21 #include "ui/gfx/gtk_util.h"
23 #include "webkit/glue/window_open_disposition.h" 22 #include "webkit/glue/window_open_disposition.h"
24 23
(...skipping 82 matching lines...) Expand 10 before | Expand all | Expand 10 after
107 int alternate_y = y - menu_req->height; 106 int alternate_y = y - menu_req->height;
108 if (widget) 107 if (widget)
109 alternate_y -= widget->allocation.height; 108 alternate_y -= widget->allocation.height;
110 if (menu_bottom >= screen_bottom && alternate_y >= screen_top) 109 if (menu_bottom >= screen_bottom && alternate_y >= screen_top)
111 return alternate_y; 110 return alternate_y;
112 return y; 111 return y;
113 } 112 }
114 113
115 } // namespace 114 } // namespace
116 115
117 GtkWidget* MenuGtk::Delegate::GetDefaultImageForCommandId(int command_id) {
118 const char* stock;
119 switch (command_id) {
120 case IDC_NEW_TAB:
121 case IDC_CONTENT_CONTEXT_OPENIMAGENEWTAB:
122 case IDC_CONTENT_CONTEXT_OPENLINKNEWTAB:
123 case IDC_CONTENT_CONTEXT_OPENAVNEWTAB:
124 stock = GTK_STOCK_NEW;
125 break;
126
127 case IDC_CLOSE_TAB:
128 stock = GTK_STOCK_CLOSE;
129 break;
130
131 case IDC_CONTENT_CONTEXT_SAVEIMAGEAS:
132 case IDC_CONTENT_CONTEXT_SAVEAVAS:
133 case IDC_CONTENT_CONTEXT_SAVELINKAS:
134 stock = GTK_STOCK_SAVE_AS;
135 break;
136
137 case IDC_SAVE_PAGE:
138 stock = GTK_STOCK_SAVE;
139 break;
140
141 case IDC_COPY:
142 case IDC_COPY_URL:
143 case IDC_CONTENT_CONTEXT_COPYIMAGELOCATION:
144 case IDC_CONTENT_CONTEXT_COPYLINKLOCATION:
145 case IDC_CONTENT_CONTEXT_COPYAVLOCATION:
146 case IDC_CONTENT_CONTEXT_COPYEMAILADDRESS:
147 case IDC_CONTENT_CONTEXT_COPY:
148 stock = GTK_STOCK_COPY;
149 break;
150
151 case IDC_CUT:
152 case IDC_CONTENT_CONTEXT_CUT:
153 stock = GTK_STOCK_CUT;
154 break;
155
156 case IDC_PASTE:
157 case IDC_CONTENT_CONTEXT_PASTE:
158 stock = GTK_STOCK_PASTE;
159 break;
160
161 case IDC_CONTENT_CONTEXT_DELETE:
162 case IDC_BOOKMARK_BAR_REMOVE:
163 stock = GTK_STOCK_DELETE;
164 break;
165
166 case IDC_CONTENT_CONTEXT_UNDO:
167 stock = GTK_STOCK_UNDO;
168 break;
169
170 case IDC_CONTENT_CONTEXT_REDO:
171 stock = GTK_STOCK_REDO;
172 break;
173
174 case IDC_SEARCH:
175 case IDC_FIND:
176 case IDC_CONTENT_CONTEXT_SEARCHWEBFOR:
177 stock = GTK_STOCK_FIND;
178 break;
179
180 case IDC_CONTENT_CONTEXT_SELECTALL:
181 stock = GTK_STOCK_SELECT_ALL;
182 break;
183
184 case IDC_CLEAR_BROWSING_DATA:
185 stock = GTK_STOCK_CLEAR;
186 break;
187
188 case IDC_BACK:
189 stock = GTK_STOCK_GO_BACK;
190 break;
191
192 case IDC_RELOAD:
193 stock = GTK_STOCK_REFRESH;
194 break;
195
196 case IDC_FORWARD:
197 stock = GTK_STOCK_GO_FORWARD;
198 break;
199
200 case IDC_PRINT:
201 stock = GTK_STOCK_PRINT;
202 break;
203
204 case IDC_CONTENT_CONTEXT_VIEWPAGEINFO:
205 stock = GTK_STOCK_INFO;
206 break;
207
208 case IDC_SPELLCHECK_MENU:
209 stock = GTK_STOCK_SPELL_CHECK;
210 break;
211
212 case IDC_RESTORE_TAB:
213 stock = GTK_STOCK_UNDELETE;
214 break;
215
216 case IDC_HOME:
217 stock = GTK_STOCK_HOME;
218 break;
219
220 case IDC_STOP:
221 stock = GTK_STOCK_STOP;
222 break;
223
224 case IDC_ABOUT:
225 stock = GTK_STOCK_ABOUT;
226 break;
227
228 case IDC_EXIT:
229 stock = GTK_STOCK_QUIT;
230 break;
231
232 case IDC_HELP_PAGE:
233 stock = GTK_STOCK_HELP;
234 break;
235
236 case IDC_OPTIONS:
237 stock = GTK_STOCK_PREFERENCES;
238 break;
239
240 case IDC_CONTENT_CONTEXT_GOTOURL:
241 stock = GTK_STOCK_JUMP_TO;
242 break;
243
244 case IDC_DEV_TOOLS_INSPECT:
245 case IDC_CONTENT_CONTEXT_INSPECTELEMENT:
246 stock = GTK_STOCK_PROPERTIES;
247 break;
248
249 case IDC_BOOKMARK_BAR_ADD_NEW_BOOKMARK:
250 stock = GTK_STOCK_ADD;
251 break;
252
253 case IDC_BOOKMARK_BAR_RENAME_FOLDER:
254 case IDC_BOOKMARK_BAR_EDIT:
255 stock = GTK_STOCK_EDIT;
256 break;
257
258 case IDC_BOOKMARK_BAR_NEW_FOLDER:
259 stock = GTK_STOCK_DIRECTORY;
260 break;
261
262 case IDC_BOOKMARK_BAR_OPEN_ALL:
263 stock = GTK_STOCK_OPEN;
264 break;
265
266 default:
267 stock = NULL;
268 }
269
270 return stock ? gtk_image_new_from_stock(stock, GTK_ICON_SIZE_MENU) : NULL;
271 }
272
273 GtkWidget* MenuGtk::Delegate::GetImageForCommandId(int command_id) const {
274 return GetDefaultImageForCommandId(command_id);
275 }
276
277 MenuGtk::MenuGtk(MenuGtk::Delegate* delegate, 116 MenuGtk::MenuGtk(MenuGtk::Delegate* delegate,
278 ui::MenuModel* model) 117 ui::MenuModel* model)
279 : delegate_(delegate), 118 : GtkMenuCreator(delegate),
119 delegate_(delegate),
280 model_(model), 120 model_(model),
281 dummy_accel_group_(gtk_accel_group_new()),
282 menu_(gtk_custom_menu_new()), 121 menu_(gtk_custom_menu_new()),
283 factory_(this) { 122 factory_(this) {
284 DCHECK(model); 123 DCHECK(model);
285 g_object_ref_sink(menu_); 124 g_object_ref_sink(menu_);
286 ConnectSignalHandlers(); 125 ConnectSignalHandlers();
287 BuildMenuFromModel(); 126 BuildMenuFromModel();
288 } 127 }
289 128
290 MenuGtk::~MenuGtk() { 129 MenuGtk::~MenuGtk() {
291 Cancel(); 130 Cancel();
292 131
293 gtk_widget_destroy(menu_); 132 gtk_widget_destroy(menu_);
294 g_object_unref(menu_); 133 g_object_unref(menu_);
295 134
296 STLDeleteContainerPointers(submenus_we_own_.begin(), submenus_we_own_.end()); 135 STLDeleteContainerPointers(submenus_we_own_.begin(), submenus_we_own_.end());
297 g_object_unref(dummy_accel_group_);
298 } 136 }
299 137
300 void MenuGtk::ConnectSignalHandlers() { 138 void MenuGtk::ConnectSignalHandlers() {
301 // We connect afterwards because OnMenuShow calls SetMenuItemInfo, which may 139 // We connect afterwards because OnMenuShow calls SetMenuItemInfo, which may
302 // take a long time or even start a nested message loop. 140 // take a long time or even start a nested message loop.
303 g_signal_connect(menu_, "show", G_CALLBACK(OnMenuShowThunk), this); 141 g_signal_connect(menu_, "show", G_CALLBACK(OnMenuShowThunk), this);
304 g_signal_connect(menu_, "hide", G_CALLBACK(OnMenuHiddenThunk), this); 142 g_signal_connect(menu_, "hide", G_CALLBACK(OnMenuHiddenThunk), this);
305 } 143 }
306 144
307 GtkWidget* MenuGtk::AppendMenuItemWithLabel(int command_id, 145 GtkWidget* MenuGtk::AppendMenuItemWithLabel(int command_id,
(...skipping 24 matching lines...) Expand all
332 gtk_widget_show(menu_item); 170 gtk_widget_show(menu_item);
333 gtk_menu_shell_append(GTK_MENU_SHELL(menu_), menu_item); 171 gtk_menu_shell_append(GTK_MENU_SHELL(menu_), menu_item);
334 return menu_item; 172 return menu_item;
335 } 173 }
336 174
337 GtkWidget* MenuGtk::AppendMenuItem(int command_id, GtkWidget* menu_item) { 175 GtkWidget* MenuGtk::AppendMenuItem(int command_id, GtkWidget* menu_item) {
338 if (delegate_ && delegate_->AlwaysShowIconForCmd(command_id) && 176 if (delegate_ && delegate_->AlwaysShowIconForCmd(command_id) &&
339 GTK_IS_IMAGE_MENU_ITEM(menu_item)) 177 GTK_IS_IMAGE_MENU_ITEM(menu_item))
340 gtk_util::SetAlwaysShowImage(menu_item); 178 gtk_util::SetAlwaysShowImage(menu_item);
341 179
342 return AppendMenuItemToMenu(command_id, NULL, menu_item, menu_, true); 180 gtk_menu_shell_append(GTK_MENU_SHELL(menu_), menu_item);
181 return AppendMenuItemToMenu(command_id, NULL, menu_item, menu_);
343 } 182 }
344 183
345 GtkWidget* MenuGtk::AppendMenuItemToMenu(int index, 184 GtkWidget* MenuGtk::AppendMenuItemToMenu(int index,
346 ui::MenuModel* model, 185 ui::MenuModel* model,
347 GtkWidget* menu_item, 186 GtkWidget* menu_item,
348 GtkWidget* menu, 187 GtkWidget* menu) {
349 bool connect_to_activate) {
350 SetMenuItemID(menu_item, index); 188 SetMenuItemID(menu_item, index);
351 189
352 // Native menu items do their own thing, so only selectively listen for the 190 // Native menu items do their own thing, so only selectively listen for the
353 // activate signal. 191 // activate signal.
354 if (connect_to_activate) { 192 if (!model ||
193 model->GetTypeAt(index) != ui::MenuModel::TYPE_BUTTON_ITEM) {
355 g_signal_connect(menu_item, "activate", 194 g_signal_connect(menu_item, "activate",
356 G_CALLBACK(OnMenuItemActivatedThunk), this); 195 G_CALLBACK(OnMenuItemActivatedThunk), this);
357 } 196 }
358 197
359 // AppendMenuItemToMenu is used both internally when we control menu creation 198 // AppendMenuItemToMenu is used both internally when we control menu creation
360 // from a model (where the model can choose to hide certain menu items), and 199 // from a model (where the model can choose to hide certain menu items), and
361 // with immediate commands which don't provide the option. 200 // with immediate commands which don't provide the option.
362 if (model) { 201 if (model) {
Evan Stade 2011/04/25 20:08:22 if (!model || model->IsVisibleAt(index))
363 if (model->IsVisibleAt(index)) 202 if (model->IsVisibleAt(index))
364 gtk_widget_show(menu_item); 203 gtk_widget_show(menu_item);
365 } else { 204 } else {
366 gtk_widget_show(menu_item); 205 gtk_widget_show(menu_item);
367 } 206 }
368 gtk_menu_shell_append(GTK_MENU_SHELL(menu), menu_item); 207
369 return menu_item; 208 return menu_item;
370 } 209 }
371 210
372 void MenuGtk::PopupForWidget(GtkWidget* widget, int button, 211 void MenuGtk::PopupForWidget(GtkWidget* widget, int button,
373 guint32 event_time) { 212 guint32 event_time) {
374 gtk_menu_popup(GTK_MENU(menu_), NULL, NULL, 213 gtk_menu_popup(GTK_MENU(menu_), NULL, NULL,
375 WidgetMenuPositionFunc, 214 WidgetMenuPositionFunc,
376 widget, 215 widget,
377 button, event_time); 216 button, event_time);
378 } 217 }
(...skipping 18 matching lines...) Expand all
397 } 236 }
398 237
399 void MenuGtk::Cancel() { 238 void MenuGtk::Cancel() {
400 gtk_menu_popdown(GTK_MENU(menu_)); 239 gtk_menu_popdown(GTK_MENU(menu_));
401 } 240 }
402 241
403 void MenuGtk::UpdateMenu() { 242 void MenuGtk::UpdateMenu() {
404 gtk_container_foreach(GTK_CONTAINER(menu_), SetMenuItemInfo, this); 243 gtk_container_foreach(GTK_CONTAINER(menu_), SetMenuItemInfo, this);
405 } 244 }
406 245
407 GtkWidget* MenuGtk::BuildMenuItemWithImage(const std::string& label,
408 GtkWidget* image) {
409 GtkWidget* menu_item =
410 gtk_image_menu_item_new_with_mnemonic(label.c_str());
411 gtk_image_menu_item_set_image(GTK_IMAGE_MENU_ITEM(menu_item), image);
412 return menu_item;
413 }
414
415 GtkWidget* MenuGtk::BuildMenuItemWithImage(const std::string& label,
416 const SkBitmap& icon) {
417 GdkPixbuf* pixbuf = gfx::GdkPixbufFromSkBitmap(&icon);
418 GtkWidget* menu_item = BuildMenuItemWithImage(label,
419 gtk_image_new_from_pixbuf(pixbuf));
420 g_object_unref(pixbuf);
421 return menu_item;
422 }
423
424 GtkWidget* MenuGtk::BuildMenuItemWithLabel(const std::string& label,
425 int command_id) {
426 GtkWidget* img =
427 delegate_ ? delegate_->GetImageForCommandId(command_id) :
428 MenuGtk::Delegate::GetDefaultImageForCommandId(command_id);
429 return img ? BuildMenuItemWithImage(label, img) :
430 gtk_menu_item_new_with_mnemonic(label.c_str());
431 }
432
433 void MenuGtk::BuildMenuFromModel() { 246 void MenuGtk::BuildMenuFromModel() {
434 BuildSubmenuFromModel(model_, menu_); 247 BuildSubmenuFromModel(model_, menu_);
435 } 248 }
436 249
437 void MenuGtk::BuildSubmenuFromModel(ui::MenuModel* model, GtkWidget* menu) {
438 std::map<int, GtkWidget*> radio_groups;
439 GtkWidget* menu_item = NULL;
440 for (int i = 0; i < model->GetItemCount(); ++i) {
441 SkBitmap icon;
442 std::string label =
443 gfx::ConvertAcceleratorsFromWindowsStyle(
444 UTF16ToUTF8(model->GetLabelAt(i)));
445 bool connect_to_activate = true;
446
447 switch (model->GetTypeAt(i)) {
448 case ui::MenuModel::TYPE_SEPARATOR:
449 menu_item = gtk_separator_menu_item_new();
450 break;
451
452 case ui::MenuModel::TYPE_CHECK:
453 menu_item = gtk_check_menu_item_new_with_mnemonic(label.c_str());
454 break;
455
456 case ui::MenuModel::TYPE_RADIO: {
457 std::map<int, GtkWidget*>::iterator iter =
458 radio_groups.find(model->GetGroupIdAt(i));
459
460 if (iter == radio_groups.end()) {
461 menu_item = gtk_radio_menu_item_new_with_mnemonic(
462 NULL, label.c_str());
463 radio_groups[model->GetGroupIdAt(i)] = menu_item;
464 } else {
465 menu_item = gtk_radio_menu_item_new_with_mnemonic_from_widget(
466 GTK_RADIO_MENU_ITEM(iter->second), label.c_str());
467 }
468 break;
469 }
470 case ui::MenuModel::TYPE_BUTTON_ITEM: {
471 ui::ButtonMenuItemModel* button_menu_item_model =
472 model->GetButtonMenuItemAt(i);
473 menu_item = BuildButtonMenuItem(button_menu_item_model, menu);
474 connect_to_activate = false;
475 break;
476 }
477 case ui::MenuModel::TYPE_SUBMENU:
478 case ui::MenuModel::TYPE_COMMAND: {
479 int command_id = model->GetCommandIdAt(i);
480 if (model->GetIconAt(i, &icon))
481 menu_item = BuildMenuItemWithImage(label, icon);
482 else
483 menu_item = BuildMenuItemWithLabel(label, command_id);
484 if (delegate_ && delegate_->AlwaysShowIconForCmd(command_id) &&
485 GTK_IS_IMAGE_MENU_ITEM(menu_item))
486 gtk_util::SetAlwaysShowImage(menu_item);
487 break;
488 }
489
490 default:
491 NOTREACHED();
492 }
493
494 if (model->GetTypeAt(i) == ui::MenuModel::TYPE_SUBMENU) {
495 GtkWidget* submenu = gtk_menu_new();
496 BuildSubmenuFromModel(model->GetSubmenuModelAt(i), submenu);
497 gtk_menu_item_set_submenu(GTK_MENU_ITEM(menu_item), submenu);
498 }
499
500 ui::AcceleratorGtk accelerator;
501 if (model->GetAcceleratorAt(i, &accelerator)) {
502 gtk_widget_add_accelerator(menu_item,
503 "activate",
504 dummy_accel_group_,
505 accelerator.GetGdkKeyCode(),
506 accelerator.gdk_modifier_type(),
507 GTK_ACCEL_VISIBLE);
508 }
509
510 g_object_set_data(G_OBJECT(menu_item), "model", model);
511 AppendMenuItemToMenu(i, model, menu_item, menu, connect_to_activate);
512
513 menu_item = NULL;
514 }
515 }
516
517 GtkWidget* MenuGtk::BuildButtonMenuItem(ui::ButtonMenuItemModel* model, 250 GtkWidget* MenuGtk::BuildButtonMenuItem(ui::ButtonMenuItemModel* model,
518 GtkWidget* menu) { 251 GtkWidget* menu) {
519 GtkWidget* menu_item = gtk_custom_menu_item_new( 252 GtkWidget* menu_item = gtk_custom_menu_item_new(
520 gfx::RemoveWindowsStyleAccelerators(UTF16ToUTF8(model->label())).c_str()); 253 gfx::RemoveWindowsStyleAccelerators(UTF16ToUTF8(model->label())).c_str());
521 254
522 // Set up the callback to the model for when it is clicked. 255 // Set up the callback to the model for when it is clicked.
523 g_object_set_data(G_OBJECT(menu_item), "button-model", model); 256 g_object_set_data(G_OBJECT(menu_item), "button-model", model);
524 g_signal_connect(menu_item, "button-pushed", 257 g_signal_connect(menu_item, "button-pushed",
525 G_CALLBACK(OnMenuButtonPressedThunk), this); 258 G_CALLBACK(OnMenuButtonPressedThunk), this);
526 g_signal_connect(menu_item, "try-button-pushed", 259 g_signal_connect(menu_item, "try-button-pushed",
(...skipping 296 matching lines...) Expand 10 before | Expand all | Expand 10 after
823 gtk_widget_hide(widget); 556 gtk_widget_hide(widget);
824 } 557 }
825 558
826 GtkWidget* submenu = gtk_menu_item_get_submenu(GTK_MENU_ITEM(widget)); 559 GtkWidget* submenu = gtk_menu_item_get_submenu(GTK_MENU_ITEM(widget));
827 if (submenu) { 560 if (submenu) {
828 gtk_container_foreach(GTK_CONTAINER(submenu), &SetMenuItemInfo, 561 gtk_container_foreach(GTK_CONTAINER(submenu), &SetMenuItemInfo,
829 userdata); 562 userdata);
830 } 563 }
831 } 564 }
832 } 565 }
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698