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.
24 #include <gdk/gdkkeysyms.h>
25 #include "gailbutton.h"
26 #include <libgail-util/gailmisc.h>
28 #define GAIL_BUTTON_ATTACHED_MENUS "gtk-attached-menus"
30 static void gail_button_class_init (GailButtonClass *klass);
31 static void gail_button_init (GailButton *button);
33 static const gchar* gail_button_get_name (AtkObject *obj);
34 static gint gail_button_get_n_children (AtkObject *obj);
35 static AtkObject* gail_button_ref_child (AtkObject *obj,
37 static AtkStateSet* gail_button_ref_state_set (AtkObject *obj);
38 static void gail_button_notify_label_gtk (GObject *obj,
41 static void gail_button_label_map_gtk (GtkWidget *widget,
44 static void gail_button_real_initialize (AtkObject *obj,
46 static void gail_button_finalize (GObject *object);
47 static void gail_button_init_textutil (GailButton *button,
50 static void gail_button_pressed_enter_handler (GtkWidget *widget);
51 static void gail_button_released_leave_handler (GtkWidget *widget);
52 static gint gail_button_real_add_gtk (GtkContainer *container,
57 static void atk_action_interface_init (AtkActionIface *iface);
58 static gboolean gail_button_do_action (AtkAction *action,
60 static gboolean idle_do_action (gpointer data);
61 static gint gail_button_get_n_actions (AtkAction *action);
62 static const gchar* gail_button_get_description(AtkAction *action,
64 static const gchar* gail_button_get_keybinding (AtkAction *action,
66 static const gchar* gail_button_action_get_name(AtkAction *action,
68 static gboolean gail_button_set_description(AtkAction *action,
71 static void gail_button_notify_label_weak_ref (gpointer data,
73 static void gail_button_notify_weak_ref (gpointer data,
78 static void atk_image_interface_init (AtkImageIface *iface);
79 static const gchar* gail_button_get_image_description
81 static void gail_button_get_image_position
85 AtkCoordType coord_type);
86 static void gail_button_get_image_size (AtkImage *image,
89 static gboolean gail_button_set_image_description
91 const gchar *description);
94 static void atk_text_interface_init (AtkTextIface *iface);
96 static gchar* gail_button_get_text (AtkText *text,
99 static gunichar gail_button_get_character_at_offset(AtkText *text,
101 static gchar* gail_button_get_text_before_offset(AtkText *text,
103 AtkTextBoundary boundary_type,
106 static gchar* gail_button_get_text_at_offset (AtkText *text,
108 AtkTextBoundary boundary_type,
111 static gchar* gail_button_get_text_after_offset(AtkText *text,
113 AtkTextBoundary boundary_type,
116 static gint gail_button_get_character_count (AtkText *text);
117 static void gail_button_get_character_extents (AtkText *text,
123 AtkCoordType coords);
124 static gint gail_button_get_offset_at_point (AtkText *text,
127 AtkCoordType coords);
128 static AtkAttributeSet* gail_button_get_run_attributes
133 static AtkAttributeSet* gail_button_get_default_attributes
135 static GtkImage* get_image_from_button (GtkWidget *button);
136 static GtkWidget* get_label_from_button (GtkWidget *button,
138 gboolean allow_many);
139 static gint get_n_labels_from_button (GtkWidget *button);
140 static void set_role_for_button (AtkObject *accessible,
143 static gint get_n_attached_menus (GtkWidget *widget);
144 static GtkWidget* get_nth_attached_menu (GtkWidget *widget,
147 G_DEFINE_TYPE_WITH_CODE (GailButton, gail_button, GAIL_TYPE_CONTAINER,
148 G_IMPLEMENT_INTERFACE (ATK_TYPE_ACTION, atk_action_interface_init)
149 G_IMPLEMENT_INTERFACE (ATK_TYPE_IMAGE, atk_image_interface_init)
150 G_IMPLEMENT_INTERFACE (ATK_TYPE_TEXT, atk_text_interface_init))
153 gail_button_class_init (GailButtonClass *klass)
155 GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
156 AtkObjectClass *class = ATK_OBJECT_CLASS (klass);
157 GailContainerClass *container_class;
159 container_class = (GailContainerClass*)klass;
161 gobject_class->finalize = gail_button_finalize;
163 class->get_name = gail_button_get_name;
164 class->get_n_children = gail_button_get_n_children;
165 class->ref_child = gail_button_ref_child;
166 class->ref_state_set = gail_button_ref_state_set;
167 class->initialize = gail_button_real_initialize;
169 container_class->add_gtk = gail_button_real_add_gtk;
170 container_class->remove_gtk = NULL;
174 gail_button_init (GailButton *button)
176 button->click_description = NULL;
177 button->press_description = NULL;
178 button->release_description = NULL;
179 button->click_keybinding = NULL;
180 button->action_queue = NULL;
181 button->action_idle_handler = 0;
182 button->textutil = NULL;
186 gail_button_get_name (AtkObject *obj)
188 const gchar* name = NULL;
190 g_return_val_if_fail (GAIL_IS_BUTTON (obj), NULL);
192 name = ATK_OBJECT_CLASS (gail_button_parent_class)->get_name (obj);
196 * Get the text on the label
201 widget = gtk_accessible_get_widget (GTK_ACCESSIBLE (obj));
208 g_return_val_if_fail (GTK_IS_BUTTON (widget), NULL);
210 child = get_label_from_button (widget, 0, FALSE);
211 if (GTK_IS_LABEL (child))
212 name = gtk_label_get_text (GTK_LABEL (child));
217 image = get_image_from_button (widget);
218 if (GTK_IS_IMAGE (image))
222 atk_obj = gtk_widget_get_accessible (GTK_WIDGET (image));
223 name = atk_object_get_name (atk_obj);
231 * A DownArrow in a GtkToggltButton whose parent is not a ColorCombo
232 * has press as default action.
235 gail_button_is_default_press (GtkWidget *widget)
237 GtkArrowType arrow_type;
240 gboolean ret = FALSE;
241 const gchar *parent_type_name;
243 child = gtk_bin_get_child (GTK_BIN (widget));
244 if (GTK_IS_ARROW (child))
247 "arrow_type", &arrow_type,
250 if (arrow_type == GTK_ARROW_DOWN)
252 parent = gtk_widget_get_parent (widget);
255 parent_type_name = g_type_name (G_OBJECT_TYPE (parent));
256 if (g_strcmp0 (parent_type_name, "ColorCombo"))
266 gail_button_real_initialize (AtkObject *obj,
269 GailButton *button = GAIL_BUTTON (obj);
273 ATK_OBJECT_CLASS (gail_button_parent_class)->initialize (obj, data);
275 button->state = GTK_STATE_NORMAL;
277 g_signal_connect (data,
279 G_CALLBACK (gail_button_pressed_enter_handler),
281 g_signal_connect (data,
283 G_CALLBACK (gail_button_pressed_enter_handler),
285 g_signal_connect (data,
287 G_CALLBACK (gail_button_released_leave_handler),
289 g_signal_connect (data,
291 G_CALLBACK (gail_button_released_leave_handler),
295 widget = GTK_WIDGET (data);
296 label = get_label_from_button (widget, 0, FALSE);
297 if (GTK_IS_LABEL (label))
299 if (gtk_widget_get_mapped (label))
300 gail_button_init_textutil (button, label);
302 g_signal_connect (label,
304 G_CALLBACK (gail_button_label_map_gtk),
307 button->default_is_press = gail_button_is_default_press (widget);
309 set_role_for_button (obj, data);
313 gail_button_label_map_gtk (GtkWidget *widget,
318 button = GAIL_BUTTON (data);
319 gail_button_init_textutil (button, widget);
323 gail_button_notify_label_gtk (GObject *obj,
327 AtkObject* atk_obj = ATK_OBJECT (data);
329 GailButton *gail_button;
331 if (strcmp (pspec->name, "label") == 0)
333 const gchar* label_text;
335 label = GTK_LABEL (obj);
337 label_text = gtk_label_get_text (label);
339 gail_button = GAIL_BUTTON (atk_obj);
340 gail_text_util_text_setup (gail_button->textutil, label_text);
342 if (atk_obj->name == NULL)
345 * The label has changed so notify a change in accessible-name
347 g_object_notify (G_OBJECT (atk_obj), "accessible-name");
350 * The label is the only property which can be changed
352 g_signal_emit_by_name (atk_obj, "visible_data_changed");
357 gail_button_notify_weak_ref (gpointer data, GObject* obj)
359 GtkLabel *label = NULL;
361 AtkObject* atk_obj = ATK_OBJECT (obj);
362 if (data && GTK_IS_WIDGET (data))
364 label = GTK_LABEL (data);
367 g_signal_handlers_disconnect_by_func (label,
368 (GCallback) gail_button_notify_label_gtk,
369 GAIL_BUTTON (atk_obj));
370 g_object_weak_unref (G_OBJECT (label),
371 gail_button_notify_label_weak_ref,
372 GAIL_BUTTON (atk_obj));
378 gail_button_notify_label_weak_ref (gpointer data, GObject* obj)
380 GtkLabel *label = NULL;
381 GailButton *button = NULL;
383 label = GTK_LABEL (obj);
384 if (data && GAIL_IS_BUTTON (data))
386 button = GAIL_BUTTON (ATK_OBJECT (data));
388 g_object_weak_unref (G_OBJECT (button), gail_button_notify_weak_ref,
395 gail_button_init_textutil (GailButton *button,
398 const gchar *label_text;
400 if (button->textutil)
401 g_object_unref (button->textutil);
402 button->textutil = gail_text_util_new ();
403 label_text = gtk_label_get_text (GTK_LABEL (label));
404 gail_text_util_text_setup (button->textutil, label_text);
405 g_object_weak_ref (G_OBJECT (button),
406 gail_button_notify_weak_ref, label);
407 g_object_weak_ref (G_OBJECT (label),
408 gail_button_notify_label_weak_ref, button);
409 g_signal_connect (label,
411 (GCallback) gail_button_notify_label_gtk,
416 gail_button_real_add_gtk (GtkContainer *container,
423 if (GTK_IS_LABEL (widget))
425 const gchar* label_text;
427 label = GTK_LABEL (widget);
430 button = GAIL_BUTTON (data);
431 if (!button->textutil)
432 gail_button_init_textutil (button, widget);
435 label_text = gtk_label_get_text (label);
436 gail_text_util_text_setup (button->textutil, label_text);
444 atk_action_interface_init (AtkActionIface *iface)
446 iface->do_action = gail_button_do_action;
447 iface->get_n_actions = gail_button_get_n_actions;
448 iface->get_description = gail_button_get_description;
449 iface->get_keybinding = gail_button_get_keybinding;
450 iface->get_name = gail_button_action_get_name;
451 iface->set_description = gail_button_set_description;
455 gail_button_do_action (AtkAction *action,
460 gboolean return_value = TRUE;
462 widget = gtk_accessible_get_widget (GTK_ACCESSIBLE (action));
469 if (!gtk_widget_is_sensitive (widget) || !gtk_widget_get_visible (widget))
472 button = GAIL_BUTTON (action);
479 if (!button->action_queue)
481 button->action_queue = g_queue_new ();
483 g_queue_push_head (button->action_queue, GINT_TO_POINTER(i));
484 if (!button->action_idle_handler)
485 button->action_idle_handler = gdk_threads_add_idle (idle_do_action, button);
488 return_value = FALSE;
495 idle_do_action (gpointer data)
499 GailButton *gail_button;
503 gail_button = GAIL_BUTTON (data);
504 gail_button->action_idle_handler = 0;
505 widget = gtk_accessible_get_widget (GTK_ACCESSIBLE (gail_button));
506 window = gtk_widget_get_window (widget);
508 tmp_event.button.type = GDK_BUTTON_RELEASE;
509 tmp_event.button.window = window;
510 tmp_event.button.button = 1;
511 tmp_event.button.send_event = TRUE;
512 tmp_event.button.time = GDK_CURRENT_TIME;
513 tmp_event.button.axes = NULL;
515 g_object_ref (gail_button);
517 if (widget == NULL /* State is defunct */ ||
518 !gtk_widget_is_sensitive (widget) || !gtk_widget_get_visible (widget))
520 g_object_unref (gail_button);
524 gtk_widget_event (widget, &tmp_event);
526 button = GTK_BUTTON (widget);
527 while (!g_queue_is_empty (gail_button->action_queue))
529 gint action_number = GPOINTER_TO_INT(g_queue_pop_head (gail_button->action_queue));
530 if (gail_button->default_is_press)
532 if (action_number == 0)
534 else if (action_number == 1)
537 switch (action_number)
542 /* FIXME: Do not access public member
543 button->in_button = TRUE;
545 g_signal_emit_by_name (button, "enter");
547 * Simulate a button press event. calling gtk_button_pressed() does
548 * not get the job done for a GtkOptionMenu.
550 tmp_event.button.type = GDK_BUTTON_PRESS;
551 tmp_event.button.window = window;
552 tmp_event.button.button = 1;
553 tmp_event.button.send_event = TRUE;
554 tmp_event.button.time = GDK_CURRENT_TIME;
555 tmp_event.button.axes = NULL;
557 gtk_widget_event (widget, &tmp_event);
560 tmp_event.button.type = GDK_BUTTON_RELEASE;
561 gtk_widget_event (widget, &tmp_event);
562 /* FIXME: Do not access public member
563 button->in_button = FALSE;
565 g_signal_emit_by_name (button, "leave");
568 /* FIXME: Do not access public member
569 button->in_button = TRUE;
571 g_signal_emit_by_name (button, "enter");
573 * Simulate a button press event. calling gtk_button_pressed() does
574 * not get the job done for a GtkOptionMenu.
576 tmp_event.button.type = GDK_BUTTON_PRESS;
577 tmp_event.button.window = window;
578 tmp_event.button.button = 1;
579 tmp_event.button.send_event = TRUE;
580 tmp_event.button.time = GDK_CURRENT_TIME;
581 tmp_event.button.axes = NULL;
583 gtk_widget_event (widget, &tmp_event);
586 /* FIXME: Do not access public member
587 button->in_button = FALSE;
589 g_signal_emit_by_name (button, "leave");
592 g_assert_not_reached ();
596 g_object_unref (gail_button);
601 gail_button_get_n_actions (AtkAction *action)
607 gail_button_get_description (AtkAction *action,
611 const gchar *return_value;
613 button = GAIL_BUTTON (action);
615 if (button->default_is_press)
625 return_value = button->click_description;
628 return_value = button->press_description;
631 return_value = button->release_description;
641 gail_button_get_keybinding (AtkAction *action,
645 gchar *return_value = NULL;
647 button = GAIL_BUTTON (action);
648 if (button->default_is_press)
660 * We look for a mnemonic on the label
666 widget = gtk_accessible_get_widget (GTK_ACCESSIBLE (button));
673 g_return_val_if_fail (GTK_IS_BUTTON (widget), NULL);
675 label = get_label_from_button (widget, 0, FALSE);
676 if (GTK_IS_LABEL (label))
678 key_val = gtk_label_get_mnemonic_keyval (GTK_LABEL (label));
679 if (key_val != GDK_KEY_VoidSymbol)
680 return_value = gtk_accelerator_name (key_val, GDK_MOD1_MASK);
682 if (return_value == NULL)
684 /* Find labelled-by relation */
686 AtkRelation *relation;
688 gpointer target_object;
690 set = atk_object_ref_relation_set (ATK_OBJECT (action));
693 relation = atk_relation_set_get_relation_by_type (set, ATK_RELATION_LABELLED_BY);
696 target = atk_relation_get_target (relation);
698 target_object = g_ptr_array_index (target, 0);
699 label = gtk_accessible_get_widget (GTK_ACCESSIBLE (target_object));
701 g_object_unref (set);
704 if (GTK_IS_LABEL (label))
706 key_val = gtk_label_get_mnemonic_keyval (GTK_LABEL (label));
707 if (key_val != GDK_KEY_VoidSymbol)
708 return_value = gtk_accelerator_name (key_val, GDK_MOD1_MASK);
711 g_free (button->click_keybinding);
712 button->click_keybinding = return_value;
722 gail_button_action_get_name (AtkAction *action,
725 const gchar *return_value;
728 button = GAIL_BUTTON (action);
730 if (button->default_is_press)
741 * This action is a "click" to activate a button or "toggle" to change
742 * the state of a toggle button check box or radio button.
744 return_value = "click";
748 * This action simulates a button press by simulating moving the
749 * mouse into the button followed by pressing the left mouse button.
751 return_value = "press";
755 * This action simulates releasing the left mouse button outside the
758 * To simulate releasing the left mouse button inside the button use
761 return_value = "release";
771 gail_button_set_description (AtkAction *action,
778 button = GAIL_BUTTON (action);
780 if (button->default_is_press)
790 value = &button->click_description;
793 value = &button->press_description;
796 value = &button->release_description;
805 *value = g_strdup (desc);
813 gail_button_get_n_children (AtkObject* obj)
818 g_return_val_if_fail (GAIL_IS_BUTTON (obj), 0);
820 widget = gtk_accessible_get_widget (GTK_ACCESSIBLE (obj));
828 * Check whether we have an attached menus for PanelMenuButton
830 n_children = get_n_attached_menus (widget);
834 n_children = get_n_labels_from_button (widget);
842 gail_button_ref_child (AtkObject *obj,
846 GtkWidget *child_widget;
849 g_return_val_if_fail (GAIL_IS_BUTTON (obj), NULL);
851 widget = gtk_accessible_get_widget (GTK_ACCESSIBLE (obj));
858 if (i >= gail_button_get_n_children (obj))
861 if (get_n_attached_menus (widget) > 0)
863 child_widget = get_nth_attached_menu (widget, i);
870 if (get_n_labels_from_button (widget) > 1)
872 child_widget = get_label_from_button (widget, i, TRUE);
878 child = gtk_widget_get_accessible (child_widget);
879 g_object_ref (child);
888 gail_button_ref_state_set (AtkObject *obj)
890 AtkStateSet *state_set;
893 state_set = ATK_OBJECT_CLASS (gail_button_parent_class)->ref_state_set (obj);
894 widget = gtk_accessible_get_widget (GTK_ACCESSIBLE (obj));
899 if (gtk_widget_get_state (widget) == GTK_STATE_ACTIVE)
900 atk_state_set_add_state (state_set, ATK_STATE_ARMED);
902 if (!gtk_widget_get_can_focus (widget))
903 atk_state_set_remove_state (state_set, ATK_STATE_SELECTABLE);
910 * This is the signal handler for the "pressed" or "enter" signal handler
913 * If the state is now GTK_STATE_ACTIVE we notify a property change
916 gail_button_pressed_enter_handler (GtkWidget *widget)
918 AtkObject *accessible;
920 if (gtk_widget_get_state (widget) == GTK_STATE_ACTIVE)
922 accessible = gtk_widget_get_accessible (widget);
923 atk_object_notify_state_change (accessible, ATK_STATE_ARMED, TRUE);
924 GAIL_BUTTON (accessible)->state = GTK_STATE_ACTIVE;
929 * This is the signal handler for the "released" or "leave" signal handler
932 * If the state was GTK_STATE_ACTIVE we notify a property change
935 gail_button_released_leave_handler (GtkWidget *widget)
937 AtkObject *accessible;
939 accessible = gtk_widget_get_accessible (widget);
940 if (GAIL_BUTTON (accessible)->state == GTK_STATE_ACTIVE)
942 atk_object_notify_state_change (accessible, ATK_STATE_ARMED, FALSE);
943 GAIL_BUTTON (accessible)->state = GTK_STATE_NORMAL;
948 atk_image_interface_init (AtkImageIface *iface)
950 iface->get_image_description = gail_button_get_image_description;
951 iface->get_image_position = gail_button_get_image_position;
952 iface->get_image_size = gail_button_get_image_size;
953 iface->set_image_description = gail_button_set_image_description;
957 get_image_from_button (GtkWidget *button)
961 GtkImage *image = NULL;
963 child = gtk_bin_get_child (GTK_BIN (button));
964 if (GTK_IS_IMAGE (child))
965 image = GTK_IMAGE (child);
968 if (GTK_IS_ALIGNMENT (child))
969 child = gtk_bin_get_child (GTK_BIN (child));
970 if (GTK_IS_CONTAINER (child))
972 list = gtk_container_get_children (GTK_CONTAINER (child));
975 if (GTK_IS_IMAGE (list->data))
976 image = GTK_IMAGE (list->data);
985 gail_button_get_image_description (AtkImage *image) {
988 GtkImage *button_image;
991 widget = gtk_accessible_get_widget (GTK_ACCESSIBLE (image));
998 button_image = get_image_from_button (widget);
1000 if (button_image != NULL)
1002 obj = gtk_widget_get_accessible (GTK_WIDGET (button_image));
1003 return atk_image_get_image_description (ATK_IMAGE (obj));
1010 gail_button_get_image_position (AtkImage *image,
1013 AtkCoordType coord_type)
1016 GtkImage *button_image;
1019 widget = gtk_accessible_get_widget (GTK_ACCESSIBLE (image));
1031 button_image = get_image_from_button (widget);
1033 if (button_image != NULL)
1035 obj = gtk_widget_get_accessible (GTK_WIDGET (button_image));
1036 atk_component_get_position (ATK_COMPONENT (obj), x, y, coord_type);
1046 gail_button_get_image_size (AtkImage *image,
1051 GtkImage *button_image;
1054 widget = gtk_accessible_get_widget (GTK_ACCESSIBLE (image));
1066 button_image = get_image_from_button (widget);
1068 if (button_image != NULL)
1070 obj = gtk_widget_get_accessible (GTK_WIDGET (button_image));
1071 atk_image_get_image_size (ATK_IMAGE (obj), width, height);
1081 gail_button_set_image_description (AtkImage *image,
1082 const gchar *description)
1085 GtkImage *button_image;
1088 widget = gtk_accessible_get_widget (GTK_ACCESSIBLE (image));
1096 button_image = get_image_from_button (widget);
1098 if (button_image != NULL)
1100 obj = gtk_widget_get_accessible (GTK_WIDGET (button_image));
1101 return atk_image_set_image_description (ATK_IMAGE (obj), description);
1110 atk_text_interface_init (AtkTextIface *iface)
1112 iface->get_text = gail_button_get_text;
1113 iface->get_character_at_offset = gail_button_get_character_at_offset;
1114 iface->get_text_before_offset = gail_button_get_text_before_offset;
1115 iface->get_text_at_offset = gail_button_get_text_at_offset;
1116 iface->get_text_after_offset = gail_button_get_text_after_offset;
1117 iface->get_character_count = gail_button_get_character_count;
1118 iface->get_character_extents = gail_button_get_character_extents;
1119 iface->get_offset_at_point = gail_button_get_offset_at_point;
1120 iface->get_run_attributes = gail_button_get_run_attributes;
1121 iface->get_default_attributes = gail_button_get_default_attributes;
1125 gail_button_get_text (AtkText *text,
1132 const gchar *label_text;
1134 widget = gtk_accessible_get_widget (GTK_ACCESSIBLE (text));
1137 /* State is defunct */
1140 label = get_label_from_button (widget, 0, FALSE);
1142 if (!GTK_IS_LABEL (label))
1145 button = GAIL_BUTTON (text);
1146 if (!button->textutil)
1147 gail_button_init_textutil (button, label);
1149 label_text = gtk_label_get_text (GTK_LABEL (label));
1151 if (label_text == NULL)
1155 return gail_text_util_get_substring (button->textutil,
1156 start_pos, end_pos);
1161 gail_button_get_text_before_offset (AtkText *text,
1163 AtkTextBoundary boundary_type,
1171 widget = gtk_accessible_get_widget (GTK_ACCESSIBLE (text));
1174 /* State is defunct */
1178 label = get_label_from_button (widget, 0, FALSE);
1180 if (!GTK_IS_LABEL(label))
1183 button = GAIL_BUTTON (text);
1184 if (!button->textutil)
1185 gail_button_init_textutil (button, label);
1187 return gail_text_util_get_text (button->textutil,
1188 gtk_label_get_layout (GTK_LABEL (label)), GAIL_BEFORE_OFFSET,
1189 boundary_type, offset, start_offset, end_offset);
1193 gail_button_get_text_at_offset (AtkText *text,
1195 AtkTextBoundary boundary_type,
1203 widget = gtk_accessible_get_widget (GTK_ACCESSIBLE (text));
1206 /* State is defunct */
1210 label = get_label_from_button (widget, 0, FALSE);
1212 if (!GTK_IS_LABEL(label))
1215 button = GAIL_BUTTON (text);
1216 if (!button->textutil)
1217 gail_button_init_textutil (button, label);
1219 return gail_text_util_get_text (button->textutil,
1220 gtk_label_get_layout (GTK_LABEL (label)), GAIL_AT_OFFSET,
1221 boundary_type, offset, start_offset, end_offset);
1225 gail_button_get_text_after_offset (AtkText *text,
1227 AtkTextBoundary boundary_type,
1235 widget = gtk_accessible_get_widget (GTK_ACCESSIBLE (text));
1239 /* State is defunct */
1244 label = get_label_from_button (widget, 0, FALSE);
1246 if (!GTK_IS_LABEL(label))
1249 button = GAIL_BUTTON (text);
1250 if (!button->textutil)
1251 gail_button_init_textutil (button, label);
1253 return gail_text_util_get_text (button->textutil,
1254 gtk_label_get_layout (GTK_LABEL (label)), GAIL_AFTER_OFFSET,
1255 boundary_type, offset, start_offset, end_offset);
1259 gail_button_get_character_count (AtkText *text)
1264 widget = gtk_accessible_get_widget (GTK_ACCESSIBLE (text));
1267 /* State is defunct */
1270 label = get_label_from_button (widget, 0, FALSE);
1272 if (!GTK_IS_LABEL(label))
1275 return g_utf8_strlen (gtk_label_get_text (GTK_LABEL (label)), -1);
1279 gail_button_get_character_extents (AtkText *text,
1285 AtkCoordType coords)
1289 PangoRectangle char_rect;
1290 gint index, x_layout, y_layout;
1291 const gchar *label_text;
1293 widget = gtk_accessible_get_widget (GTK_ACCESSIBLE (text));
1296 /* State is defunct */
1299 label = get_label_from_button (widget, 0, FALSE);
1301 if (!GTK_IS_LABEL(label))
1304 gtk_label_get_layout_offsets (GTK_LABEL (label), &x_layout, &y_layout);
1305 label_text = gtk_label_get_text (GTK_LABEL (label));
1306 index = g_utf8_offset_to_pointer (label_text, offset) - label_text;
1307 pango_layout_index_to_pos (gtk_label_get_layout (GTK_LABEL (label)), index, &char_rect);
1309 gail_misc_get_extents_from_pango_rectangle (label, &char_rect,
1310 x_layout, y_layout, x, y, width, height, coords);
1314 gail_button_get_offset_at_point (AtkText *text,
1317 AtkCoordType coords)
1321 gint index, x_layout, y_layout;
1322 const gchar *label_text;
1324 widget = gtk_accessible_get_widget (GTK_ACCESSIBLE (text));
1327 /* State is defunct */
1330 label = get_label_from_button (widget, 0, FALSE);
1332 if (!GTK_IS_LABEL(label))
1335 gtk_label_get_layout_offsets (GTK_LABEL (label), &x_layout, &y_layout);
1337 index = gail_misc_get_index_at_point_in_layout (label,
1338 gtk_label_get_layout (GTK_LABEL (label)),
1339 x_layout, y_layout, x, y, coords);
1340 label_text = gtk_label_get_text (GTK_LABEL (label));
1343 if (coords == ATK_XY_WINDOW || coords == ATK_XY_SCREEN)
1344 return g_utf8_strlen (label_text, -1);
1349 return g_utf8_pointer_to_offset (label_text, label_text + index);
1352 static AtkAttributeSet*
1353 gail_button_get_run_attributes (AtkText *text,
1360 AtkAttributeSet *at_set = NULL;
1361 GtkJustification justify;
1362 GtkTextDirection dir;
1364 widget = gtk_accessible_get_widget (GTK_ACCESSIBLE (text));
1367 /* State is defunct */
1370 label = get_label_from_button (widget, 0, FALSE);
1372 if (!GTK_IS_LABEL(label))
1375 /* Get values set for entire label, if any */
1376 justify = gtk_label_get_justify (GTK_LABEL (label));
1377 if (justify != GTK_JUSTIFY_CENTER)
1379 at_set = gail_misc_add_attribute (at_set,
1380 ATK_TEXT_ATTR_JUSTIFICATION,
1381 g_strdup (atk_text_attribute_get_value (ATK_TEXT_ATTR_JUSTIFICATION, justify)));
1383 dir = gtk_widget_get_direction (label);
1384 if (dir == GTK_TEXT_DIR_RTL)
1386 at_set = gail_misc_add_attribute (at_set,
1387 ATK_TEXT_ATTR_DIRECTION,
1388 g_strdup (atk_text_attribute_get_value (ATK_TEXT_ATTR_DIRECTION, dir)));
1391 at_set = gail_misc_layout_get_run_attributes (at_set,
1392 gtk_label_get_layout (GTK_LABEL (label)),
1393 (gchar *) gtk_label_get_text (GTK_LABEL (label)),
1400 static AtkAttributeSet*
1401 gail_button_get_default_attributes (AtkText *text)
1405 AtkAttributeSet *at_set = NULL;
1407 widget = gtk_accessible_get_widget (GTK_ACCESSIBLE (text));
1410 /* State is defunct */
1413 label = get_label_from_button (widget, 0, FALSE);
1415 if (!GTK_IS_LABEL(label))
1418 at_set = gail_misc_get_default_attributes (at_set,
1419 gtk_label_get_layout (GTK_LABEL (label)),
1425 gail_button_get_character_at_offset (AtkText *text,
1430 const gchar *string;
1433 widget = gtk_accessible_get_widget (GTK_ACCESSIBLE (text));
1436 /* State is defunct */
1439 label = get_label_from_button (widget, 0, FALSE);
1441 if (!GTK_IS_LABEL(label))
1443 string = gtk_label_get_text (GTK_LABEL (label));
1444 if (offset >= g_utf8_strlen (string, -1))
1446 index = g_utf8_offset_to_pointer (string, offset);
1448 return g_utf8_get_char (index);
1452 gail_button_finalize (GObject *object)
1454 GailButton *button = GAIL_BUTTON (object);
1456 g_free (button->click_description);
1457 g_free (button->press_description);
1458 g_free (button->release_description);
1459 g_free (button->click_keybinding);
1460 if (button->action_idle_handler)
1462 g_source_remove (button->action_idle_handler);
1463 button->action_idle_handler = 0;
1465 if (button->action_queue)
1467 g_queue_free (button->action_queue);
1469 if (button->textutil)
1471 g_object_unref (button->textutil);
1473 G_OBJECT_CLASS (gail_button_parent_class)->finalize (object);
1477 find_label_child (GtkContainer *container,
1479 gboolean allow_many)
1481 GList *children, *tmp_list;
1484 children = gtk_container_get_children (container);
1487 for (tmp_list = children; tmp_list != NULL; tmp_list = tmp_list->next)
1489 if (GTK_IS_LABEL (tmp_list->data))
1498 child = GTK_WIDGET (tmp_list->data);
1504 child = GTK_WIDGET (tmp_list->data);
1511 * Label for button which are GtkTreeView column headers are in a
1512 * GtkHBox in a GtkAlignment.
1514 else if (GTK_IS_ALIGNMENT (tmp_list->data))
1518 widget = gtk_bin_get_child (GTK_BIN (tmp_list->data));
1519 if (GTK_IS_LABEL (widget))
1541 else if (GTK_IS_CONTAINER (tmp_list->data))
1543 child = find_label_child (GTK_CONTAINER (tmp_list->data), index, allow_many);
1548 g_list_free (children);
1553 get_label_from_button (GtkWidget *button,
1555 gboolean allow_many)
1559 if (index > 0 && !allow_many)
1560 g_warning ("Inconsistent values passed to get_label_from_button");
1562 child = gtk_bin_get_child (GTK_BIN (button));
1563 if (GTK_IS_ALIGNMENT (child))
1564 child = gtk_bin_get_child (GTK_BIN (child));
1566 if (GTK_IS_CONTAINER (child))
1567 child = find_label_child (GTK_CONTAINER (child), &index, allow_many);
1568 else if (!GTK_IS_LABEL (child))
1575 count_labels (GtkContainer *container,
1578 GList *children, *tmp_list;
1580 children = gtk_container_get_children (container);
1582 for (tmp_list = children; tmp_list != NULL; tmp_list = tmp_list->next)
1584 if (GTK_IS_LABEL (tmp_list->data))
1589 * Label for button which are GtkTreeView column headers are in a
1590 * GtkHBox in a GtkAlignment.
1592 else if (GTK_IS_ALIGNMENT (tmp_list->data))
1596 widget = gtk_bin_get_child (GTK_BIN (tmp_list->data));
1597 if (GTK_IS_LABEL (widget))
1600 else if (GTK_IS_CONTAINER (tmp_list->data))
1602 count_labels (GTK_CONTAINER (tmp_list->data), n_labels);
1605 g_list_free (children);
1609 get_n_labels_from_button (GtkWidget *button)
1616 child = gtk_bin_get_child (GTK_BIN (button));
1617 if (GTK_IS_ALIGNMENT (child))
1618 child = gtk_bin_get_child (GTK_BIN (child));
1620 if (GTK_IS_CONTAINER (child))
1621 count_labels (GTK_CONTAINER (child), &n_labels);
1627 set_role_for_button (AtkObject *accessible,
1633 parent = gtk_widget_get_parent (button);
1634 if (GTK_IS_TREE_VIEW (parent))
1636 role = ATK_ROLE_TABLE_COLUMN_HEADER;
1638 * Even though the accessible parent of the column header will
1639 * be reported as the table because the parent widget of the
1640 * GtkTreeViewColumn's button is the GtkTreeView we set
1641 * the accessible parent for column header to be the table
1642 * to ensure that atk_object_get_index_in_parent() returns
1643 * the correct value; see gail_widget_get_index_in_parent().
1645 atk_object_set_parent (accessible, gtk_widget_get_accessible (parent));
1648 role = ATK_ROLE_PUSH_BUTTON;
1650 accessible->role = role;
1654 get_n_attached_menus (GtkWidget *widget)
1661 list_menus = g_object_get_data (G_OBJECT (widget), GAIL_BUTTON_ATTACHED_MENUS);
1662 if (list_menus == NULL)
1665 return g_list_length (list_menus);
1669 get_nth_attached_menu (GtkWidget *widget,
1672 GtkWidget *attached_menu;
1678 list_menus = g_object_get_data (G_OBJECT (widget), GAIL_BUTTON_ATTACHED_MENUS);
1679 if (list_menus == NULL ||
1680 index >= g_list_length (list_menus))
1683 attached_menu = (GtkWidget *) g_list_nth_data (list_menus, index);
1685 return attached_menu;