1 /* GAIL - The GNOME Accessibility Implementation Library
2 * Copyright 2001, 2002, 2003 Sun Microsystems Inc.
4 * This library is free software; you can redistribute it and/or
5 * modify it under the terms of the GNU Lesser General Public
6 * License as published by the Free Software Foundation; either
7 * version 2 of the License, or (at your option) any later version.
9 * This library is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12 * Lesser General Public License for more details.
14 * You should have received a copy of the GNU Lesser General Public
15 * License along with this library; if not, write to the
16 * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
17 * Boston, MA 02111-1307, USA.
22 #include <gdk/gdkkeysyms.h>
23 #include "gailmenuitem.h"
24 #include "gailsubmenuitem.h"
25 #include <libgail-util/gailmisc.h>
27 #define KEYBINDING_SEPARATOR ";"
29 static void gail_menu_item_class_init (GailMenuItemClass *klass);
30 static void gail_menu_item_init (GailMenuItem *menu_item);
32 static void gail_menu_item_real_initialize
35 static gint gail_menu_item_get_n_children (AtkObject *obj);
36 static AtkObject* gail_menu_item_ref_child (AtkObject *obj,
38 static AtkStateSet* gail_menu_item_ref_state_set (AtkObject *obj);
39 static void gail_menu_item_finalize (GObject *object);
40 static void gail_menu_item_label_map_gtk (GtkWidget *widget,
42 static void gail_menu_item_init_textutil (GailMenuItem *item,
44 static void gail_menu_item_notify_label_gtk (GObject *obj,
47 static const gchar * gail_menu_item_get_name (AtkObject *object);
50 static void atk_action_interface_init (AtkActionIface *iface);
51 static gboolean gail_menu_item_do_action (AtkAction *action,
53 static gboolean idle_do_action (gpointer data);
54 static gint gail_menu_item_get_n_actions (AtkAction *action);
55 static const gchar* gail_menu_item_get_description(AtkAction *action,
57 static const gchar* gail_menu_item_action_get_name (AtkAction *action,
59 static const gchar* gail_menu_item_get_keybinding (AtkAction *action,
61 static gboolean gail_menu_item_set_description(AtkAction *action,
64 static void menu_item_select (GtkMenuItem *item);
65 static void menu_item_deselect (GtkMenuItem *item);
66 static void menu_item_selection (GtkMenuItem *item,
68 static gboolean find_accel (GtkAccelKey *key,
71 static gboolean find_accel_new (GtkAccelKey *key,
75 static void atk_text_interface_init (AtkTextIface *iface);
77 static gchar* gail_menu_item_get_text (AtkText *text,
80 static gunichar gail_menu_item_get_character_at_offset (AtkText *text,
82 static gchar* gail_menu_item_get_text_before_offset (AtkText *text,
84 AtkTextBoundary boundary_type,
87 static gchar* gail_menu_item_get_text_at_offset (AtkText *text,
89 AtkTextBoundary boundary_type,
92 static gchar* gail_menu_item_get_text_after_offset (AtkText *text,
94 AtkTextBoundary boundary_type,
97 static gint gail_menu_item_get_character_count (AtkText *text);
98 static void gail_menu_item_get_character_extents (AtkText *text,
104 AtkCoordType coords);
105 static gint gail_menu_item_get_offset_at_point (AtkText *text,
108 AtkCoordType coords);
109 static AtkAttributeSet* gail_menu_item_get_run_attributes (AtkText *text,
113 static AtkAttributeSet* gail_menu_item_get_default_attributes (AtkText *text);
114 static GtkWidget* get_label_from_container (GtkWidget *container);
115 static gchar * get_text_from_label_widget (GtkWidget *widget);
118 G_DEFINE_TYPE_WITH_CODE (GailMenuItem, gail_menu_item, GAIL_TYPE_CONTAINER,
119 G_IMPLEMENT_INTERFACE (ATK_TYPE_ACTION, atk_action_interface_init)
120 G_IMPLEMENT_INTERFACE (ATK_TYPE_TEXT, atk_text_interface_init))
123 gail_menu_item_class_init (GailMenuItemClass *klass)
125 GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
126 AtkObjectClass *class = ATK_OBJECT_CLASS (klass);
128 gobject_class->finalize = gail_menu_item_finalize;
130 class->get_n_children = gail_menu_item_get_n_children;
131 class->ref_child = gail_menu_item_ref_child;
132 class->ref_state_set = gail_menu_item_ref_state_set;
133 class->initialize = gail_menu_item_real_initialize;
134 class->get_name = gail_menu_item_get_name;
138 gail_menu_item_real_initialize (AtkObject *obj,
143 GailMenuItem *item = GAIL_MENU_ITEM (obj);
146 ATK_OBJECT_CLASS (gail_menu_item_parent_class)->initialize (obj, data);
148 item->textutil = NULL;
151 label = get_label_from_container (GTK_WIDGET (data));
152 if (gtk_widget_get_mapped (label))
153 gail_menu_item_init_textutil (item, label);
155 g_signal_connect (label,
157 G_CALLBACK (gail_menu_item_label_map_gtk),
160 g_signal_connect (data,
162 G_CALLBACK (menu_item_select),
164 g_signal_connect (data,
166 G_CALLBACK (menu_item_deselect),
168 widget = GTK_WIDGET (data);
169 parent = gtk_widget_get_parent (widget);
170 if (GTK_IS_MENU (parent))
172 GtkWidget *parent_widget;
174 parent_widget = gtk_menu_get_attach_widget (GTK_MENU (parent));
176 if (!GTK_IS_MENU_ITEM (parent_widget))
177 parent_widget = gtk_widget_get_parent (widget);
180 atk_object_set_parent (obj, gtk_widget_get_accessible (parent_widget));
183 g_object_set_data (G_OBJECT (obj), "atk-component-layer",
184 GINT_TO_POINTER (ATK_LAYER_POPUP));
186 if (GTK_IS_TEAROFF_MENU_ITEM (data))
187 obj->role = ATK_ROLE_TEAR_OFF_MENU_ITEM;
188 else if (GTK_IS_SEPARATOR_MENU_ITEM (data))
189 obj->role = ATK_ROLE_SEPARATOR;
191 obj->role = ATK_ROLE_MENU_ITEM;
195 gail_menu_item_init (GailMenuItem *menu_item)
197 menu_item->click_keybinding = NULL;
198 menu_item->click_description = NULL;
202 gail_menu_item_label_map_gtk (GtkWidget *widget,
207 item = GAIL_MENU_ITEM (data);
208 gail_menu_item_init_textutil (item, widget);
212 gail_menu_item_notify_label_gtk (GObject *obj,
216 AtkObject* atk_obj = ATK_OBJECT (data);
218 GailMenuItem *menu_item;
220 if (strcmp (pspec->name, "label") == 0)
222 const gchar* label_text;
224 label = GTK_LABEL (obj);
226 label_text = gtk_label_get_text (label);
228 menu_item = GAIL_MENU_ITEM (atk_obj);
229 gail_text_util_text_setup (menu_item->textutil, label_text);
231 if (atk_obj->name == NULL)
234 * The label has changed so notify a change in accessible-name
236 g_object_notify (G_OBJECT (atk_obj), "accessible-name");
239 * The label is the only property which can be changed
241 g_signal_emit_by_name (atk_obj, "visible_data_changed");
246 gail_menu_item_init_textutil (GailMenuItem *item,
249 const gchar *label_text;
251 if (item->textutil == NULL)
253 item->textutil = gail_text_util_new ();
254 g_signal_connect (label,
256 (GCallback) gail_menu_item_notify_label_gtk,
259 label_text = get_text_from_label_widget (label);
260 gail_text_util_text_setup (item->textutil, label_text);
266 atk_text_interface_init (AtkTextIface *iface)
268 iface->get_text = gail_menu_item_get_text;
269 iface->get_character_at_offset = gail_menu_item_get_character_at_offset;
270 iface->get_text_before_offset = gail_menu_item_get_text_before_offset;
271 iface->get_text_at_offset = gail_menu_item_get_text_at_offset;
272 iface->get_text_after_offset = gail_menu_item_get_text_after_offset;
273 iface->get_character_count = gail_menu_item_get_character_count;
274 iface->get_character_extents = gail_menu_item_get_character_extents;
275 iface->get_offset_at_point = gail_menu_item_get_offset_at_point;
276 iface->get_run_attributes = gail_menu_item_get_run_attributes;
277 iface->get_default_attributes = gail_menu_item_get_default_attributes;
281 gail_menu_item_get_text (AtkText *text,
288 const gchar *label_text;
290 widget = gtk_accessible_get_widget (GTK_ACCESSIBLE (text));
292 /* State is defunct */
295 label = get_label_from_container (widget);
297 item = GAIL_MENU_ITEM (text);
299 gail_menu_item_init_textutil (item, label);
301 label_text = get_text_from_label_widget (label);
303 if (label_text == NULL)
306 return gail_text_util_get_substring (item->textutil,
311 gail_menu_item_get_text_before_offset (AtkText *text,
313 AtkTextBoundary boundary_type,
321 widget = gtk_accessible_get_widget (GTK_ACCESSIBLE (text));
324 /* State is defunct */
328 label = get_label_from_container (widget);
330 item = GAIL_MENU_ITEM (text);
332 gail_menu_item_init_textutil (item, label);
334 return gail_text_util_get_text (item->textutil,
335 NULL, GAIL_BEFORE_OFFSET,
336 boundary_type, offset, start_offset, end_offset);
340 gail_menu_item_get_text_at_offset (AtkText *text,
342 AtkTextBoundary boundary_type,
350 widget = gtk_accessible_get_widget (GTK_ACCESSIBLE (text));
353 /* State is defunct */
357 label = get_label_from_container (widget);
359 item = GAIL_MENU_ITEM (text);
361 gail_menu_item_init_textutil (item, label);
363 return gail_text_util_get_text (item->textutil,
364 NULL, GAIL_AT_OFFSET,
365 boundary_type, offset, start_offset, end_offset);
369 gail_menu_item_get_text_after_offset (AtkText *text,
371 AtkTextBoundary boundary_type,
379 widget = gtk_accessible_get_widget (GTK_ACCESSIBLE (text));
383 /* State is defunct */
388 label = get_label_from_container (widget);
390 item = GAIL_MENU_ITEM (text);
392 gail_menu_item_init_textutil (item, label);
394 return gail_text_util_get_text (item->textutil,
395 NULL, GAIL_AFTER_OFFSET,
396 boundary_type, offset, start_offset, end_offset);
400 gail_menu_item_get_character_count (AtkText *atk_text)
405 text = gail_menu_item_get_text (atk_text, 0, -1);
408 len = g_utf8_strlen (text, -1);
418 gail_menu_item_get_character_extents (AtkText *text,
428 PangoRectangle char_rect;
429 gint index, x_layout, y_layout;
430 const gchar *label_text;
432 widget = gtk_accessible_get_widget (GTK_ACCESSIBLE (text));
435 /* State is defunct */
438 label = get_label_from_container (widget);
440 if (!GTK_IS_LABEL(label))
443 gtk_label_get_layout_offsets (GTK_LABEL (label), &x_layout, &y_layout);
444 label_text = gtk_label_get_text (GTK_LABEL (label));
445 index = g_utf8_offset_to_pointer (label_text, offset) - label_text;
446 pango_layout_index_to_pos (gtk_label_get_layout (GTK_LABEL (label)), index, &char_rect);
448 gail_misc_get_extents_from_pango_rectangle (label, &char_rect,
449 x_layout, y_layout, x, y, width, height, coords);
453 gail_menu_item_get_offset_at_point (AtkText *text,
460 gint index, x_layout, y_layout;
461 const gchar *label_text;
463 widget = gtk_accessible_get_widget (GTK_ACCESSIBLE (text));
465 /* State is defunct */
468 label = get_label_from_container (widget);
470 if (!GTK_IS_LABEL(label))
473 gtk_label_get_layout_offsets (GTK_LABEL (label), &x_layout, &y_layout);
475 index = gail_misc_get_index_at_point_in_layout (label,
476 gtk_label_get_layout (GTK_LABEL (label)),
477 x_layout, y_layout, x, y, coords);
478 label_text = gtk_label_get_text (GTK_LABEL (label));
481 if (coords == ATK_XY_WINDOW || coords == ATK_XY_SCREEN)
482 return g_utf8_strlen (label_text, -1);
487 return g_utf8_pointer_to_offset (label_text, label_text + index);
490 static AtkAttributeSet*
491 gail_menu_item_get_run_attributes (AtkText *text,
498 AtkAttributeSet *at_set = NULL;
499 GtkJustification justify;
500 GtkTextDirection dir;
502 widget = gtk_accessible_get_widget (GTK_ACCESSIBLE (text));
504 /* State is defunct */
507 label = get_label_from_container (widget);
509 if (!GTK_IS_LABEL(label))
512 /* Get values set for entire label, if any */
513 justify = gtk_label_get_justify (GTK_LABEL (label));
514 if (justify != GTK_JUSTIFY_CENTER)
516 at_set = gail_misc_add_attribute (at_set,
517 ATK_TEXT_ATTR_JUSTIFICATION,
518 g_strdup (atk_text_attribute_get_value (ATK_TEXT_ATTR_JUSTIFICATION, justify)));
520 dir = gtk_widget_get_direction (label);
521 if (dir == GTK_TEXT_DIR_RTL)
523 at_set = gail_misc_add_attribute (at_set,
524 ATK_TEXT_ATTR_DIRECTION,
525 g_strdup (atk_text_attribute_get_value (ATK_TEXT_ATTR_DIRECTION, dir)));
528 at_set = gail_misc_layout_get_run_attributes (at_set,
529 gtk_label_get_layout (GTK_LABEL (label)),
530 (gchar *) gtk_label_get_text (GTK_LABEL (label)),
537 static AtkAttributeSet*
538 gail_menu_item_get_default_attributes (AtkText *text)
542 AtkAttributeSet *at_set = NULL;
544 widget = gtk_accessible_get_widget (GTK_ACCESSIBLE (text));
546 /* State is defunct */
549 label = get_label_from_container (widget);
551 if (!GTK_IS_LABEL(label))
554 at_set = gail_misc_get_default_attributes (at_set,
555 gtk_label_get_layout (GTK_LABEL (label)),
561 gail_menu_item_get_character_at_offset (AtkText *text,
568 string = gail_menu_item_get_text (text, 0, -1);
570 if (string == NULL || offset >= g_utf8_strlen (string, -1))
574 index = g_utf8_offset_to_pointer (string, offset);
575 ch = g_utf8_get_char (index);
584 get_label_from_container (GtkWidget *container)
587 GList *children, *tmp_list;
589 if (!GTK_IS_CONTAINER (container))
592 children = gtk_container_get_children (GTK_CONTAINER (container));
595 for (tmp_list = children; tmp_list != NULL; tmp_list = tmp_list->next)
597 if (GTK_IS_LABEL (tmp_list->data))
599 label = tmp_list->data;
602 else if (GTK_IS_CELL_VIEW (tmp_list->data))
604 label = tmp_list->data;
608 * * Get label from menu item in desktop background preferences
609 * * option menu. See bug #144084.
611 else if (GTK_IS_BOX (tmp_list->data))
613 label = get_label_from_container (GTK_WIDGET (tmp_list->data));
618 g_list_free (children);
624 get_text_from_label_widget (GtkWidget *label)
626 if (GTK_IS_LABEL (label))
627 return g_strdup (gtk_label_get_text (GTK_LABEL (label)));
628 else if (GTK_IS_CELL_VIEW (label))
637 model = gtk_cell_view_get_model (GTK_CELL_VIEW (label));
638 path = gtk_cell_view_get_displayed_row (GTK_CELL_VIEW (label));
639 gtk_tree_model_get_iter (model, &iter, path);
640 gtk_tree_path_free (path);
642 area = gtk_cell_layout_get_area (GTK_CELL_LAYOUT (label));
644 gtk_cell_area_apply_attributes (area, model, &iter, FALSE, FALSE);
646 cells = gtk_cell_layout_get_cells (GTK_CELL_LAYOUT (label));
647 for (l = cells; l; l = l->next)
649 GtkCellRenderer *cell = l->data;
651 if (GTK_IS_CELL_RENDERER_TEXT (cell))
653 g_object_get (cell, "text", &text, NULL);
667 gail_menu_item_new (GtkWidget *widget)
670 AtkObject *accessible;
672 g_return_val_if_fail (GTK_IS_MENU_ITEM (widget), NULL);
674 if (gtk_menu_item_get_submenu (GTK_MENU_ITEM (widget)))
675 return gail_sub_menu_item_new (widget);
677 object = g_object_new (GAIL_TYPE_MENU_ITEM, NULL);
679 accessible = ATK_OBJECT (object);
680 atk_object_initialize (accessible, widget);
686 get_children (GtkWidget *submenu)
690 children = gtk_container_get_children (GTK_CONTAINER (submenu));
691 if (g_list_length (children) == 0)
694 * If menu is empty it may be because the menu items are created only
695 * on demand. For example, in gnome-panel the menu items are created
696 * only when "show" signal is emitted on the menu.
698 * The following hack forces the menu items to be created.
700 if (!gtk_widget_get_visible (submenu))
702 /* FIXME GTK_WIDGET_SET_FLAGS (submenu, GTK_VISIBLE); */
703 g_signal_emit_by_name (submenu, "show");
704 /* FIXME GTK_WIDGET_UNSET_FLAGS (submenu, GTK_VISIBLE); */
706 g_list_free (children);
707 children = gtk_container_get_children (GTK_CONTAINER (submenu));
713 * If a menu item has a submenu return the items of the submenu as the
714 * accessible children; otherwise expose no accessible children.
717 gail_menu_item_get_n_children (AtkObject* obj)
723 g_return_val_if_fail (GAIL_IS_MENU_ITEM (obj), count);
725 widget = gtk_accessible_get_widget (GTK_ACCESSIBLE (obj));
729 submenu = gtk_menu_item_get_submenu (GTK_MENU_ITEM (widget));
734 children = get_children (submenu);
735 count = g_list_length (children);
736 g_list_free (children);
742 gail_menu_item_ref_child (AtkObject *obj,
745 AtkObject *accessible;
749 g_return_val_if_fail (GAIL_IS_MENU_ITEM (obj), NULL);
750 g_return_val_if_fail ((i >= 0), NULL);
752 widget = gtk_accessible_get_widget (GTK_ACCESSIBLE (obj));
756 submenu = gtk_menu_item_get_submenu (GTK_MENU_ITEM (widget));
762 children = get_children (submenu);
763 tmp_list = g_list_nth (children, i);
766 g_list_free (children);
769 accessible = gtk_widget_get_accessible (GTK_WIDGET (tmp_list->data));
770 g_list_free (children);
771 g_object_ref (accessible);
780 gail_menu_item_ref_state_set (AtkObject *obj)
782 AtkObject *menu_item;
783 AtkStateSet *state_set, *parent_state_set;
785 state_set = ATK_OBJECT_CLASS (gail_menu_item_parent_class)->ref_state_set (obj);
787 menu_item = atk_object_get_parent (obj);
791 if (!GTK_IS_MENU_ITEM (gtk_accessible_get_widget (GTK_ACCESSIBLE (menu_item))))
794 parent_state_set = atk_object_ref_state_set (menu_item);
795 if (!atk_state_set_contains_state (parent_state_set, ATK_STATE_SELECTED))
797 atk_state_set_remove_state (state_set, ATK_STATE_FOCUSED);
798 atk_state_set_remove_state (state_set, ATK_STATE_SHOWING);
805 atk_action_interface_init (AtkActionIface *iface)
807 iface->do_action = gail_menu_item_do_action;
808 iface->get_n_actions = gail_menu_item_get_n_actions;
809 iface->get_description = gail_menu_item_get_description;
810 iface->get_name = gail_menu_item_action_get_name;
811 iface->get_keybinding = gail_menu_item_get_keybinding;
812 iface->set_description = gail_menu_item_set_description;
816 gail_menu_item_do_action (AtkAction *action,
822 GailMenuItem *gail_menu_item;
824 item = gtk_accessible_get_widget (GTK_ACCESSIBLE (action));
826 /* State is defunct */
829 if (!gtk_widget_get_sensitive (item) || !gtk_widget_get_visible (item))
832 gail_menu_item = GAIL_MENU_ITEM (action);
833 if (gail_menu_item->action_idle_handler)
837 gail_menu_item->action_idle_handler =
838 gdk_threads_add_idle_full (G_PRIORITY_DEFAULT_IDLE,
840 g_object_ref (gail_menu_item),
841 (GDestroyNotify) g_object_unref);
850 ensure_menus_unposted (GailMenuItem *menu_item)
855 parent = atk_object_get_parent (ATK_OBJECT (menu_item));
858 widget = gtk_accessible_get_widget (GTK_ACCESSIBLE (parent));
859 if (GTK_IS_MENU (widget))
861 if (gtk_widget_get_mapped (widget))
862 gtk_menu_shell_cancel (GTK_MENU_SHELL (widget));
866 parent = atk_object_get_parent (parent);
871 idle_do_action (gpointer data)
874 GtkWidget *item_parent;
875 GailMenuItem *menu_item;
876 gboolean item_mapped;
878 menu_item = GAIL_MENU_ITEM (data);
879 menu_item->action_idle_handler = 0;
880 item = gtk_accessible_get_widget (GTK_ACCESSIBLE (menu_item));
881 if (item == NULL /* State is defunct */ ||
882 !gtk_widget_get_sensitive (item) || !gtk_widget_get_visible (item))
885 item_parent = gtk_widget_get_parent (item);
886 gtk_menu_shell_select_item (GTK_MENU_SHELL (item_parent), item);
887 item_mapped = gtk_widget_get_mapped (item);
889 * This is what is called when <Return> is pressed for a menu item
891 g_signal_emit_by_name (item_parent, "activate_current",
894 ensure_menus_unposted (menu_item);
900 gail_menu_item_get_n_actions (AtkAction *action)
903 * Menu item has 1 action
909 gail_menu_item_get_description (AtkAction *action,
916 item = GAIL_MENU_ITEM (action);
917 return item->click_description;
924 gail_menu_item_action_get_name (AtkAction *action,
934 gail_menu_item_get_keybinding (AtkAction *action,
938 * This function returns a string of the form A;B;C where
939 * A is the keybinding for the widget; B is the keybinding to traverse
940 * from the menubar and C is the accelerator.
941 * The items in the keybinding to traverse from the menubar are separated
944 GailMenuItem *gail_menu_item;
945 gchar *keybinding = NULL;
946 gchar *item_keybinding = NULL;
947 gchar *full_keybinding = NULL;
948 gchar *accelerator = NULL;
950 gail_menu_item = GAIL_MENU_ITEM (action);
954 GtkWidget *temp_item;
958 item = gtk_accessible_get_widget (GTK_ACCESSIBLE (action));
960 /* State is defunct */
966 GdkModifierType mnemonic_modifier = 0;
968 gchar *key, *temp_keybinding;
970 child = gtk_bin_get_child (GTK_BIN (temp_item));
973 /* Possibly a tear off menu item; it could also be a menu
974 * separator generated by gtk_item_factory_create_items()
978 parent = gtk_widget_get_parent (temp_item);
982 * parent can be NULL when activating a window from the panel
986 g_return_val_if_fail (GTK_IS_MENU_SHELL (parent), NULL);
987 if (GTK_IS_MENU_BAR (parent))
991 toplevel = gtk_widget_get_toplevel (parent);
992 if (toplevel && GTK_IS_WINDOW (toplevel))
993 mnemonic_modifier = gtk_window_get_mnemonic_modifier (
994 GTK_WINDOW (toplevel));
996 if (GTK_IS_LABEL (child))
998 key_val = gtk_label_get_mnemonic_keyval (GTK_LABEL (child));
999 if (key_val != GDK_KEY_VoidSymbol)
1001 key = gtk_accelerator_name (key_val, mnemonic_modifier);
1002 if (full_keybinding)
1003 temp_keybinding = g_strconcat (key, ":", full_keybinding, NULL);
1005 temp_keybinding = g_strconcat (key, NULL);
1006 if (temp_item == item)
1008 item_keybinding = g_strdup (key);
1011 g_free (full_keybinding);
1012 full_keybinding = temp_keybinding;
1017 g_free (full_keybinding);
1018 full_keybinding = NULL;
1022 if (GTK_IS_MENU_BAR (parent))
1023 /* We have reached the menu bar so we are finished */
1025 g_return_val_if_fail (GTK_IS_MENU (parent), NULL);
1026 temp_item = gtk_menu_get_attach_widget (GTK_MENU (parent));
1027 if (!GTK_IS_MENU_ITEM (temp_item))
1030 * Menu is attached to something other than a menu item;
1031 * probably an option menu
1033 g_free (full_keybinding);
1034 full_keybinding = NULL;
1039 parent = gtk_widget_get_parent (item);
1040 if (GTK_IS_MENU (parent))
1042 GtkAccelGroup *group;
1045 group = gtk_menu_get_accel_group (GTK_MENU (parent));
1049 key = gtk_accel_group_find (group, find_accel, item);
1054 * If the menu item is created using GtkAction and GtkUIManager
1058 child = gtk_bin_get_child (GTK_BIN (item));
1059 if (GTK_IS_ACCEL_LABEL (child))
1061 GtkAccelLabel *accel_label;
1062 GClosure *accel_closure;
1064 accel_label = GTK_ACCEL_LABEL (child);
1065 g_object_get (accel_label,
1066 "accel-closure", &accel_closure,
1070 key = gtk_accel_group_find (gtk_accel_group_from_accel_closure (accel_closure),
1080 accelerator = gtk_accelerator_name (key->accel_key,
1086 * Concatenate the bindings
1088 if (item_keybinding || full_keybinding || accelerator)
1091 if (item_keybinding)
1093 keybinding = g_strconcat (item_keybinding, KEYBINDING_SEPARATOR, NULL);
1094 g_free (item_keybinding);
1097 keybinding = g_strconcat (KEYBINDING_SEPARATOR, NULL);
1099 if (full_keybinding)
1101 temp = g_strconcat (keybinding, full_keybinding,
1102 KEYBINDING_SEPARATOR, NULL);
1103 g_free (full_keybinding);
1106 temp = g_strconcat (keybinding, KEYBINDING_SEPARATOR, NULL);
1108 g_free (keybinding);
1112 temp = g_strconcat (keybinding, accelerator, NULL);
1113 g_free (accelerator);
1114 g_free (keybinding);
1118 g_free (gail_menu_item->click_keybinding);
1119 gail_menu_item->click_keybinding = keybinding;
1124 gail_menu_item_set_description (AtkAction *action,
1132 item = GAIL_MENU_ITEM (action);
1133 g_free (item->click_description);
1134 item->click_description = g_strdup (desc);
1142 gail_menu_item_finalize (GObject *object)
1144 GailMenuItem *menu_item = GAIL_MENU_ITEM (object);
1146 g_free (menu_item->click_keybinding);
1147 g_free (menu_item->click_description);
1148 if (menu_item->action_idle_handler)
1150 g_source_remove (menu_item->action_idle_handler);
1151 menu_item->action_idle_handler = 0;
1154 if (menu_item->textutil)
1156 g_object_unref (menu_item->textutil);
1158 if (menu_item->text)
1160 g_free (menu_item->text);
1161 menu_item->text = NULL;
1164 G_OBJECT_CLASS (gail_menu_item_parent_class)->finalize (object);
1167 static const gchar *
1168 gail_menu_item_get_name (AtkObject *obj)
1174 name = ATK_OBJECT_CLASS (gail_menu_item_parent_class)->get_name (obj);
1179 widget = gtk_accessible_get_widget (GTK_ACCESSIBLE (obj));
1183 label = get_label_from_container (widget);
1184 if (GTK_IS_LABEL (label))
1185 return gtk_label_get_text (GTK_LABEL(label));
1191 menu_item_select (GtkMenuItem *item)
1193 menu_item_selection (item, TRUE);
1197 menu_item_deselect (GtkMenuItem *item)
1199 menu_item_selection (item, FALSE);
1203 menu_item_selection (GtkMenuItem *item,
1206 AtkObject *obj, *parent;
1209 obj = gtk_widget_get_accessible (GTK_WIDGET (item));
1210 atk_object_notify_state_change (obj, ATK_STATE_SELECTED, selected);
1212 for (i = 0; i < atk_object_get_n_accessible_children (obj); i++)
1215 child = atk_object_ref_accessible_child (obj, i);
1216 atk_object_notify_state_change (child, ATK_STATE_SHOWING, selected);
1217 g_object_unref (child);
1219 parent = atk_object_get_parent (obj);
1220 g_signal_emit_by_name (parent, "selection_changed");
1224 find_accel (GtkAccelKey *key,
1229 * We assume that closure->data points to the widget
1230 * pending gtk_widget_get_accel_closures being made public
1232 return data == (gpointer) closure->data;
1236 find_accel_new (GtkAccelKey *key,
1240 return data == (gpointer) closure;