Chromium Code Reviews| OLD | NEW |
|---|---|
| 1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. | 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 | 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/bind.h" | 9 #include "base/bind.h" |
| 10 #include "base/i18n/rtl.h" | 10 #include "base/i18n/rtl.h" |
| 11 #include "base/logging.h" | 11 #include "base/logging.h" |
| 12 #include "base/message_loop.h" | 12 #include "base/message_loop.h" |
| 13 #include "base/stl_util.h" | 13 #include "base/stl_util.h" |
| 14 #include "base/utf_string_conversions.h" | 14 #include "base/utf_string_conversions.h" |
| 15 #include "chrome/app/chrome_command_ids.h" | 15 #include "chrome/app/chrome_command_ids.h" |
| 16 #include "chrome/browser/ui/gtk/gtk_custom_menu.h" | 16 #include "chrome/browser/ui/gtk/gtk_custom_menu.h" |
| 17 #include "chrome/browser/ui/gtk/gtk_custom_menu_item.h" | 17 #include "chrome/browser/ui/gtk/gtk_custom_menu_item.h" |
| 18 #include "chrome/browser/ui/gtk/gtk_util.h" | 18 #include "chrome/browser/ui/gtk/gtk_util.h" |
| 19 #include "chrome/browser/ui/views/event_utils.h" | 19 #include "chrome/browser/ui/views/event_utils.h" |
| 20 #include "third_party/skia/include/core/SkBitmap.h" | 20 #include "third_party/skia/include/core/SkBitmap.h" |
| 21 #include "ui/base/accelerators/accelerator_gtk.h" | 21 #include "ui/base/accelerators/accelerator_gtk.h" |
| 22 #include "ui/base/gtk/menu_label_accelerator_util.h" | |
| 22 #include "ui/base/models/button_menu_item_model.h" | 23 #include "ui/base/models/button_menu_item_model.h" |
| 23 #include "ui/base/models/menu_model.h" | 24 #include "ui/base/models/menu_model.h" |
| 24 #include "ui/gfx/gtk_util.h" | 25 #include "ui/gfx/gtk_util.h" |
| 25 #include "ui/gfx/linux_util.h" | |
| 26 #include "webkit/glue/window_open_disposition.h" | 26 #include "webkit/glue/window_open_disposition.h" |
| 27 | 27 |
| 28 bool MenuGtk::block_activation_ = false; | 28 bool MenuGtk::block_activation_ = false; |
| 29 | 29 |
| 30 namespace { | 30 namespace { |
| 31 | 31 |
| 32 // Sets the ID of a menu item. | 32 // Sets the ID of a menu item. |
| 33 void SetMenuItemID(GtkWidget* menu_item, int menu_id) { | 33 void SetMenuItemID(GtkWidget* menu_item, int menu_id) { |
| 34 DCHECK_GE(menu_id, 0); | 34 DCHECK_GE(menu_id, 0); |
| 35 | 35 |
| (...skipping 264 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 300 g_object_unref(menu_); | 300 g_object_unref(menu_); |
| 301 | 301 |
| 302 g_object_unref(dummy_accel_group_); | 302 g_object_unref(dummy_accel_group_); |
| 303 } | 303 } |
| 304 | 304 |
| 305 void MenuGtk::ConnectSignalHandlers() { | 305 void MenuGtk::ConnectSignalHandlers() { |
| 306 // We connect afterwards because OnMenuShow calls SetMenuItemInfo, which may | 306 // We connect afterwards because OnMenuShow calls SetMenuItemInfo, which may |
| 307 // take a long time or even start a nested message loop. | 307 // take a long time or even start a nested message loop. |
| 308 g_signal_connect(menu_, "show", G_CALLBACK(OnMenuShowThunk), this); | 308 g_signal_connect(menu_, "show", G_CALLBACK(OnMenuShowThunk), this); |
| 309 g_signal_connect(menu_, "hide", G_CALLBACK(OnMenuHiddenThunk), this); | 309 g_signal_connect(menu_, "hide", G_CALLBACK(OnMenuHiddenThunk), this); |
| 310 GtkWidget *toplevel_window = gtk_widget_get_toplevel(menu_); | 310 GtkWidget *toplevel_window = gtk_widget_get_toplevel(menu_); |
|
tfarina
2012/05/03 18:54:26
nit: GtkWidget* :)
tony
2012/05/03 19:14:32
Feel free to fix it in this patch.
| |
| 311 signal_.Connect(toplevel_window, "focus-out-event", | 311 signal_.Connect(toplevel_window, "focus-out-event", |
| 312 G_CALLBACK(OnMenuFocusOutThunk), this); | 312 G_CALLBACK(OnMenuFocusOutThunk), this); |
| 313 } | 313 } |
| 314 | 314 |
| 315 GtkWidget* MenuGtk::AppendMenuItemWithLabel(int command_id, | 315 GtkWidget* MenuGtk::AppendMenuItemWithLabel(int command_id, |
| 316 const std::string& label) { | 316 const std::string& label) { |
| 317 std::string converted_label = gfx::ConvertAcceleratorsFromWindowsStyle(label); | 317 std::string converted_label = ui::ConvertAcceleratorsFromWindowsStyle(label); |
|
tfarina
2012/05/03 18:54:26
nit: this is unused :/
| |
| 318 GtkWidget* menu_item = BuildMenuItemWithLabel(label, command_id); | 318 GtkWidget* menu_item = BuildMenuItemWithLabel(label, command_id); |
|
tfarina
2012/05/03 18:54:26
shouldn't this be converted_label?
tony
2012/05/03 19:14:32
That's interesting. We should fix in a separate p
| |
| 319 return AppendMenuItem(command_id, menu_item); | 319 return AppendMenuItem(command_id, menu_item); |
| 320 } | 320 } |
| 321 | 321 |
| 322 GtkWidget* MenuGtk::AppendMenuItemWithIcon(int command_id, | 322 GtkWidget* MenuGtk::AppendMenuItemWithIcon(int command_id, |
| 323 const std::string& label, | 323 const std::string& label, |
| 324 const SkBitmap& icon) { | 324 const SkBitmap& icon) { |
| 325 std::string converted_label = gfx::ConvertAcceleratorsFromWindowsStyle(label); | 325 std::string converted_label = ui::ConvertAcceleratorsFromWindowsStyle(label); |
| 326 GtkWidget* menu_item = BuildMenuItemWithImage(converted_label, icon); | 326 GtkWidget* menu_item = BuildMenuItemWithImage(converted_label, icon); |
| 327 return AppendMenuItem(command_id, menu_item); | 327 return AppendMenuItem(command_id, menu_item); |
| 328 } | 328 } |
| 329 | 329 |
| 330 GtkWidget* MenuGtk::AppendCheckMenuItemWithLabel(int command_id, | 330 GtkWidget* MenuGtk::AppendCheckMenuItemWithLabel(int command_id, |
| 331 const std::string& label) { | 331 const std::string& label) { |
| 332 std::string converted_label = gfx::ConvertAcceleratorsFromWindowsStyle(label); | 332 std::string converted_label = ui::ConvertAcceleratorsFromWindowsStyle(label); |
| 333 GtkWidget* menu_item = | 333 GtkWidget* menu_item = |
| 334 gtk_check_menu_item_new_with_mnemonic(converted_label.c_str()); | 334 gtk_check_menu_item_new_with_mnemonic(converted_label.c_str()); |
| 335 return AppendMenuItem(command_id, menu_item); | 335 return AppendMenuItem(command_id, menu_item); |
| 336 } | 336 } |
| 337 | 337 |
| 338 GtkWidget* MenuGtk::AppendSeparator() { | 338 GtkWidget* MenuGtk::AppendSeparator() { |
| 339 GtkWidget* menu_item = gtk_separator_menu_item_new(); | 339 GtkWidget* menu_item = gtk_separator_menu_item_new(); |
| 340 gtk_widget_show(menu_item); | 340 gtk_widget_show(menu_item); |
| 341 gtk_menu_shell_append(GTK_MENU_SHELL(menu_), menu_item); | 341 gtk_menu_shell_append(GTK_MENU_SHELL(menu_), menu_item); |
| 342 return menu_item; | 342 return menu_item; |
| (...skipping 97 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 440 | 440 |
| 441 void MenuGtk::BuildMenuFromModel() { | 441 void MenuGtk::BuildMenuFromModel() { |
| 442 BuildSubmenuFromModel(model_, menu_); | 442 BuildSubmenuFromModel(model_, menu_); |
| 443 } | 443 } |
| 444 | 444 |
| 445 void MenuGtk::BuildSubmenuFromModel(ui::MenuModel* model, GtkWidget* menu) { | 445 void MenuGtk::BuildSubmenuFromModel(ui::MenuModel* model, GtkWidget* menu) { |
| 446 std::map<int, GtkWidget*> radio_groups; | 446 std::map<int, GtkWidget*> radio_groups; |
| 447 GtkWidget* menu_item = NULL; | 447 GtkWidget* menu_item = NULL; |
| 448 for (int i = 0; i < model->GetItemCount(); ++i) { | 448 for (int i = 0; i < model->GetItemCount(); ++i) { |
| 449 SkBitmap icon; | 449 SkBitmap icon; |
| 450 std::string label = | 450 std::string label = ui::ConvertAcceleratorsFromWindowsStyle( |
| 451 gfx::ConvertAcceleratorsFromWindowsStyle( | 451 UTF16ToUTF8(model->GetLabelAt(i))); |
| 452 UTF16ToUTF8(model->GetLabelAt(i))); | |
| 453 bool connect_to_activate = true; | 452 bool connect_to_activate = true; |
| 454 | 453 |
| 455 switch (model->GetTypeAt(i)) { | 454 switch (model->GetTypeAt(i)) { |
| 456 case ui::MenuModel::TYPE_SEPARATOR: | 455 case ui::MenuModel::TYPE_SEPARATOR: |
| 457 menu_item = gtk_separator_menu_item_new(); | 456 menu_item = gtk_separator_menu_item_new(); |
| 458 break; | 457 break; |
| 459 | 458 |
| 460 case ui::MenuModel::TYPE_CHECK: | 459 case ui::MenuModel::TYPE_CHECK: |
| 461 menu_item = gtk_check_menu_item_new_with_mnemonic(label.c_str()); | 460 menu_item = gtk_check_menu_item_new_with_mnemonic(label.c_str()); |
| 462 break; | 461 break; |
| (...skipping 61 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 524 g_object_set_data(G_OBJECT(menu_item), "model", model); | 523 g_object_set_data(G_OBJECT(menu_item), "model", model); |
| 525 AppendMenuItemToMenu(i, model, menu_item, menu, connect_to_activate); | 524 AppendMenuItemToMenu(i, model, menu_item, menu, connect_to_activate); |
| 526 | 525 |
| 527 menu_item = NULL; | 526 menu_item = NULL; |
| 528 } | 527 } |
| 529 } | 528 } |
| 530 | 529 |
| 531 GtkWidget* MenuGtk::BuildButtonMenuItem(ui::ButtonMenuItemModel* model, | 530 GtkWidget* MenuGtk::BuildButtonMenuItem(ui::ButtonMenuItemModel* model, |
| 532 GtkWidget* menu) { | 531 GtkWidget* menu) { |
| 533 GtkWidget* menu_item = gtk_custom_menu_item_new( | 532 GtkWidget* menu_item = gtk_custom_menu_item_new( |
| 534 gfx::RemoveWindowsStyleAccelerators(UTF16ToUTF8(model->label())).c_str()); | 533 ui::RemoveWindowsStyleAccelerators(UTF16ToUTF8(model->label())).c_str()); |
| 535 | 534 |
| 536 // Set up the callback to the model for when it is clicked. | 535 // Set up the callback to the model for when it is clicked. |
| 537 g_object_set_data(G_OBJECT(menu_item), "button-model", model); | 536 g_object_set_data(G_OBJECT(menu_item), "button-model", model); |
| 538 g_signal_connect(menu_item, "button-pushed", | 537 g_signal_connect(menu_item, "button-pushed", |
| 539 G_CALLBACK(OnMenuButtonPressedThunk), this); | 538 G_CALLBACK(OnMenuButtonPressedThunk), this); |
| 540 g_signal_connect(menu_item, "try-button-pushed", | 539 g_signal_connect(menu_item, "try-button-pushed", |
| 541 G_CALLBACK(OnMenuTryButtonPressedThunk), this); | 540 G_CALLBACK(OnMenuTryButtonPressedThunk), this); |
| 542 | 541 |
| 543 GtkSizeGroup* group = NULL; | 542 GtkSizeGroup* group = NULL; |
| 544 for (int i = 0; i < model->GetItemCount(); ++i) { | 543 for (int i = 0; i < model->GetItemCount(); ++i) { |
| 545 GtkWidget* button = NULL; | 544 GtkWidget* button = NULL; |
| 546 | 545 |
| 547 switch (model->GetTypeAt(i)) { | 546 switch (model->GetTypeAt(i)) { |
| 548 case ui::ButtonMenuItemModel::TYPE_SPACE: { | 547 case ui::ButtonMenuItemModel::TYPE_SPACE: { |
| 549 gtk_custom_menu_item_add_space(GTK_CUSTOM_MENU_ITEM(menu_item)); | 548 gtk_custom_menu_item_add_space(GTK_CUSTOM_MENU_ITEM(menu_item)); |
| 550 break; | 549 break; |
| 551 } | 550 } |
| 552 case ui::ButtonMenuItemModel::TYPE_BUTTON: { | 551 case ui::ButtonMenuItemModel::TYPE_BUTTON: { |
| 553 button = gtk_custom_menu_item_add_button( | 552 button = gtk_custom_menu_item_add_button( |
| 554 GTK_CUSTOM_MENU_ITEM(menu_item), | 553 GTK_CUSTOM_MENU_ITEM(menu_item), |
| 555 model->GetCommandIdAt(i)); | 554 model->GetCommandIdAt(i)); |
| 556 | 555 |
| 557 int icon_idr; | 556 int icon_idr; |
| 558 if (model->GetIconAt(i, &icon_idr)) { | 557 if (model->GetIconAt(i, &icon_idr)) { |
| 559 SetupImageIcon(button, menu, icon_idr, delegate_); | 558 SetupImageIcon(button, menu, icon_idr, delegate_); |
| 560 } else { | 559 } else { |
| 561 gtk_button_set_label( | 560 gtk_button_set_label( |
| 562 GTK_BUTTON(button), | 561 GTK_BUTTON(button), |
| 563 gfx::RemoveWindowsStyleAccelerators( | 562 ui::RemoveWindowsStyleAccelerators( |
| 564 UTF16ToUTF8(model->GetLabelAt(i))).c_str()); | 563 UTF16ToUTF8(model->GetLabelAt(i))).c_str()); |
| 565 } | 564 } |
| 566 | 565 |
| 567 SetUpButtonShowHandler(button, model, i); | 566 SetUpButtonShowHandler(button, model, i); |
| 568 break; | 567 break; |
| 569 } | 568 } |
| 570 case ui::ButtonMenuItemModel::TYPE_BUTTON_LABEL: { | 569 case ui::ButtonMenuItemModel::TYPE_BUTTON_LABEL: { |
| 571 button = gtk_custom_menu_item_add_button_label( | 570 button = gtk_custom_menu_item_add_button_label( |
| 572 GTK_CUSTOM_MENU_ITEM(menu_item), | 571 GTK_CUSTOM_MENU_ITEM(menu_item), |
| 573 model->GetCommandIdAt(i)); | 572 model->GetCommandIdAt(i)); |
| 574 gtk_button_set_label( | 573 gtk_button_set_label( |
| 575 GTK_BUTTON(button), | 574 GTK_BUTTON(button), |
| 576 gfx::RemoveWindowsStyleAccelerators( | 575 ui::RemoveWindowsStyleAccelerators( |
| 577 UTF16ToUTF8(model->GetLabelAt(i))).c_str()); | 576 UTF16ToUTF8(model->GetLabelAt(i))).c_str()); |
| 578 SetUpButtonShowHandler(button, model, i); | 577 SetUpButtonShowHandler(button, model, i); |
| 579 break; | 578 break; |
| 580 } | 579 } |
| 581 } | 580 } |
| 582 | 581 |
| 583 if (button && model->PartOfGroup(i)) { | 582 if (button && model->PartOfGroup(i)) { |
| 584 if (!group) | 583 if (!group) |
| 585 group = gtk_size_group_new(GTK_SIZE_GROUP_HORIZONTAL); | 584 group = gtk_size_group_new(GTK_SIZE_GROUP_HORIZONTAL); |
| 586 | 585 |
| (...skipping 221 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 808 | 807 |
| 809 // static | 808 // static |
| 810 void MenuGtk::SetButtonItemInfo(GtkWidget* button, gpointer userdata) { | 809 void MenuGtk::SetButtonItemInfo(GtkWidget* button, gpointer userdata) { |
| 811 ui::ButtonMenuItemModel* model = | 810 ui::ButtonMenuItemModel* model = |
| 812 reinterpret_cast<ui::ButtonMenuItemModel*>( | 811 reinterpret_cast<ui::ButtonMenuItemModel*>( |
| 813 g_object_get_data(G_OBJECT(button), "button-model")); | 812 g_object_get_data(G_OBJECT(button), "button-model")); |
| 814 int index = GPOINTER_TO_INT(g_object_get_data( | 813 int index = GPOINTER_TO_INT(g_object_get_data( |
| 815 G_OBJECT(button), "button-model-id")); | 814 G_OBJECT(button), "button-model-id")); |
| 816 | 815 |
| 817 if (model->IsItemDynamicAt(index)) { | 816 if (model->IsItemDynamicAt(index)) { |
| 818 std::string label = | 817 std::string label = ui::ConvertAcceleratorsFromWindowsStyle( |
| 819 gfx::ConvertAcceleratorsFromWindowsStyle( | 818 UTF16ToUTF8(model->GetLabelAt(index))); |
| 820 UTF16ToUTF8(model->GetLabelAt(index))); | |
| 821 gtk_button_set_label(GTK_BUTTON(button), label.c_str()); | 819 gtk_button_set_label(GTK_BUTTON(button), label.c_str()); |
| 822 } | 820 } |
| 823 | 821 |
| 824 gtk_widget_set_sensitive(GTK_WIDGET(button), model->IsEnabledAt(index)); | 822 gtk_widget_set_sensitive(GTK_WIDGET(button), model->IsEnabledAt(index)); |
| 825 } | 823 } |
| 826 | 824 |
| 827 // static | 825 // static |
| 828 void MenuGtk::SetMenuItemInfo(GtkWidget* widget, gpointer userdata) { | 826 void MenuGtk::SetMenuItemInfo(GtkWidget* widget, gpointer userdata) { |
| 829 if (GTK_IS_SEPARATOR_MENU_ITEM(widget)) { | 827 if (GTK_IS_SEPARATOR_MENU_ITEM(widget)) { |
| 830 // We need to explicitly handle this case because otherwise we'll ask the | 828 // We need to explicitly handle this case because otherwise we'll ask the |
| (...skipping 36 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 867 SetButtonItemInfo, | 865 SetButtonItemInfo, |
| 868 userdata); | 866 userdata); |
| 869 } | 867 } |
| 870 | 868 |
| 871 if (GTK_IS_MENU_ITEM(widget)) { | 869 if (GTK_IS_MENU_ITEM(widget)) { |
| 872 gtk_widget_set_sensitive(widget, model->IsEnabledAt(id)); | 870 gtk_widget_set_sensitive(widget, model->IsEnabledAt(id)); |
| 873 | 871 |
| 874 if (model->IsVisibleAt(id)) { | 872 if (model->IsVisibleAt(id)) { |
| 875 // Update the menu item label if it is dynamic. | 873 // Update the menu item label if it is dynamic. |
| 876 if (model->IsItemDynamicAt(id)) { | 874 if (model->IsItemDynamicAt(id)) { |
| 877 std::string label = | 875 std::string label = ui::ConvertAcceleratorsFromWindowsStyle( |
| 878 gfx::ConvertAcceleratorsFromWindowsStyle( | 876 UTF16ToUTF8(model->GetLabelAt(id))); |
| 879 UTF16ToUTF8(model->GetLabelAt(id))); | |
| 880 | 877 |
| 881 gtk_menu_item_set_label(GTK_MENU_ITEM(widget), label.c_str()); | 878 gtk_menu_item_set_label(GTK_MENU_ITEM(widget), label.c_str()); |
| 882 if (GTK_IS_IMAGE_MENU_ITEM(widget)) { | 879 if (GTK_IS_IMAGE_MENU_ITEM(widget)) { |
| 883 SkBitmap icon; | 880 SkBitmap icon; |
| 884 if (model->GetIconAt(id, &icon)) { | 881 if (model->GetIconAt(id, &icon)) { |
| 885 GdkPixbuf* pixbuf = gfx::GdkPixbufFromSkBitmap(&icon); | 882 GdkPixbuf* pixbuf = gfx::GdkPixbufFromSkBitmap(&icon); |
| 886 gtk_image_menu_item_set_image(GTK_IMAGE_MENU_ITEM(widget), | 883 gtk_image_menu_item_set_image(GTK_IMAGE_MENU_ITEM(widget), |
| 887 gtk_image_new_from_pixbuf(pixbuf)); | 884 gtk_image_new_from_pixbuf(pixbuf)); |
| 888 g_object_unref(pixbuf); | 885 g_object_unref(pixbuf); |
| 889 } else { | 886 } else { |
| 890 gtk_image_menu_item_set_image(GTK_IMAGE_MENU_ITEM(widget), NULL); | 887 gtk_image_menu_item_set_image(GTK_IMAGE_MENU_ITEM(widget), NULL); |
| 891 } | 888 } |
| 892 } | 889 } |
| 893 } | 890 } |
| 894 | 891 |
| 895 gtk_widget_show(widget); | 892 gtk_widget_show(widget); |
| 896 } else { | 893 } else { |
| 897 gtk_widget_hide(widget); | 894 gtk_widget_hide(widget); |
| 898 } | 895 } |
| 899 | 896 |
| 900 GtkWidget* submenu = gtk_menu_item_get_submenu(GTK_MENU_ITEM(widget)); | 897 GtkWidget* submenu = gtk_menu_item_get_submenu(GTK_MENU_ITEM(widget)); |
| 901 if (submenu) { | 898 if (submenu) { |
| 902 gtk_container_foreach(GTK_CONTAINER(submenu), &SetMenuItemInfo, | 899 gtk_container_foreach(GTK_CONTAINER(submenu), &SetMenuItemInfo, |
| 903 userdata); | 900 userdata); |
| 904 } | 901 } |
| 905 } | 902 } |
| 906 } | 903 } |
| OLD | NEW |