15821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Copyright (c) 2012 The Chromium Authors. All rights reserved. 25821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Use of this source code is governed by a BSD-style license that can be 35821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// found in the LICENSE file. 45821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 55821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "chrome/browser/ui/gtk/gtk_custom_menu_item.h" 65821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 75821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "base/i18n/rtl.h" 85821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "chrome/browser/ui/gtk/gtk_custom_menu.h" 958537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)#include "ui/gfx/gtk_compat.h" 105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// This method was autogenerated by the program glib-genmarshall, which 125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// generated it from the line "BOOL:INT". Two different attempts at getting gyp 135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// to autogenerate this didn't work. If we need more non-standard marshallers, 145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// this should be deleted, and an actual build step should be added. 155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void chrome_marshall_BOOLEAN__INT(GClosure* closure, 165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) GValue* return_value G_GNUC_UNUSED, 175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) guint n_param_values, 185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) const GValue* param_values, 195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) gpointer invocation_hint G_GNUC_UNUSED, 205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) gpointer marshal_data) { 215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) typedef gboolean(*GMarshalFunc_BOOLEAN__INT)(gpointer data1, 225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) gint arg_1, 235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) gpointer data2); 245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) register GMarshalFunc_BOOLEAN__INT callback; 255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) register GCClosure *cc = (GCClosure*)closure; 265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) register gpointer data1, data2; 275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) gboolean v_return; 285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) g_return_if_fail(return_value != NULL); 305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) g_return_if_fail(n_param_values == 2); 315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (G_CCLOSURE_SWAP_DATA(closure)) { 335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) data1 = closure->data; 345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Note: This line (and the line setting data1 in the other if branch) 355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // were macros in the original autogenerated output. This is with the 365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // macro resolved for release mode. In debug mode, it uses an accessor 375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // that asserts saying that the object pointed to by param_values doesn't 385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // hold a pointer. This appears to be the cause of http://crbug.com/58945. 395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // 405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // This is more than a little odd because the gtype on this first param 415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // isn't set correctly by the time we get here, while I watched it 425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // explicitly set upstack. I verified that v_pointer is still set 435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // correctly. I'm not sure what's going on. :( 445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) data2 = (param_values + 0)->data[0].v_pointer; 455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } else { 465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) data1 = (param_values + 0)->data[0].v_pointer; 475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) data2 = closure->data; 485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) callback = (GMarshalFunc_BOOLEAN__INT)(marshal_data ? marshal_data : 505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) cc->callback); 515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) v_return = callback(data1, 535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) g_value_get_int(param_values + 1), 545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) data2); 555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) g_value_set_boolean(return_value, v_return); 575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)enum { 605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) BUTTON_PUSHED, 615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) TRY_BUTTON_PUSHED, 625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) LAST_SIGNAL 635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}; 645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)static guint custom_menu_item_signals[LAST_SIGNAL] = { 0 }; 665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)G_DEFINE_TYPE(GtkCustomMenuItem, gtk_custom_menu_item, GTK_TYPE_MENU_ITEM) 685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)static void set_selected(GtkCustomMenuItem* item, GtkWidget* selected) { 705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (selected != item->currently_selected_button) { 715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (item->currently_selected_button) { 725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) gtk_widget_set_state(item->currently_selected_button, GTK_STATE_NORMAL); 735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) gtk_widget_set_state( 745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) gtk_bin_get_child(GTK_BIN(item->currently_selected_button)), 755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) GTK_STATE_NORMAL); 765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) item->currently_selected_button = selected; 795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (item->currently_selected_button) { 805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) gtk_widget_set_state(item->currently_selected_button, GTK_STATE_SELECTED); 815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) gtk_widget_set_state( 825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) gtk_bin_get_child(GTK_BIN(item->currently_selected_button)), 835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) GTK_STATE_PRELIGHT); 845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// When GtkButtons set the label text, they rebuild the widget hierarchy each 895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// and every time. Therefore, we can't just fish out the label from the button 905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// and set some properties; we have to create this callback function that 915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// listens on the button's "notify" signal, which is emitted right after the 925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// label has been (re)created. (Label values can change dynamically.) 935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)static void on_button_label_set(GObject* object) { 945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) GtkButton* button = GTK_BUTTON(object); 955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) GtkWidget* child = gtk_bin_get_child(GTK_BIN(button)); 965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) gtk_widget_set_sensitive(child, FALSE); 975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) gtk_misc_set_padding(GTK_MISC(child), 2, 0); 985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)static void gtk_custom_menu_item_finalize(GObject *object); 1015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)static gint gtk_custom_menu_item_expose(GtkWidget* widget, 1025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) GdkEventExpose* event); 1035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)static gboolean gtk_custom_menu_item_hbox_expose(GtkWidget* widget, 1045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) GdkEventExpose* event, 1055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) GtkCustomMenuItem* menu_item); 1065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)static void gtk_custom_menu_item_select(GtkItem *item); 1075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)static void gtk_custom_menu_item_deselect(GtkItem *item); 1085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)static void gtk_custom_menu_item_activate(GtkMenuItem* menu_item); 1095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)static void gtk_custom_menu_item_init(GtkCustomMenuItem* item) { 1115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) item->all_widgets = NULL; 1125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) item->button_widgets = NULL; 1135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) item->currently_selected_button = NULL; 1145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) item->previously_selected_button = NULL; 1155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) GtkWidget* menu_hbox = gtk_hbox_new(FALSE, 0); 1175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) gtk_container_add(GTK_CONTAINER(item), menu_hbox); 1185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) item->label = gtk_label_new(NULL); 1205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) gtk_misc_set_alignment(GTK_MISC(item->label), 0.0, 0.5); 1215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) gtk_box_pack_start(GTK_BOX(menu_hbox), item->label, TRUE, TRUE, 0); 1225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) item->hbox = gtk_hbox_new(FALSE, 0); 1245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) gtk_box_pack_end(GTK_BOX(menu_hbox), item->hbox, FALSE, FALSE, 0); 1255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) g_signal_connect(item->hbox, "expose-event", 1275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) G_CALLBACK(gtk_custom_menu_item_hbox_expose), 1285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) item); 1295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) gtk_widget_show_all(menu_hbox); 1315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 1325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)static void gtk_custom_menu_item_class_init(GtkCustomMenuItemClass* klass) { 1345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) GObjectClass* gobject_class = G_OBJECT_CLASS(klass); 1355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) GtkWidgetClass* widget_class = GTK_WIDGET_CLASS(klass); 1365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) GtkItemClass* item_class = GTK_ITEM_CLASS(klass); 1375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) GtkMenuItemClass* menu_item_class = GTK_MENU_ITEM_CLASS(klass); 1385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) gobject_class->finalize = gtk_custom_menu_item_finalize; 1405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) widget_class->expose_event = gtk_custom_menu_item_expose; 1425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) item_class->select = gtk_custom_menu_item_select; 1445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) item_class->deselect = gtk_custom_menu_item_deselect; 1455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) menu_item_class->activate = gtk_custom_menu_item_activate; 1475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) custom_menu_item_signals[BUTTON_PUSHED] = 1495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) g_signal_new("button-pushed", 1505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) G_TYPE_FROM_CLASS(gobject_class), 1515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) G_SIGNAL_RUN_FIRST, 1525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 0, 1535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) NULL, NULL, 1545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) g_cclosure_marshal_VOID__INT, 1555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) G_TYPE_NONE, 1, G_TYPE_INT); 1565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) custom_menu_item_signals[TRY_BUTTON_PUSHED] = 1575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) g_signal_new("try-button-pushed", 1585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) G_TYPE_FROM_CLASS(gobject_class), 1595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) G_SIGNAL_RUN_LAST, 1605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 0, 1615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) NULL, NULL, 1625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) chrome_marshall_BOOLEAN__INT, 1635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) G_TYPE_BOOLEAN, 1, G_TYPE_INT); 1645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 1655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)static void gtk_custom_menu_item_finalize(GObject *object) { 1675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) GtkCustomMenuItem* item = GTK_CUSTOM_MENU_ITEM(object); 1685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) g_list_free(item->all_widgets); 1695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) g_list_free(item->button_widgets); 1705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) G_OBJECT_CLASS(gtk_custom_menu_item_parent_class)->finalize(object); 1725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 1735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)static gint gtk_custom_menu_item_expose(GtkWidget* widget, 1755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) GdkEventExpose* event) { 1765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (gtk_widget_get_visible(widget) && 1775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) gtk_widget_get_mapped(widget) && 1785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) gtk_bin_get_child(GTK_BIN(widget))) { 1795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // We skip the drawing in the GtkMenuItem class it draws the highlighted 1805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // background and we don't want that. 1815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) gtk_container_propagate_expose(GTK_CONTAINER(widget), 1825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) gtk_bin_get_child(GTK_BIN(widget)), 1835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) event); 1845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 1855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return FALSE; 1875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 1885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)static void gtk_custom_menu_item_expose_button(GtkWidget* hbox, 1905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) GdkEventExpose* event, 1915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) GList* button_item) { 1925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // We search backwards to find the leftmost and rightmost buttons. The 1935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // current button may be that button. 1945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) GtkWidget* current_button = GTK_WIDGET(button_item->data); 1955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) GtkWidget* first_button = current_button; 1965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) for (GList* i = button_item; i && GTK_IS_BUTTON(i->data); 1975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) i = g_list_previous(i)) { 1985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) first_button = GTK_WIDGET(i->data); 1995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 2005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 2015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) GtkWidget* last_button = current_button; 2025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) for (GList* i = button_item; i && GTK_IS_BUTTON(i->data); 2035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) i = g_list_next(i)) { 2045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) last_button = GTK_WIDGET(i->data); 2055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 2065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 2075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (base::i18n::IsRTL()) 2085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) std::swap(first_button, last_button); 2095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 2105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) GtkAllocation first_allocation; 2115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) gtk_widget_get_allocation(first_button, &first_allocation); 2125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) GtkAllocation current_allocation; 2135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) gtk_widget_get_allocation(current_button, ¤t_allocation); 2145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) GtkAllocation last_allocation; 2155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) gtk_widget_get_allocation(last_button, &last_allocation); 2165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 2175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) int x = first_allocation.x; 2185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) int y = first_allocation.y; 2195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) int width = last_allocation.width + last_allocation.x - first_allocation.x; 2205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) int height = last_allocation.height; 2215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 2225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) gtk_paint_box(gtk_widget_get_style(hbox), 2235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) gtk_widget_get_window(hbox), 2245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) gtk_widget_get_state(current_button), 2255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) GTK_SHADOW_OUT, 2265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) ¤t_allocation, hbox, "button", 2275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) x, y, width, height); 2285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 2295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Propagate to the button's children. 2305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) gtk_container_propagate_expose( 2315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) GTK_CONTAINER(current_button), 2325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) gtk_bin_get_child(GTK_BIN(current_button)), 2335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) event); 2345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 2355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 2365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)static gboolean gtk_custom_menu_item_hbox_expose(GtkWidget* widget, 2375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) GdkEventExpose* event, 2385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) GtkCustomMenuItem* menu_item) { 2395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // First render all the buttons that aren't the currently selected item. 2405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) for (GList* current_item = menu_item->all_widgets; 2415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) current_item != NULL; current_item = g_list_next(current_item)) { 2425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (GTK_IS_BUTTON(current_item->data)) { 2435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (GTK_WIDGET(current_item->data) != 2445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) menu_item->currently_selected_button) { 2455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) gtk_custom_menu_item_expose_button(widget, event, current_item); 2465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 2475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 2485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 2495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 2505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // As a separate pass, draw the buton separators above. We need to draw the 2515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // separators in a separate pass because we are drawing on top of the 2525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // buttons. Otherwise, the vlines are overwritten by the next button. 2535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) for (GList* current_item = menu_item->all_widgets; 2545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) current_item != NULL; current_item = g_list_next(current_item)) { 2555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (GTK_IS_BUTTON(current_item->data)) { 2565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Check to see if this is the last button in a run. 2575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) GList* next_item = g_list_next(current_item); 2585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (next_item && GTK_IS_BUTTON(next_item->data)) { 2595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) GtkWidget* current_button = GTK_WIDGET(current_item->data); 2605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) GtkAllocation button_allocation; 2615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) gtk_widget_get_allocation(current_button, &button_allocation); 2625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) GtkAllocation child_alloc; 2635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) gtk_widget_get_allocation(gtk_bin_get_child(GTK_BIN(current_button)), 2645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) &child_alloc); 2655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) GtkStyle* style = gtk_widget_get_style(widget); 2665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) int half_offset = style->xthickness / 2; 2675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) gtk_paint_vline(style, 2685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) gtk_widget_get_window(widget), 2695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) gtk_widget_get_state(current_button), 2705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) &event->area, widget, "button", 2715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) child_alloc.y, 2725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) child_alloc.y + child_alloc.height, 2735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) button_allocation.x + 2745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) button_allocation.width - half_offset); 2755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 2765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 2775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 2785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 2795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Finally, draw the selected item on top of the separators so there are no 2805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // artifacts inside the button area. 2815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) GList* selected = g_list_find(menu_item->all_widgets, 2825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) menu_item->currently_selected_button); 2835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (selected) { 2845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) gtk_custom_menu_item_expose_button(widget, event, selected); 2855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 2865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 2875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return TRUE; 2885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 2895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 2905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)static void gtk_custom_menu_item_select(GtkItem* item) { 2915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) GtkCustomMenuItem* custom_item = GTK_CUSTOM_MENU_ITEM(item); 2925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 2935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // When we are selected, the only thing we do is clear information from 2945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // previous selections. Actual selection of a button is done either in the 2955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // "mouse-motion-event" or is manually set from GtkCustomMenu's overridden 2965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // "move-current" handler. 2975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) custom_item->previously_selected_button = NULL; 2985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 2995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) gtk_widget_queue_draw(GTK_WIDGET(item)); 3005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 3015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 3025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)static void gtk_custom_menu_item_deselect(GtkItem* item) { 3035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) GtkCustomMenuItem* custom_item = GTK_CUSTOM_MENU_ITEM(item); 3045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 3055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // When we are deselected, we store the item that was currently selected so 3065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // that it can be acted on. Menu items are first deselected before they are 3075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // activated. 3085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) custom_item->previously_selected_button = 3095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) custom_item->currently_selected_button; 3105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (custom_item->currently_selected_button) 3115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) set_selected(custom_item, NULL); 3125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 3135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) gtk_widget_queue_draw(GTK_WIDGET(item)); 3145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 3155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 3165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)static void gtk_custom_menu_item_activate(GtkMenuItem* menu_item) { 3175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) GtkCustomMenuItem* custom_item = GTK_CUSTOM_MENU_ITEM(menu_item); 3185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 3195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // We look at |previously_selected_button| because by the time we've been 3205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // activated, we've already gone through our deselect handler. 3215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (custom_item->previously_selected_button) { 3225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) gpointer id_ptr = g_object_get_data( 3235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) G_OBJECT(custom_item->previously_selected_button), "command-id"); 3245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (id_ptr != NULL) { 3255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) int command_id = GPOINTER_TO_INT(id_ptr); 3265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) g_signal_emit(custom_item, custom_menu_item_signals[BUTTON_PUSHED], 0, 3275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) command_id); 3285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) set_selected(custom_item, NULL); 3295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 3305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 3315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 3325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 3335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)GtkWidget* gtk_custom_menu_item_new(const char* title) { 3345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) GtkCustomMenuItem* item = GTK_CUSTOM_MENU_ITEM( 3355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) g_object_new(GTK_TYPE_CUSTOM_MENU_ITEM, NULL)); 3365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) gtk_label_set_text(GTK_LABEL(item->label), title); 3375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return GTK_WIDGET(item); 3385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 3395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 3405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)GtkWidget* gtk_custom_menu_item_add_button(GtkCustomMenuItem* menu_item, 3415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) int command_id) { 3425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) GtkWidget* button = gtk_button_new(); 3435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) g_object_set_data(G_OBJECT(button), "command-id", 3445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) GINT_TO_POINTER(command_id)); 3455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) gtk_box_pack_start(GTK_BOX(menu_item->hbox), button, FALSE, FALSE, 0); 3465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) gtk_widget_show(button); 3475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 3485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) menu_item->all_widgets = g_list_append(menu_item->all_widgets, button); 3495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) menu_item->button_widgets = g_list_append(menu_item->button_widgets, button); 3505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 3515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return button; 3525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 3535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 3545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)GtkWidget* gtk_custom_menu_item_add_button_label(GtkCustomMenuItem* menu_item, 3555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) int command_id) { 3565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) GtkWidget* button = gtk_button_new_with_label(""); 3575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) g_object_set_data(G_OBJECT(button), "command-id", 3585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) GINT_TO_POINTER(command_id)); 3595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) gtk_box_pack_start(GTK_BOX(menu_item->hbox), button, FALSE, FALSE, 0); 3605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) g_signal_connect(button, "notify::label", 3615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) G_CALLBACK(on_button_label_set), NULL); 3625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) gtk_widget_show(button); 3635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 3645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) menu_item->all_widgets = g_list_append(menu_item->all_widgets, button); 3655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 3665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return button; 3675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 3685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 3695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void gtk_custom_menu_item_add_space(GtkCustomMenuItem* menu_item) { 3705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) GtkWidget* fixed = gtk_fixed_new(); 3715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) gtk_widget_set_size_request(fixed, 5, -1); 3725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 3735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) gtk_box_pack_start(GTK_BOX(menu_item->hbox), fixed, FALSE, FALSE, 0); 3745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) gtk_widget_show(fixed); 3755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 3765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) menu_item->all_widgets = g_list_append(menu_item->all_widgets, fixed); 3775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 3785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 3795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void gtk_custom_menu_item_receive_motion_event(GtkCustomMenuItem* menu_item, 3805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) gdouble x, gdouble y) { 3815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) GtkWidget* new_selected_widget = NULL; 3825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) GList* current = menu_item->button_widgets; 3835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) for (; current != NULL; current = current->next) { 3845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) GtkWidget* current_widget = GTK_WIDGET(current->data); 3855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) GtkAllocation alloc; 3865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) gtk_widget_get_allocation(current_widget, &alloc); 3875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) int offset_x, offset_y; 3885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) gtk_widget_translate_coordinates(current_widget, GTK_WIDGET(menu_item), 3895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 0, 0, &offset_x, &offset_y); 3905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (x >= offset_x && x < (offset_x + alloc.width) && 3915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) y >= offset_y && y < (offset_y + alloc.height)) { 3925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) new_selected_widget = current_widget; 3935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) break; 3945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 3955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 3965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 3975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) set_selected(menu_item, new_selected_widget); 3985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 3995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 4005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)gboolean gtk_custom_menu_item_handle_move(GtkCustomMenuItem* menu_item, 4015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) GtkMenuDirectionType direction) { 4025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) GtkWidget* current = menu_item->currently_selected_button; 4035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (menu_item->button_widgets && current) { 4045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) switch (direction) { 4055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) case GTK_MENU_DIR_PREV: { 4065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (g_list_first(menu_item->button_widgets)->data == current) 4075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return FALSE; 4085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 4095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) set_selected(menu_item, GTK_WIDGET(g_list_previous(g_list_find( 4105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) menu_item->button_widgets, current))->data)); 4115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) break; 4125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 4135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) case GTK_MENU_DIR_NEXT: { 4145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (g_list_last(menu_item->button_widgets)->data == current) 4155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return FALSE; 4165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 4175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) set_selected(menu_item, GTK_WIDGET(g_list_next(g_list_find( 4185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) menu_item->button_widgets, current))->data)); 4195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) break; 4205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 4215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) default: 4225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) break; 4235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 4245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 4255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 4265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return TRUE; 4275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 4285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 4295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void gtk_custom_menu_item_select_item_by_direction( 4305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) GtkCustomMenuItem* menu_item, GtkMenuDirectionType direction) { 4315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) menu_item->previously_selected_button = NULL; 4325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 4335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // If we're just told to be selected by the menu system, select the first 4345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // item. 4355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (menu_item->button_widgets) { 4365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) switch (direction) { 4375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) case GTK_MENU_DIR_PREV: { 4385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) GtkWidget* last_button = 4395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) GTK_WIDGET(g_list_last(menu_item->button_widgets)->data); 4405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (last_button) 4415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) set_selected(menu_item, last_button); 4425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) break; 4435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 4445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) case GTK_MENU_DIR_NEXT: { 4455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) GtkWidget* first_button = 4465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) GTK_WIDGET(g_list_first(menu_item->button_widgets)->data); 4475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (first_button) 4485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) set_selected(menu_item, first_button); 4495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) break; 4505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 4515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) default: 4525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) break; 4535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 4545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 4555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 4565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) gtk_widget_queue_draw(GTK_WIDGET(menu_item)); 4575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 4585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 4595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)gboolean gtk_custom_menu_item_is_in_clickable_region( 4605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) GtkCustomMenuItem* menu_item) { 4615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return menu_item->currently_selected_button != NULL; 4625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 4635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 4645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)gboolean gtk_custom_menu_item_try_no_dismiss_command( 4655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) GtkCustomMenuItem* menu_item) { 4665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) GtkCustomMenuItem* custom_item = GTK_CUSTOM_MENU_ITEM(menu_item); 4675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) gboolean activated = TRUE; 4685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 4695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // We work with |currently_selected_button| instead of 4705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // |previously_selected_button| since we haven't been "deselect"ed yet. 4715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) gpointer id_ptr = g_object_get_data( 4725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) G_OBJECT(custom_item->currently_selected_button), "command-id"); 4735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (id_ptr != NULL) { 4745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) int command_id = GPOINTER_TO_INT(id_ptr); 4755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) g_signal_emit(custom_item, custom_menu_item_signals[TRY_BUTTON_PUSHED], 0, 4765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) command_id, &activated); 4775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 4785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 4795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return activated; 4805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 4815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 4825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void gtk_custom_menu_item_foreach_button(GtkCustomMenuItem* menu_item, 4835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) GtkCallback callback, 4845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) gpointer callback_data) { 4855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Even though we're filtering |all_widgets| on GTK_IS_BUTTON(), this isn't 4865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // equivalent to |button_widgets| because we also want the button-labels. 4875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) for (GList* i = menu_item->all_widgets; i && GTK_IS_BUTTON(i->data); 4885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) i = g_list_next(i)) { 4895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (GTK_IS_BUTTON(i->data)) { 4905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) callback(GTK_WIDGET(i->data), callback_data); 4915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 4925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 4935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 494