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

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

Issue 6251001: Move chrome/browser/gtk/ to chrome/browser/ui/gtk/... (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src/
Patch Set: '' Created 9 years, 11 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
« no previous file with comments | « chrome/browser/gtk/menu_gtk.h ('k') | chrome/browser/gtk/nine_box.h » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
(Empty)
1 // Copyright (c) 2010 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.
4
5 #include "chrome/browser/gtk/menu_gtk.h"
6
7 #include <map>
8
9 #include "app/menus/accelerator_gtk.h"
10 #include "app/menus/button_menu_item_model.h"
11 #include "app/menus/menu_model.h"
12 #include "base/i18n/rtl.h"
13 #include "base/logging.h"
14 #include "base/message_loop.h"
15 #include "base/stl_util-inl.h"
16 #include "base/utf_string_conversions.h"
17 #include "chrome/app/chrome_command_ids.h"
18 #include "chrome/browser/gtk/gtk_custom_menu.h"
19 #include "chrome/browser/gtk/gtk_custom_menu_item.h"
20 #include "chrome/browser/gtk/gtk_util.h"
21 #include "gfx/gtk_util.h"
22 #include "third_party/skia/include/core/SkBitmap.h"
23 #include "webkit/glue/window_open_disposition.h"
24
25 bool MenuGtk::block_activation_ = false;
26
27 namespace {
28
29 // Sets the ID of a menu item.
30 void SetMenuItemID(GtkWidget* menu_item, int menu_id) {
31 DCHECK_GE(menu_id, 0);
32
33 // Add 1 to the menu_id to avoid setting zero (null) to "menu-id".
34 g_object_set_data(G_OBJECT(menu_item), "menu-id",
35 GINT_TO_POINTER(menu_id + 1));
36 }
37
38 // Gets the ID of a menu item.
39 // Returns true if the menu item has an ID.
40 bool GetMenuItemID(GtkWidget* menu_item, int* menu_id) {
41 gpointer id_ptr = g_object_get_data(G_OBJECT(menu_item), "menu-id");
42 if (id_ptr != NULL) {
43 *menu_id = GPOINTER_TO_INT(id_ptr) - 1;
44 return true;
45 }
46
47 return false;
48 }
49
50 menus::MenuModel* ModelForMenuItem(GtkMenuItem* menu_item) {
51 return reinterpret_cast<menus::MenuModel*>(
52 g_object_get_data(G_OBJECT(menu_item), "model"));
53 }
54
55 void SetupButtonShowHandler(GtkWidget* button,
56 menus::ButtonMenuItemModel* model,
57 int index) {
58 g_object_set_data(G_OBJECT(button), "button-model",
59 model);
60 g_object_set_data(G_OBJECT(button), "button-model-id",
61 GINT_TO_POINTER(index));
62 }
63
64 void OnSubmenuShowButtonImage(GtkWidget* widget, GtkButton* button) {
65 MenuGtk::Delegate* delegate = reinterpret_cast<MenuGtk::Delegate*>(
66 g_object_get_data(G_OBJECT(button), "menu-gtk-delegate"));
67 int icon_idr = GPOINTER_TO_INT(g_object_get_data(
68 G_OBJECT(button), "button-image-idr"));
69
70 GtkIconSet* icon_set = delegate->GetIconSetForId(icon_idr);
71 if (icon_set) {
72 gtk_button_set_image(
73 button, gtk_image_new_from_icon_set(icon_set,
74 GTK_ICON_SIZE_MENU));
75 }
76 }
77
78 void SetupImageIcon(GtkWidget* button,
79 GtkWidget* menu,
80 int icon_idr,
81 MenuGtk::Delegate* menu_gtk_delegate) {
82 g_object_set_data(G_OBJECT(button), "button-image-idr",
83 GINT_TO_POINTER(icon_idr));
84 g_object_set_data(G_OBJECT(button), "menu-gtk-delegate",
85 menu_gtk_delegate);
86
87 g_signal_connect(menu, "show", G_CALLBACK(OnSubmenuShowButtonImage), button);
88 }
89
90 // Popup menus may get squished if they open up too close to the bottom of the
91 // screen. This function takes the size of the screen, the size of the menu,
92 // an optional widget, the Y position of the mouse click, and adjusts the popup
93 // menu's Y position to make it fit if it's possible to do so.
94 // Returns the new Y position of the popup menu.
95 int CalculateMenuYPosition(const GdkRectangle* screen_rect,
96 const GtkRequisition* menu_req,
97 const GtkWidget* widget, const int y) {
98 CHECK(screen_rect);
99 CHECK(menu_req);
100 // If the menu would run off the bottom of the screen, and there is enough
101 // screen space upwards to accommodate the menu, then pop upwards. If there
102 // is a widget, then also move the anchor point to the top of the widget
103 // rather than the bottom.
104 const int screen_top = screen_rect->y;
105 const int screen_bottom = screen_rect->y + screen_rect->height;
106 const int menu_bottom = y + menu_req->height;
107 int alternate_y = y - menu_req->height;
108 if (widget)
109 alternate_y -= widget->allocation.height;
110 if (menu_bottom >= screen_bottom && alternate_y >= screen_top)
111 return alternate_y;
112 return y;
113 }
114
115 } // namespace
116
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,
278 menus::MenuModel* model)
279 : delegate_(delegate),
280 model_(model),
281 dummy_accel_group_(gtk_accel_group_new()),
282 menu_(gtk_custom_menu_new()),
283 factory_(this) {
284 DCHECK(model);
285 g_object_ref_sink(menu_);
286 ConnectSignalHandlers();
287 BuildMenuFromModel();
288 }
289
290 MenuGtk::~MenuGtk() {
291 Cancel();
292
293 gtk_widget_destroy(menu_);
294 g_object_unref(menu_);
295
296 STLDeleteContainerPointers(submenus_we_own_.begin(), submenus_we_own_.end());
297 g_object_unref(dummy_accel_group_);
298 }
299
300 void MenuGtk::ConnectSignalHandlers() {
301 // We connect afterwards because OnMenuShow calls SetMenuItemInfo, which may
302 // take a long time or even start a nested message loop.
303 g_signal_connect(menu_, "show", G_CALLBACK(OnMenuShowThunk), this);
304 g_signal_connect(menu_, "hide", G_CALLBACK(OnMenuHiddenThunk), this);
305 }
306
307 GtkWidget* MenuGtk::AppendMenuItemWithLabel(int command_id,
308 const std::string& label) {
309 std::string converted_label = gfx::ConvertAcceleratorsFromWindowsStyle(label);
310 GtkWidget* menu_item = BuildMenuItemWithLabel(label, command_id);
311 return AppendMenuItem(command_id, menu_item);
312 }
313
314 GtkWidget* MenuGtk::AppendMenuItemWithIcon(int command_id,
315 const std::string& label,
316 const SkBitmap& icon) {
317 std::string converted_label = gfx::ConvertAcceleratorsFromWindowsStyle(label);
318 GtkWidget* menu_item = BuildMenuItemWithImage(converted_label, icon);
319 return AppendMenuItem(command_id, menu_item);
320 }
321
322 GtkWidget* MenuGtk::AppendCheckMenuItemWithLabel(int command_id,
323 const std::string& label) {
324 std::string converted_label = gfx::ConvertAcceleratorsFromWindowsStyle(label);
325 GtkWidget* menu_item =
326 gtk_check_menu_item_new_with_mnemonic(converted_label.c_str());
327 return AppendMenuItem(command_id, menu_item);
328 }
329
330 GtkWidget* MenuGtk::AppendSeparator() {
331 GtkWidget* menu_item = gtk_separator_menu_item_new();
332 gtk_widget_show(menu_item);
333 gtk_menu_shell_append(GTK_MENU_SHELL(menu_), menu_item);
334 return menu_item;
335 }
336
337 GtkWidget* MenuGtk::AppendMenuItem(int command_id, GtkWidget* menu_item) {
338 if (delegate_ && delegate_->AlwaysShowIconForCmd(command_id) &&
339 GTK_IS_IMAGE_MENU_ITEM(menu_item))
340 gtk_util::SetAlwaysShowImage(menu_item);
341
342 return AppendMenuItemToMenu(command_id, NULL, menu_item, menu_, true);
343 }
344
345 GtkWidget* MenuGtk::AppendMenuItemToMenu(int index,
346 menus::MenuModel* model,
347 GtkWidget* menu_item,
348 GtkWidget* menu,
349 bool connect_to_activate) {
350 SetMenuItemID(menu_item, index);
351
352 // Native menu items do their own thing, so only selectively listen for the
353 // activate signal.
354 if (connect_to_activate) {
355 g_signal_connect(menu_item, "activate",
356 G_CALLBACK(OnMenuItemActivatedThunk), this);
357 }
358
359 // 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
361 // with immediate commands which don't provide the option.
362 if (model) {
363 if (model->IsVisibleAt(index))
364 gtk_widget_show(menu_item);
365 } else {
366 gtk_widget_show(menu_item);
367 }
368 gtk_menu_shell_append(GTK_MENU_SHELL(menu), menu_item);
369 return menu_item;
370 }
371
372 void MenuGtk::Popup(GtkWidget* widget, GdkEvent* event) {
373 DCHECK(event->type == GDK_BUTTON_PRESS)
374 << "Non-button press event sent to RunMenuAt";
375
376 Popup(widget, event->button.button, event->button.time);
377 }
378
379 void MenuGtk::Popup(GtkWidget* widget, gint button_type, guint32 timestamp) {
380 gtk_menu_popup(GTK_MENU(menu_), NULL, NULL,
381 WidgetMenuPositionFunc,
382 widget,
383 button_type, timestamp);
384 }
385
386 void MenuGtk::PopupAsContext(guint32 event_time) {
387 // TODO(estade): |button| value of 3 (6th argument) is not strictly true,
388 // but does it matter?
389 gtk_menu_popup(GTK_MENU(menu_), NULL, NULL, NULL, NULL, 3, event_time);
390 }
391
392 void MenuGtk::PopupAsContextAt(guint32 event_time, gfx::Point point) {
393 gtk_menu_popup(GTK_MENU(menu_), NULL, NULL,
394 PointMenuPositionFunc, &point, 3, event_time);
395 }
396
397 void MenuGtk::PopupAsContextForStatusIcon(guint32 event_time, guint32 button,
398 GtkStatusIcon* icon) {
399 gtk_menu_popup(GTK_MENU(menu_), NULL, NULL, gtk_status_icon_position_menu,
400 icon, button, event_time);
401 }
402
403 void MenuGtk::PopupAsFromKeyEvent(GtkWidget* widget) {
404 Popup(widget, 0, gtk_get_current_event_time());
405 gtk_menu_shell_select_first(GTK_MENU_SHELL(menu_), FALSE);
406 }
407
408 void MenuGtk::Cancel() {
409 gtk_menu_popdown(GTK_MENU(menu_));
410 }
411
412 void MenuGtk::UpdateMenu() {
413 gtk_container_foreach(GTK_CONTAINER(menu_), SetMenuItemInfo, this);
414 }
415
416 GtkWidget* MenuGtk::BuildMenuItemWithImage(const std::string& label,
417 GtkWidget* image) {
418 GtkWidget* menu_item =
419 gtk_image_menu_item_new_with_mnemonic(label.c_str());
420 gtk_image_menu_item_set_image(GTK_IMAGE_MENU_ITEM(menu_item), image);
421 return menu_item;
422 }
423
424 GtkWidget* MenuGtk::BuildMenuItemWithImage(const std::string& label,
425 const SkBitmap& icon) {
426 GdkPixbuf* pixbuf = gfx::GdkPixbufFromSkBitmap(&icon);
427 GtkWidget* menu_item = BuildMenuItemWithImage(label,
428 gtk_image_new_from_pixbuf(pixbuf));
429 g_object_unref(pixbuf);
430 return menu_item;
431 }
432
433 GtkWidget* MenuGtk::BuildMenuItemWithLabel(const std::string& label,
434 int command_id) {
435 GtkWidget* img =
436 delegate_ ? delegate_->GetImageForCommandId(command_id) :
437 MenuGtk::Delegate::GetDefaultImageForCommandId(command_id);
438 return img ? BuildMenuItemWithImage(label, img) :
439 gtk_menu_item_new_with_mnemonic(label.c_str());
440 }
441
442 void MenuGtk::BuildMenuFromModel() {
443 BuildSubmenuFromModel(model_, menu_);
444 }
445
446 void MenuGtk::BuildSubmenuFromModel(menus::MenuModel* model, GtkWidget* menu) {
447 std::map<int, GtkWidget*> radio_groups;
448 GtkWidget* menu_item = NULL;
449 for (int i = 0; i < model->GetItemCount(); ++i) {
450 SkBitmap icon;
451 std::string label =
452 gfx::ConvertAcceleratorsFromWindowsStyle(
453 UTF16ToUTF8(model->GetLabelAt(i)));
454 bool connect_to_activate = true;
455
456 switch (model->GetTypeAt(i)) {
457 case menus::MenuModel::TYPE_SEPARATOR:
458 menu_item = gtk_separator_menu_item_new();
459 break;
460
461 case menus::MenuModel::TYPE_CHECK:
462 menu_item = gtk_check_menu_item_new_with_mnemonic(label.c_str());
463 break;
464
465 case menus::MenuModel::TYPE_RADIO: {
466 std::map<int, GtkWidget*>::iterator iter =
467 radio_groups.find(model->GetGroupIdAt(i));
468
469 if (iter == radio_groups.end()) {
470 menu_item = gtk_radio_menu_item_new_with_mnemonic(
471 NULL, label.c_str());
472 radio_groups[model->GetGroupIdAt(i)] = menu_item;
473 } else {
474 menu_item = gtk_radio_menu_item_new_with_mnemonic_from_widget(
475 GTK_RADIO_MENU_ITEM(iter->second), label.c_str());
476 }
477 break;
478 }
479 case menus::MenuModel::TYPE_BUTTON_ITEM: {
480 menus::ButtonMenuItemModel* button_menu_item_model =
481 model->GetButtonMenuItemAt(i);
482 menu_item = BuildButtomMenuItem(button_menu_item_model, menu);
483 connect_to_activate = false;
484 break;
485 }
486 case menus::MenuModel::TYPE_SUBMENU:
487 case menus::MenuModel::TYPE_COMMAND: {
488 int command_id = model->GetCommandIdAt(i);
489 if (model->GetIconAt(i, &icon))
490 menu_item = BuildMenuItemWithImage(label, icon);
491 else
492 menu_item = BuildMenuItemWithLabel(label, command_id);
493 if (delegate_ && delegate_->AlwaysShowIconForCmd(command_id) &&
494 GTK_IS_IMAGE_MENU_ITEM(menu_item))
495 gtk_util::SetAlwaysShowImage(menu_item);
496 break;
497 }
498
499 default:
500 NOTREACHED();
501 }
502
503 if (model->GetTypeAt(i) == menus::MenuModel::TYPE_SUBMENU) {
504 GtkWidget* submenu = gtk_menu_new();
505 BuildSubmenuFromModel(model->GetSubmenuModelAt(i), submenu);
506 gtk_menu_item_set_submenu(GTK_MENU_ITEM(menu_item), submenu);
507 }
508
509 menus::AcceleratorGtk accelerator;
510 if (model->GetAcceleratorAt(i, &accelerator)) {
511 gtk_widget_add_accelerator(menu_item,
512 "activate",
513 dummy_accel_group_,
514 accelerator.GetGdkKeyCode(),
515 accelerator.gdk_modifier_type(),
516 GTK_ACCEL_VISIBLE);
517 }
518
519 g_object_set_data(G_OBJECT(menu_item), "model", model);
520 AppendMenuItemToMenu(i, model, menu_item, menu, connect_to_activate);
521
522 menu_item = NULL;
523 }
524 }
525
526 GtkWidget* MenuGtk::BuildButtomMenuItem(menus::ButtonMenuItemModel* model,
527 GtkWidget* menu) {
528 GtkWidget* menu_item = gtk_custom_menu_item_new(
529 gfx::RemoveWindowsStyleAccelerators(UTF16ToUTF8(model->label())).c_str());
530
531 // Set up the callback to the model for when it is clicked.
532 g_object_set_data(G_OBJECT(menu_item), "button-model", model);
533 g_signal_connect(menu_item, "button-pushed",
534 G_CALLBACK(OnMenuButtonPressedThunk), this);
535 g_signal_connect(menu_item, "try-button-pushed",
536 G_CALLBACK(OnMenuTryButtonPressedThunk), this);
537
538 GtkSizeGroup* group = NULL;
539 for (int i = 0; i < model->GetItemCount(); ++i) {
540 GtkWidget* button = NULL;
541
542 switch (model->GetTypeAt(i)) {
543 case menus::ButtonMenuItemModel::TYPE_SPACE: {
544 gtk_custom_menu_item_add_space(GTK_CUSTOM_MENU_ITEM(menu_item));
545 break;
546 }
547 case menus::ButtonMenuItemModel::TYPE_BUTTON: {
548 button = gtk_custom_menu_item_add_button(
549 GTK_CUSTOM_MENU_ITEM(menu_item),
550 model->GetCommandIdAt(i));
551
552 int icon_idr;
553 if (model->GetIconAt(i, &icon_idr)) {
554 SetupImageIcon(button, menu, icon_idr, delegate_);
555 } else {
556 gtk_button_set_label(
557 GTK_BUTTON(button),
558 gfx::RemoveWindowsStyleAccelerators(
559 UTF16ToUTF8(model->GetLabelAt(i))).c_str());
560 }
561
562 SetupButtonShowHandler(button, model, i);
563 break;
564 }
565 case menus::ButtonMenuItemModel::TYPE_BUTTON_LABEL: {
566 button = gtk_custom_menu_item_add_button_label(
567 GTK_CUSTOM_MENU_ITEM(menu_item),
568 model->GetCommandIdAt(i));
569 gtk_button_set_label(
570 GTK_BUTTON(button),
571 gfx::RemoveWindowsStyleAccelerators(
572 UTF16ToUTF8(model->GetLabelAt(i))).c_str());
573 SetupButtonShowHandler(button, model, i);
574 break;
575 }
576 }
577
578 if (button && model->PartOfGroup(i)) {
579 if (!group)
580 group = gtk_size_group_new(GTK_SIZE_GROUP_HORIZONTAL);
581
582 gtk_size_group_add_widget(group, button);
583 }
584 }
585
586 if (group) {
587 g_object_unref(group);
588 }
589
590 return menu_item;
591 }
592
593 void MenuGtk::OnMenuItemActivated(GtkWidget* menuitem) {
594 if (block_activation_)
595 return;
596
597 // We receive activation messages when highlighting a menu that has a
598 // submenu. Ignore them.
599 if (gtk_menu_item_get_submenu(GTK_MENU_ITEM(menuitem)))
600 return;
601
602 // The activate signal is sent to radio items as they get deselected;
603 // ignore it in this case.
604 if (GTK_IS_RADIO_MENU_ITEM(menuitem) &&
605 !gtk_check_menu_item_get_active(GTK_CHECK_MENU_ITEM(menuitem))) {
606 return;
607 }
608
609 int id;
610 if (!GetMenuItemID(menuitem, &id))
611 return;
612
613 menus::MenuModel* model = ModelForMenuItem(GTK_MENU_ITEM(menuitem));
614
615 // The menu item can still be activated by hotkeys even if it is disabled.
616 if (model->IsEnabledAt(id))
617 ExecuteCommand(model, id);
618 }
619
620 void MenuGtk::OnMenuButtonPressed(GtkWidget* menu_item, int command_id) {
621 menus::ButtonMenuItemModel* model =
622 reinterpret_cast<menus::ButtonMenuItemModel*>(
623 g_object_get_data(G_OBJECT(menu_item), "button-model"));
624 if (model && model->IsCommandIdEnabled(command_id)) {
625 if (delegate_)
626 delegate_->CommandWillBeExecuted();
627
628 model->ActivatedCommand(command_id);
629 }
630 }
631
632 gboolean MenuGtk::OnMenuTryButtonPressed(GtkWidget* menu_item,
633 int command_id) {
634 gboolean pressed = FALSE;
635 menus::ButtonMenuItemModel* model =
636 reinterpret_cast<menus::ButtonMenuItemModel*>(
637 g_object_get_data(G_OBJECT(menu_item), "button-model"));
638 if (model &&
639 model->IsCommandIdEnabled(command_id) &&
640 !model->DoesCommandIdDismissMenu(command_id)) {
641 if (delegate_)
642 delegate_->CommandWillBeExecuted();
643
644 model->ActivatedCommand(command_id);
645 pressed = TRUE;
646 }
647
648 return pressed;
649 }
650
651 // static
652 void MenuGtk::WidgetMenuPositionFunc(GtkMenu* menu,
653 int* x,
654 int* y,
655 gboolean* push_in,
656 void* void_widget) {
657 GtkWidget* widget = GTK_WIDGET(void_widget);
658 GtkRequisition menu_req;
659
660 gtk_widget_size_request(GTK_WIDGET(menu), &menu_req);
661
662 gdk_window_get_origin(widget->window, x, y);
663 GdkScreen *screen = gtk_widget_get_screen(widget);
664 gint monitor = gdk_screen_get_monitor_at_point(screen, *x, *y);
665
666 GdkRectangle screen_rect;
667 gdk_screen_get_monitor_geometry(screen, monitor,
668 &screen_rect);
669
670 if (GTK_WIDGET_NO_WINDOW(widget)) {
671 *x += widget->allocation.x;
672 *y += widget->allocation.y;
673 }
674 *y += widget->allocation.height;
675
676 bool start_align =
677 !!g_object_get_data(G_OBJECT(widget), "left-align-popup");
678 if (base::i18n::IsRTL())
679 start_align = !start_align;
680
681 if (!start_align)
682 *x += widget->allocation.width - menu_req.width;
683
684 *y = CalculateMenuYPosition(&screen_rect, &menu_req, widget, *y);
685
686 *push_in = FALSE;
687 }
688
689 // static
690 void MenuGtk::PointMenuPositionFunc(GtkMenu* menu,
691 int* x,
692 int* y,
693 gboolean* push_in,
694 gpointer userdata) {
695 *push_in = TRUE;
696
697 gfx::Point* point = reinterpret_cast<gfx::Point*>(userdata);
698 *x = point->x();
699 *y = point->y();
700
701 GtkRequisition menu_req;
702 gtk_widget_size_request(GTK_WIDGET(menu), &menu_req);
703 GdkScreen* screen;
704 gdk_display_get_pointer(gdk_display_get_default(), &screen, NULL, NULL, NULL);
705 gint monitor = gdk_screen_get_monitor_at_point(screen, *x, *y);
706
707 GdkRectangle screen_rect;
708 gdk_screen_get_monitor_geometry(screen, monitor, &screen_rect);
709
710 *y = CalculateMenuYPosition(&screen_rect, &menu_req, NULL, *y);
711 }
712
713 void MenuGtk::ExecuteCommand(menus::MenuModel* model, int id) {
714 if (delegate_)
715 delegate_->CommandWillBeExecuted();
716
717 GdkEvent* event = gtk_get_current_event();
718 if (event && event->type == GDK_BUTTON_RELEASE) {
719 model->ActivatedAtWithDisposition(
720 id, event_utils::DispositionFromEventFlags(event->button.state));
721 } else {
722 model->ActivatedAt(id);
723 }
724
725 if (event)
726 gdk_event_free(event);
727 }
728
729 void MenuGtk::OnMenuShow(GtkWidget* widget) {
730 MessageLoop::current()->PostTask(FROM_HERE,
731 factory_.NewRunnableMethod(&MenuGtk::UpdateMenu));
732 }
733
734 void MenuGtk::OnMenuHidden(GtkWidget* widget) {
735 if (delegate_)
736 delegate_->StoppedShowing();
737 }
738
739 // static
740 void MenuGtk::SetButtonItemInfo(GtkWidget* button, gpointer userdata) {
741 menus::ButtonMenuItemModel* model =
742 reinterpret_cast<menus::ButtonMenuItemModel*>(
743 g_object_get_data(G_OBJECT(button), "button-model"));
744 int index = GPOINTER_TO_INT(g_object_get_data(
745 G_OBJECT(button), "button-model-id"));
746
747 if (model->IsItemDynamicAt(index)) {
748 std::string label =
749 gfx::ConvertAcceleratorsFromWindowsStyle(
750 UTF16ToUTF8(model->GetLabelAt(index)));
751 gtk_button_set_label(GTK_BUTTON(button), label.c_str());
752 }
753
754 gtk_widget_set_sensitive(GTK_WIDGET(button), model->IsEnabledAt(index));
755 }
756
757 // static
758 void MenuGtk::SetMenuItemInfo(GtkWidget* widget, gpointer userdata) {
759 if (GTK_IS_SEPARATOR_MENU_ITEM(widget)) {
760 // We need to explicitly handle this case because otherwise we'll ask the
761 // menu delegate about something with an invalid id.
762 return;
763 }
764
765 int id;
766 if (!GetMenuItemID(widget, &id))
767 return;
768
769 menus::MenuModel* model = ModelForMenuItem(GTK_MENU_ITEM(widget));
770 if (!model) {
771 // If we're not providing the sub menu, then there's no model. For
772 // example, the IME submenu doesn't have a model.
773 return;
774 }
775
776 if (GTK_IS_CHECK_MENU_ITEM(widget)) {
777 GtkCheckMenuItem* item = GTK_CHECK_MENU_ITEM(widget);
778
779 // gtk_check_menu_item_set_active() will send the activate signal. Touching
780 // the underlying "active" property will also call the "activate" handler
781 // for this menu item. So we prevent the "activate" handler from
782 // being called while we set the checkbox.
783 // Why not use one of the glib signal-blocking functions? Because when we
784 // toggle a radio button, it will deactivate one of the other radio buttons,
785 // which we don't have a pointer to.
786 // Wny not make this a member variable? Because "menu" is a pointer to the
787 // root of the MenuGtk and we want to disable *all* MenuGtks, including
788 // submenus.
789 block_activation_ = true;
790 gtk_check_menu_item_set_active(item, model->IsItemCheckedAt(id));
791 block_activation_ = false;
792 }
793
794 if (GTK_IS_CUSTOM_MENU_ITEM(widget)) {
795 // Iterate across all the buttons to update their visible properties.
796 gtk_custom_menu_item_foreach_button(GTK_CUSTOM_MENU_ITEM(widget),
797 SetButtonItemInfo,
798 userdata);
799 }
800
801 if (GTK_IS_MENU_ITEM(widget)) {
802 gtk_widget_set_sensitive(widget, model->IsEnabledAt(id));
803
804 if (model->IsVisibleAt(id)) {
805 // Update the menu item label if it is dynamic.
806 if (model->IsItemDynamicAt(id)) {
807 std::string label =
808 gfx::ConvertAcceleratorsFromWindowsStyle(
809 UTF16ToUTF8(model->GetLabelAt(id)));
810
811 #if GTK_CHECK_VERSION(2, 16, 0)
812 gtk_menu_item_set_label(GTK_MENU_ITEM(widget), label.c_str());
813 #else
814 gtk_label_set_label(GTK_LABEL(GTK_BIN(widget)->child), label.c_str());
815 #endif
816 if (GTK_IS_IMAGE_MENU_ITEM(widget)) {
817 SkBitmap icon;
818 if (model->GetIconAt(id, &icon)) {
819 GdkPixbuf* pixbuf = gfx::GdkPixbufFromSkBitmap(&icon);
820 gtk_image_menu_item_set_image(GTK_IMAGE_MENU_ITEM(widget),
821 gtk_image_new_from_pixbuf(pixbuf));
822 g_object_unref(pixbuf);
823 } else {
824 gtk_image_menu_item_set_image(GTK_IMAGE_MENU_ITEM(widget), NULL);
825 }
826 }
827 }
828
829 gtk_widget_show(widget);
830 } else {
831 gtk_widget_hide(widget);
832 }
833
834 GtkWidget* submenu = gtk_menu_item_get_submenu(GTK_MENU_ITEM(widget));
835 if (submenu) {
836 gtk_container_foreach(GTK_CONTAINER(submenu), &SetMenuItemInfo,
837 userdata);
838 }
839 }
840 }
OLDNEW
« no previous file with comments | « chrome/browser/gtk/menu_gtk.h ('k') | chrome/browser/gtk/nine_box.h » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698