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,
49 static void atk_action_interface_init (AtkActionIface *iface);
50 static gboolean gail_menu_item_do_action (AtkAction *action,
52 static gboolean idle_do_action (gpointer data);
53 static gint gail_menu_item_get_n_actions (AtkAction *action);
54 static G_CONST_RETURN gchar* gail_menu_item_get_description(AtkAction *action,
56 static G_CONST_RETURN gchar* gail_menu_item_get_name (AtkAction *action,
58 static G_CONST_RETURN gchar* gail_menu_item_get_keybinding (AtkAction *action,
60 static gboolean gail_menu_item_set_description(AtkAction *action,
63 static void menu_item_select (GtkMenuItem *item);
64 static void menu_item_deselect (GtkMenuItem *item);
65 static void menu_item_selection (GtkMenuItem *item,
67 static gboolean find_accel (GtkAccelKey *key,
70 static gboolean find_accel_new (GtkAccelKey *key,
74 static void atk_text_interface_init (AtkTextIface *iface);
76 static gchar* gail_menu_item_get_text (AtkText *text,
79 static gunichar gail_menu_item_get_character_at_offset (AtkText *text,
81 static gchar* gail_menu_item_get_text_before_offset (AtkText *text,
83 AtkTextBoundary boundary_type,
86 static gchar* gail_menu_item_get_text_at_offset (AtkText *text,
88 AtkTextBoundary boundary_type,
91 static gchar* gail_menu_item_get_text_after_offset (AtkText *text,
93 AtkTextBoundary boundary_type,
96 static gint gail_menu_item_get_character_count (AtkText *text);
97 static void gail_menu_item_get_character_extents (AtkText *text,
103 AtkCoordType coords);
104 static gint gail_menu_item_get_offset_at_point (AtkText *text,
107 AtkCoordType coords);
108 static AtkAttributeSet* gail_menu_item_get_run_attributes (AtkText *text,
112 static AtkAttributeSet* gail_menu_item_get_default_attributes (AtkText *text);
113 static GtkWidget* get_label_from_container (GtkWidget *container);
116 G_DEFINE_TYPE_WITH_CODE (GailMenuItem, gail_menu_item, GAIL_TYPE_CONTAINER,
117 G_IMPLEMENT_INTERFACE (ATK_TYPE_ACTION, atk_action_interface_init)
118 G_IMPLEMENT_INTERFACE (ATK_TYPE_TEXT, atk_text_interface_init))
121 gail_menu_item_class_init (GailMenuItemClass *klass)
123 GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
124 AtkObjectClass *class = ATK_OBJECT_CLASS (klass);
126 gobject_class->finalize = gail_menu_item_finalize;
128 class->get_n_children = gail_menu_item_get_n_children;
129 class->ref_child = gail_menu_item_ref_child;
130 class->ref_state_set = gail_menu_item_ref_state_set;
131 class->initialize = gail_menu_item_real_initialize;
135 gail_menu_item_real_initialize (AtkObject *obj,
140 GailMenuItem *item = GAIL_MENU_ITEM (obj);
143 ATK_OBJECT_CLASS (gail_menu_item_parent_class)->initialize (obj, data);
145 item->textutil = NULL;
148 label = get_label_from_container (GTK_WIDGET (data));
149 if (GTK_IS_LABEL (label))
151 if (gtk_widget_get_mapped (label))
152 gail_menu_item_init_textutil (item, label);
154 g_signal_connect (label,
156 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 = gtk_label_get_text (GTK_LABEL (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 if (!GTK_IS_LABEL (label))
300 item = GAIL_MENU_ITEM (text);
302 gail_menu_item_init_textutil (item, label);
304 label_text = gtk_label_get_text (GTK_LABEL (label));
306 if (label_text == NULL)
310 return gail_text_util_get_substring (item->textutil,
316 gail_menu_item_get_text_before_offset (AtkText *text,
318 AtkTextBoundary boundary_type,
326 widget = gtk_accessible_get_widget (GTK_ACCESSIBLE (text));
329 /* State is defunct */
333 label = get_label_from_container (widget);
335 if (!GTK_IS_LABEL(label))
338 item = GAIL_MENU_ITEM (text);
340 gail_menu_item_init_textutil (item, label);
342 return gail_text_util_get_text (item->textutil,
343 gtk_label_get_layout (GTK_LABEL (label)), GAIL_BEFORE_OFFSET,
344 boundary_type, offset, start_offset, end_offset);
348 gail_menu_item_get_text_at_offset (AtkText *text,
350 AtkTextBoundary boundary_type,
358 widget = gtk_accessible_get_widget (GTK_ACCESSIBLE (text));
361 /* State is defunct */
365 label = get_label_from_container (widget);
367 if (!GTK_IS_LABEL(label))
370 item = GAIL_MENU_ITEM (text);
372 gail_menu_item_init_textutil (item, label);
374 return gail_text_util_get_text (item->textutil,
375 gtk_label_get_layout (GTK_LABEL (label)), GAIL_AT_OFFSET,
376 boundary_type, offset, start_offset, end_offset);
380 gail_menu_item_get_text_after_offset (AtkText *text,
382 AtkTextBoundary boundary_type,
390 widget = gtk_accessible_get_widget (GTK_ACCESSIBLE (text));
394 /* State is defunct */
399 label = get_label_from_container (widget);
401 if (!GTK_IS_LABEL(label))
404 item = GAIL_MENU_ITEM (text);
406 gail_menu_item_init_textutil (item, label);
408 return gail_text_util_get_text (item->textutil,
409 gtk_label_get_layout (GTK_LABEL (label)), GAIL_AFTER_OFFSET,
410 boundary_type, offset, start_offset, end_offset);
414 gail_menu_item_get_character_count (AtkText *text)
419 widget = gtk_accessible_get_widget (GTK_ACCESSIBLE (text));
421 /* State is defunct */
424 label = get_label_from_container (widget);
426 if (!GTK_IS_LABEL(label))
429 return g_utf8_strlen (gtk_label_get_text (GTK_LABEL (label)), -1);
433 gail_menu_item_get_character_extents (AtkText *text,
443 PangoRectangle char_rect;
444 gint index, x_layout, y_layout;
445 const gchar *label_text;
447 widget = gtk_accessible_get_widget (GTK_ACCESSIBLE (text));
450 /* State is defunct */
453 label = get_label_from_container (widget);
455 if (!GTK_IS_LABEL(label))
458 gtk_label_get_layout_offsets (GTK_LABEL (label), &x_layout, &y_layout);
459 label_text = gtk_label_get_text (GTK_LABEL (label));
460 index = g_utf8_offset_to_pointer (label_text, offset) - label_text;
461 pango_layout_index_to_pos (gtk_label_get_layout (GTK_LABEL (label)), index, &char_rect);
463 gail_misc_get_extents_from_pango_rectangle (label, &char_rect,
464 x_layout, y_layout, x, y, width, height, coords);
468 gail_menu_item_get_offset_at_point (AtkText *text,
475 gint index, x_layout, y_layout;
476 const gchar *label_text;
478 widget = gtk_accessible_get_widget (GTK_ACCESSIBLE (text));
480 /* State is defunct */
483 label = get_label_from_container (widget);
485 if (!GTK_IS_LABEL(label))
488 gtk_label_get_layout_offsets (GTK_LABEL (label), &x_layout, &y_layout);
490 index = gail_misc_get_index_at_point_in_layout (label,
491 gtk_label_get_layout (GTK_LABEL (label)),
492 x_layout, y_layout, x, y, coords);
493 label_text = gtk_label_get_text (GTK_LABEL (label));
496 if (coords == ATK_XY_WINDOW || coords == ATK_XY_SCREEN)
497 return g_utf8_strlen (label_text, -1);
502 return g_utf8_pointer_to_offset (label_text, label_text + index);
505 static AtkAttributeSet*
506 gail_menu_item_get_run_attributes (AtkText *text,
513 AtkAttributeSet *at_set = NULL;
514 GtkJustification justify;
515 GtkTextDirection dir;
517 widget = gtk_accessible_get_widget (GTK_ACCESSIBLE (text));
519 /* State is defunct */
522 label = get_label_from_container (widget);
524 if (!GTK_IS_LABEL(label))
527 /* Get values set for entire label, if any */
528 justify = gtk_label_get_justify (GTK_LABEL (label));
529 if (justify != GTK_JUSTIFY_CENTER)
531 at_set = gail_misc_add_attribute (at_set,
532 ATK_TEXT_ATTR_JUSTIFICATION,
533 g_strdup (atk_text_attribute_get_value (ATK_TEXT_ATTR_JUSTIFICATION, justify)));
535 dir = gtk_widget_get_direction (label);
536 if (dir == GTK_TEXT_DIR_RTL)
538 at_set = gail_misc_add_attribute (at_set,
539 ATK_TEXT_ATTR_DIRECTION,
540 g_strdup (atk_text_attribute_get_value (ATK_TEXT_ATTR_DIRECTION, dir)));
543 at_set = gail_misc_layout_get_run_attributes (at_set,
544 gtk_label_get_layout (GTK_LABEL (label)),
545 (gchar *) gtk_label_get_text (GTK_LABEL (label)),
552 static AtkAttributeSet*
553 gail_menu_item_get_default_attributes (AtkText *text)
557 AtkAttributeSet *at_set = NULL;
559 widget = gtk_accessible_get_widget (GTK_ACCESSIBLE (text));
561 /* State is defunct */
564 label = get_label_from_container (widget);
566 if (!GTK_IS_LABEL(label))
569 at_set = gail_misc_get_default_attributes (at_set,
570 gtk_label_get_layout (GTK_LABEL (label)),
576 gail_menu_item_get_character_at_offset (AtkText *text,
584 widget = gtk_accessible_get_widget (GTK_ACCESSIBLE (text));
586 /* State is defunct */
589 label = get_label_from_container (widget);
591 if (!GTK_IS_LABEL(label))
593 string = gtk_label_get_text (GTK_LABEL (label));
594 if (offset >= g_utf8_strlen (string, -1))
596 index = g_utf8_offset_to_pointer (string, offset);
598 return g_utf8_get_char (index);
602 get_label_from_container (GtkWidget *container)
605 GList *children, *tmp_list;
607 if (!GTK_IS_CONTAINER (container))
610 children = gtk_container_get_children (GTK_CONTAINER (container));
613 for (tmp_list = children; tmp_list != NULL; tmp_list = tmp_list->next)
615 if (GTK_IS_LABEL (tmp_list->data))
617 label = tmp_list->data;
621 * * Get label from menu item in desktop background preferences
622 * * option menu. See bug #144084.
624 else if (GTK_IS_BOX (tmp_list->data))
626 label = get_label_from_container (GTK_WIDGET (tmp_list->data));
631 g_list_free (children);
637 gail_menu_item_new (GtkWidget *widget)
640 AtkObject *accessible;
642 g_return_val_if_fail (GTK_IS_MENU_ITEM (widget), NULL);
644 if (gtk_menu_item_get_submenu (GTK_MENU_ITEM (widget)))
645 return gail_sub_menu_item_new (widget);
647 object = g_object_new (GAIL_TYPE_MENU_ITEM, NULL);
649 accessible = ATK_OBJECT (object);
650 atk_object_initialize (accessible, widget);
656 get_children (GtkWidget *submenu)
660 children = gtk_container_get_children (GTK_CONTAINER (submenu));
661 if (g_list_length (children) == 0)
664 * If menu is empty it may be because the menu items are created only
665 * on demand. For example, in gnome-panel the menu items are created
666 * only when "show" signal is emitted on the menu.
668 * The following hack forces the menu items to be created.
670 if (!gtk_widget_get_visible (submenu))
672 /* FIXME GTK_WIDGET_SET_FLAGS (submenu, GTK_VISIBLE); */
673 g_signal_emit_by_name (submenu, "show");
674 /* FIXME GTK_WIDGET_UNSET_FLAGS (submenu, GTK_VISIBLE); */
676 g_list_free (children);
677 children = gtk_container_get_children (GTK_CONTAINER (submenu));
683 * If a menu item has a submenu return the items of the submenu as the
684 * accessible children; otherwise expose no accessible children.
687 gail_menu_item_get_n_children (AtkObject* obj)
693 g_return_val_if_fail (GAIL_IS_MENU_ITEM (obj), count);
695 widget = gtk_accessible_get_widget (GTK_ACCESSIBLE (obj));
699 submenu = gtk_menu_item_get_submenu (GTK_MENU_ITEM (widget));
704 children = get_children (submenu);
705 count = g_list_length (children);
706 g_list_free (children);
712 gail_menu_item_ref_child (AtkObject *obj,
715 AtkObject *accessible;
719 g_return_val_if_fail (GAIL_IS_MENU_ITEM (obj), NULL);
720 g_return_val_if_fail ((i >= 0), NULL);
722 widget = gtk_accessible_get_widget (GTK_ACCESSIBLE (obj));
726 submenu = gtk_menu_item_get_submenu (GTK_MENU_ITEM (widget));
732 children = get_children (submenu);
733 tmp_list = g_list_nth (children, i);
736 g_list_free (children);
739 accessible = gtk_widget_get_accessible (GTK_WIDGET (tmp_list->data));
740 g_list_free (children);
741 g_object_ref (accessible);
750 gail_menu_item_ref_state_set (AtkObject *obj)
752 AtkObject *menu_item;
753 AtkStateSet *state_set, *parent_state_set;
755 state_set = ATK_OBJECT_CLASS (gail_menu_item_parent_class)->ref_state_set (obj);
757 menu_item = atk_object_get_parent (obj);
761 if (!GTK_IS_MENU_ITEM (gtk_accessible_get_widget (GTK_ACCESSIBLE (menu_item))))
764 parent_state_set = atk_object_ref_state_set (menu_item);
765 if (!atk_state_set_contains_state (parent_state_set, ATK_STATE_SELECTED))
767 atk_state_set_remove_state (state_set, ATK_STATE_FOCUSED);
768 atk_state_set_remove_state (state_set, ATK_STATE_SHOWING);
775 atk_action_interface_init (AtkActionIface *iface)
777 iface->do_action = gail_menu_item_do_action;
778 iface->get_n_actions = gail_menu_item_get_n_actions;
779 iface->get_description = gail_menu_item_get_description;
780 iface->get_name = gail_menu_item_get_name;
781 iface->get_keybinding = gail_menu_item_get_keybinding;
782 iface->set_description = gail_menu_item_set_description;
786 gail_menu_item_do_action (AtkAction *action,
792 GailMenuItem *gail_menu_item;
794 item = gtk_accessible_get_widget (GTK_ACCESSIBLE (action));
796 /* State is defunct */
799 if (!gtk_widget_get_sensitive (item) || !gtk_widget_get_visible (item))
802 gail_menu_item = GAIL_MENU_ITEM (action);
803 if (gail_menu_item->action_idle_handler)
807 gail_menu_item->action_idle_handler =
808 gdk_threads_add_idle_full (G_PRIORITY_DEFAULT_IDLE,
810 g_object_ref (gail_menu_item),
811 (GDestroyNotify) g_object_unref);
820 ensure_menus_unposted (GailMenuItem *menu_item)
825 parent = atk_object_get_parent (ATK_OBJECT (menu_item));
828 widget = gtk_accessible_get_widget (GTK_ACCESSIBLE (parent));
829 if (GTK_IS_MENU (widget))
831 if (gtk_widget_get_mapped (widget))
832 gtk_menu_shell_cancel (GTK_MENU_SHELL (widget));
836 parent = atk_object_get_parent (parent);
841 idle_do_action (gpointer data)
844 GtkWidget *item_parent;
845 GailMenuItem *menu_item;
846 gboolean item_mapped;
848 menu_item = GAIL_MENU_ITEM (data);
849 menu_item->action_idle_handler = 0;
850 item = gtk_accessible_get_widget (GTK_ACCESSIBLE (menu_item));
851 if (item == NULL /* State is defunct */ ||
852 !gtk_widget_get_sensitive (item) || !gtk_widget_get_visible (item))
855 item_parent = gtk_widget_get_parent (item);
856 gtk_menu_shell_select_item (GTK_MENU_SHELL (item_parent), item);
857 item_mapped = gtk_widget_get_mapped (item);
859 * This is what is called when <Return> is pressed for a menu item
861 g_signal_emit_by_name (item_parent, "activate_current",
864 ensure_menus_unposted (menu_item);
870 gail_menu_item_get_n_actions (AtkAction *action)
873 * Menu item has 1 action
878 static G_CONST_RETURN gchar*
879 gail_menu_item_get_description (AtkAction *action,
886 item = GAIL_MENU_ITEM (action);
887 return item->click_description;
893 static G_CONST_RETURN gchar*
894 gail_menu_item_get_name (AtkAction *action,
903 static G_CONST_RETURN gchar*
904 gail_menu_item_get_keybinding (AtkAction *action,
908 * This function returns a string of the form A;B;C where
909 * A is the keybinding for the widget; B is the keybinding to traverse
910 * from the menubar and C is the accelerator.
911 * The items in the keybinding to traverse from the menubar are separated
914 GailMenuItem *gail_menu_item;
915 gchar *keybinding = NULL;
916 gchar *item_keybinding = NULL;
917 gchar *full_keybinding = NULL;
918 gchar *accelerator = NULL;
920 gail_menu_item = GAIL_MENU_ITEM (action);
924 GtkWidget *temp_item;
928 item = gtk_accessible_get_widget (GTK_ACCESSIBLE (action));
930 /* State is defunct */
936 GdkModifierType mnemonic_modifier = 0;
938 gchar *key, *temp_keybinding;
940 child = gtk_bin_get_child (GTK_BIN (temp_item));
943 /* Possibly a tear off menu item; it could also be a menu
944 * separator generated by gtk_item_factory_create_items()
948 parent = gtk_widget_get_parent (temp_item);
952 * parent can be NULL when activating a window from the panel
956 g_return_val_if_fail (GTK_IS_MENU_SHELL (parent), NULL);
957 if (GTK_IS_MENU_BAR (parent))
961 toplevel = gtk_widget_get_toplevel (parent);
962 if (toplevel && GTK_IS_WINDOW (toplevel))
963 mnemonic_modifier = gtk_window_get_mnemonic_modifier (
964 GTK_WINDOW (toplevel));
966 if (GTK_IS_LABEL (child))
968 key_val = gtk_label_get_mnemonic_keyval (GTK_LABEL (child));
969 if (key_val != GDK_KEY_VoidSymbol)
971 key = gtk_accelerator_name (key_val, mnemonic_modifier);
973 temp_keybinding = g_strconcat (key, ":", full_keybinding, NULL);
975 temp_keybinding = g_strconcat (key, NULL);
976 if (temp_item == item)
978 item_keybinding = g_strdup (key);
981 g_free (full_keybinding);
982 full_keybinding = temp_keybinding;
987 g_free (full_keybinding);
988 full_keybinding = NULL;
992 if (GTK_IS_MENU_BAR (parent))
993 /* We have reached the menu bar so we are finished */
995 g_return_val_if_fail (GTK_IS_MENU (parent), NULL);
996 temp_item = gtk_menu_get_attach_widget (GTK_MENU (parent));
997 if (!GTK_IS_MENU_ITEM (temp_item))
1000 * Menu is attached to something other than a menu item;
1001 * probably an option menu
1003 g_free (full_keybinding);
1004 full_keybinding = NULL;
1009 parent = gtk_widget_get_parent (item);
1010 if (GTK_IS_MENU (parent))
1012 GtkAccelGroup *group;
1015 group = gtk_menu_get_accel_group (GTK_MENU (parent));
1019 key = gtk_accel_group_find (group, find_accel, item);
1024 * If the menu item is created using GtkAction and GtkUIManager
1028 child = gtk_bin_get_child (GTK_BIN (item));
1029 if (GTK_IS_ACCEL_LABEL (child))
1031 GtkAccelLabel *accel_label;
1032 GClosure *accel_closure;
1034 accel_label = GTK_ACCEL_LABEL (child);
1035 g_object_get (accel_label,
1036 "accel-closure", &accel_closure,
1040 key = gtk_accel_group_find (gtk_accel_group_from_accel_closure (accel_closure),
1050 accelerator = gtk_accelerator_name (key->accel_key,
1056 * Concatenate the bindings
1058 if (item_keybinding || full_keybinding || accelerator)
1061 if (item_keybinding)
1063 keybinding = g_strconcat (item_keybinding, KEYBINDING_SEPARATOR, NULL);
1064 g_free (item_keybinding);
1067 keybinding = g_strconcat (KEYBINDING_SEPARATOR, NULL);
1069 if (full_keybinding)
1071 temp = g_strconcat (keybinding, full_keybinding,
1072 KEYBINDING_SEPARATOR, NULL);
1073 g_free (full_keybinding);
1076 temp = g_strconcat (keybinding, KEYBINDING_SEPARATOR, NULL);
1078 g_free (keybinding);
1082 temp = g_strconcat (keybinding, accelerator, NULL);
1083 g_free (accelerator);
1084 g_free (keybinding);
1088 g_free (gail_menu_item->click_keybinding);
1089 gail_menu_item->click_keybinding = keybinding;
1094 gail_menu_item_set_description (AtkAction *action,
1102 item = GAIL_MENU_ITEM (action);
1103 g_free (item->click_description);
1104 item->click_description = g_strdup (desc);
1112 gail_menu_item_finalize (GObject *object)
1114 GailMenuItem *menu_item = GAIL_MENU_ITEM (object);
1116 g_free (menu_item->click_keybinding);
1117 g_free (menu_item->click_description);
1118 if (menu_item->action_idle_handler)
1120 g_source_remove (menu_item->action_idle_handler);
1121 menu_item->action_idle_handler = 0;
1124 if (menu_item->textutil)
1126 g_object_unref (menu_item->textutil);
1128 if (menu_item->text)
1130 g_free (menu_item->text);
1131 menu_item->text = NULL;
1134 G_OBJECT_CLASS (gail_menu_item_parent_class)->finalize (object);
1138 menu_item_select (GtkMenuItem *item)
1140 menu_item_selection (item, TRUE);
1144 menu_item_deselect (GtkMenuItem *item)
1146 menu_item_selection (item, FALSE);
1150 menu_item_selection (GtkMenuItem *item,
1153 AtkObject *obj, *parent;
1156 obj = gtk_widget_get_accessible (GTK_WIDGET (item));
1157 atk_object_notify_state_change (obj, ATK_STATE_SELECTED, selected);
1159 for (i = 0; i < atk_object_get_n_accessible_children (obj); i++)
1162 child = atk_object_ref_accessible_child (obj, i);
1163 atk_object_notify_state_change (child, ATK_STATE_SHOWING, selected);
1164 g_object_unref (child);
1166 parent = atk_object_get_parent (obj);
1167 g_signal_emit_by_name (parent, "selection_changed");
1171 find_accel (GtkAccelKey *key,
1176 * We assume that closure->data points to the widget
1177 * pending gtk_widget_get_accel_closures being made public
1179 return data == (gpointer) closure->data;
1183 find_accel_new (GtkAccelKey *key,
1187 return data == (gpointer) closure;