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, &current_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)                &current_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