1 /* GAIL - The GNOME Accessibility Implementation Library
2 * Copyright 2004 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.
21 #include <gdk/gdkkeysyms.h>
22 #include "gailcombobox.h"
24 #if GTK_MINOR_VERSION > 4
25 #define GAIL_COMBOX_BOX_A11y_COMPLETE
28 static void gail_combo_box_class_init (GailComboBoxClass *klass);
29 static void gail_combo_box_object_init (GailComboBox *combo_box);
30 static void gail_combo_box_real_initialize (AtkObject *obj,
33 static void gail_combo_box_changed_gtk (GtkWidget *widget);
35 static G_CONST_RETURN gchar* gail_combo_box_get_name (AtkObject *obj);
36 static gint gail_combo_box_get_n_children (AtkObject *obj);
37 static AtkObject* gail_combo_box_ref_child (AtkObject *obj,
39 static void gail_combo_box_finalize (GObject *object);
40 #ifdef GAIL_COMBOX_BOX_A11y_COMPLETE
41 static void atk_action_interface_init (AtkActionIface *iface);
43 static gboolean gail_combo_box_do_action (AtkAction *action,
45 static gboolean idle_do_action (gpointer data);
46 static gint gail_combo_box_get_n_actions (AtkAction *action)
48 static G_CONST_RETURN gchar* gail_combo_box_get_description(AtkAction *action,
50 static G_CONST_RETURN gchar* gail_combo_box_get_keybinding (AtkAction *action,
52 static G_CONST_RETURN gchar* gail_combo_box_action_get_name(AtkAction *action,
54 static gboolean gail_combo_box_set_description(AtkAction *action,
59 static void atk_selection_interface_init (AtkSelectionIface *iface);
60 static gboolean gail_combo_box_add_selection (AtkSelection *selection,
62 static gboolean gail_combo_box_clear_selection (AtkSelection *selection);
63 static AtkObject* gail_combo_box_ref_selection (AtkSelection *selection,
65 static gint gail_combo_box_get_selection_count (AtkSelection *selection);
66 static gboolean gail_combo_box_is_child_selected (AtkSelection *selection,
68 static gboolean gail_combo_box_remove_selection (AtkSelection *selection,
71 static gpointer parent_class = NULL;
74 gail_combo_box_get_type (void)
76 static GType type = 0;
80 static const GTypeInfo tinfo =
82 sizeof (GailComboBoxClass),
83 (GBaseInitFunc) NULL, /* base init */
84 (GBaseFinalizeFunc) NULL, /* base finalize */
85 (GClassInitFunc) gail_combo_box_class_init, /* class init */
86 (GClassFinalizeFunc) NULL, /* class finalize */
87 NULL, /* class data */
88 sizeof (GailComboBox), /* instance size */
90 (GInstanceInitFunc) gail_combo_box_object_init, /* instance init */
91 NULL /* value table */
94 #ifdef GAIL_COMBOX_BOX_A11y_COMPLETE
95 static const GInterfaceInfo atk_action_info =
97 (GInterfaceInitFunc) atk_action_interface_init,
98 (GInterfaceFinalizeFunc) NULL,
102 static const GInterfaceInfo atk_selection_info =
104 (GInterfaceInitFunc) atk_selection_interface_init,
105 (GInterfaceFinalizeFunc) NULL,
109 type = g_type_register_static (GAIL_TYPE_CONTAINER,
110 "GailComboBox", &tinfo, 0);
112 #ifdef GAIL_COMBOX_BOX_A11y_COMPLETE
113 g_type_add_interface_static (type, ATK_TYPE_ACTION,
116 g_type_add_interface_static (type, ATK_TYPE_SELECTION,
117 &atk_selection_info);
124 gail_combo_box_class_init (GailComboBoxClass *klass)
126 GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
127 AtkObjectClass *class = ATK_OBJECT_CLASS (klass);
129 gobject_class->finalize = gail_combo_box_finalize;
131 parent_class = g_type_class_peek_parent (klass);
133 class->get_name = gail_combo_box_get_name;
134 class->get_n_children = gail_combo_box_get_n_children;
135 class->ref_child = gail_combo_box_ref_child;
136 class->initialize = gail_combo_box_real_initialize;
140 gail_combo_box_object_init (GailComboBox *combo_box)
142 combo_box->press_description = NULL;
143 combo_box->press_keybinding = NULL;
144 combo_box->old_selection = -1;
145 combo_box->name = NULL;
146 combo_box->popup_set = FALSE;
150 gail_combo_box_new (GtkWidget *widget)
153 AtkObject *accessible;
155 g_return_val_if_fail (GTK_IS_COMBO_BOX (widget), NULL);
157 object = g_object_new (GAIL_TYPE_COMBO_BOX, NULL);
159 accessible = ATK_OBJECT (object);
160 atk_object_initialize (accessible, widget);
166 gail_combo_box_real_initialize (AtkObject *obj,
169 GtkComboBox *combo_box;
170 GailComboBox *gail_combo_box;
171 #ifdef GAIL_COMBOX_BOX_A11y_COMPLETE
175 ATK_OBJECT_CLASS (parent_class)->initialize (obj, data);
177 combo_box = GTK_COMBO_BOX (data);
179 gail_combo_box = GAIL_COMBO_BOX (obj);
181 g_signal_connect (combo_box,
183 G_CALLBACK (gail_combo_box_changed_gtk),
185 gail_combo_box->old_selection = gtk_combo_box_get_active (combo_box);
187 #ifdef GAIL_COMBOX_BOX_A11y_COMPLETE
188 popup = gtk_combo_box_get_popup_accessible (combo_box);
191 atk_object_set_parent (popup, obj);
192 gail_combo_box->popup_set = TRUE;
194 if (GTK_IS_COMBO_BOX_ENTRY (combo_box))
195 atk_object_set_parent (gtk_widget_get_accessible (gtk_bin_get_child (GTK_BIN (combo_box))), obj);
198 obj->role = ATK_ROLE_COMBO_BOX;
202 gail_combo_box_changed_gtk (GtkWidget *widget)
204 GtkComboBox *combo_box;
206 GailComboBox *gail_combo_box;
209 combo_box = GTK_COMBO_BOX (widget);
211 index = gtk_combo_box_get_active (combo_box);
212 obj = gtk_widget_get_accessible (widget);
213 gail_combo_box = GAIL_COMBO_BOX (obj);
214 if (gail_combo_box->old_selection != index)
216 gail_combo_box->old_selection = index;
217 g_signal_emit_by_name (obj, "selection_changed");
221 static G_CONST_RETURN gchar*
222 gail_combo_box_get_name (AtkObject *obj)
225 GtkComboBox *combo_box;
226 GailComboBox *gail_combo_box;
228 G_CONST_RETURN gchar *name;
233 g_return_val_if_fail (GAIL_IS_COMBO_BOX (obj), NULL);
235 name = ATK_OBJECT_CLASS (parent_class)->get_name (obj);
239 widget = GTK_ACCESSIBLE (obj)->widget;
246 combo_box = GTK_COMBO_BOX (widget);
247 gail_combo_box = GAIL_COMBO_BOX (obj);
248 if (gtk_combo_box_get_active_iter (combo_box, &iter))
250 model = gtk_combo_box_get_model (combo_box);
251 n_columns = gtk_tree_model_get_n_columns (model);
252 for (i = 0; i < n_columns; i++)
254 GValue value = { 0, };
256 gtk_tree_model_get_value (model, &iter, i, &value);
257 if (G_VALUE_HOLDS_STRING (&value))
259 if (gail_combo_box->name) g_free (gail_combo_box->name);
260 gail_combo_box->name = g_strdup ((gchar *)
261 g_value_get_string (&value));
262 g_value_unset (&value);
266 g_value_unset (&value);
269 return gail_combo_box->name;
273 * The children of a GailComboBox are the list of items and the entry field
277 gail_combo_box_get_n_children (AtkObject* obj)
282 g_return_val_if_fail (GAIL_IS_COMBO_BOX (obj), 0);
284 widget = GTK_ACCESSIBLE (obj)->widget;
291 #ifdef GAIL_COMBOX_BOX_A11y_COMPLETE
293 if (GTK_IS_COMBO_BOX_ENTRY (widget))
301 gail_combo_box_ref_child (AtkObject *obj,
305 #ifdef GAIL_COMBOX_BOX_A11y_COMPLETE
310 g_return_val_if_fail (GAIL_IS_COMBO_BOX (obj), NULL);
312 widget = GTK_ACCESSIBLE (obj)->widget;
320 #ifdef GAIL_COMBOX_BOX_A11y_COMPLETE
323 child = gtk_combo_box_get_popup_accessible (GTK_COMBO_BOX (widget));
324 box = GAIL_COMBO_BOX (obj);
325 if (box->popup_set == FALSE)
327 atk_object_set_parent (child, obj);
328 box->popup_set = TRUE;
331 else if (i == 1 && GTK_IS_COMBO_BOX_ENTRY (widget))
333 child = gtk_widget_get_accessible (gtk_bin_get_child (GTK_BIN (widget)));
339 return g_object_ref (child);
345 #ifdef GAIL_COMBOX_BOX_A11y_COMPLETE
347 atk_action_interface_init (AtkActionIface *iface)
349 g_return_if_fail (iface != NULL);
351 iface->do_action = gail_combo_box_do_action;
352 iface->get_n_actions = gail_combo_box_get_n_actions;
353 iface->get_description = gail_combo_box_get_description;
354 iface->get_keybinding = gail_combo_box_get_keybinding;
355 iface->get_name = gail_combo_box_action_get_name;
356 iface->set_description = gail_combo_box_set_description;
360 gail_combo_box_do_action (AtkAction *action,
363 GailComboBox *combo_box;
366 widget = GTK_ACCESSIBLE (action)->widget;
373 if (!GTK_WIDGET_SENSITIVE (widget) || !GTK_WIDGET_VISIBLE (widget))
376 combo_box = GAIL_COMBO_BOX (action);
379 if (combo_box->action_idle_handler)
382 combo_box->action_idle_handler = gdk_threads_add_idle (idle_do_action, combo_box);
390 idle_do_action (gpointer data)
392 GtkComboBox *combo_box;
394 GailComboBox *gail_combo_box;
398 gail_combo_box = GAIL_COMBO_BOX (data);
399 gail_combo_box->action_idle_handler = 0;
400 widget = GTK_ACCESSIBLE (gail_combo_box)->widget;
401 if (widget == NULL || /* State is defunct */
402 !GTK_WIDGET_SENSITIVE (widget) || !GTK_WIDGET_VISIBLE (widget))
405 combo_box = GTK_COMBO_BOX (widget);
407 popup = gtk_combo_box_get_popup_accessible (combo_box);
408 do_popup = !GTK_WIDGET_MAPPED (GTK_ACCESSIBLE (popup)->widget);
410 gtk_combo_box_popup (combo_box);
412 gtk_combo_box_popdown (combo_box);
418 gail_combo_box_get_n_actions (AtkAction *action)
421 * The default behavior of a combo_box box is to have one action -
426 static G_CONST_RETURN gchar*
427 gail_combo_box_get_description (AtkAction *action,
432 GailComboBox *combo_box;
434 combo_box = GAIL_COMBO_BOX (action);
435 return combo_box->press_description;
441 static G_CONST_RETURN gchar*
442 gail_combo_box_get_keybinding (AtkAction *action,
445 GailComboBox *combo_box;
446 gchar *return_value = NULL;
447 combo_box = GAIL_COMBO_BOX (action);
455 AtkRelation *relation;
457 gpointer target_object;
460 combo_box = GAIL_COMBO_BOX (action);
461 widget = GTK_ACCESSIBLE (combo_box)->widget;
464 set = atk_object_ref_relation_set (ATK_OBJECT (action));
468 relation = atk_relation_set_get_relation_by_type (set, ATK_RELATION_LABELLED_BY);
471 target = atk_relation_get_target (relation);
472 target_object = g_ptr_array_index (target, 0);
473 if (GTK_IS_ACCESSIBLE (target_object))
475 label = GTK_ACCESSIBLE (target_object)->widget;
478 g_object_unref (set);
479 if (GTK_IS_LABEL (label))
481 key_val = gtk_label_get_mnemonic_keyval (GTK_LABEL (label));
482 if (key_val != GDK_VoidSymbol)
483 return_value = gtk_accelerator_name (key_val, GDK_MOD1_MASK);
485 g_free (combo_box->press_keybinding);
486 combo_box->press_keybinding = return_value;
495 static G_CONST_RETURN gchar*
496 gail_combo_box_action_get_name (AtkAction *action,
506 gail_combo_box_set_description (AtkAction *action,
512 GailComboBox *combo_box;
514 combo_box = GAIL_COMBO_BOX (action);
515 g_free (combo_box->press_description);
516 combo_box->press_description = g_strdup (desc);
525 atk_selection_interface_init (AtkSelectionIface *iface)
527 g_return_if_fail (iface != NULL);
529 iface->add_selection = gail_combo_box_add_selection;
530 iface->clear_selection = gail_combo_box_clear_selection;
531 iface->ref_selection = gail_combo_box_ref_selection;
532 iface->get_selection_count = gail_combo_box_get_selection_count;
533 iface->is_child_selected = gail_combo_box_is_child_selected;
534 iface->remove_selection = gail_combo_box_remove_selection;
536 * select_all_selection does not make sense for a combo_box
537 * so no implementation is provided.
542 gail_combo_box_add_selection (AtkSelection *selection,
545 GtkComboBox *combo_box;
548 widget = GTK_ACCESSIBLE (selection)->widget;
555 combo_box = GTK_COMBO_BOX (widget);
557 gtk_combo_box_set_active (combo_box, i);
562 gail_combo_box_clear_selection (AtkSelection *selection)
564 GtkComboBox *combo_box;
567 widget = GTK_ACCESSIBLE (selection)->widget;
574 combo_box = GTK_COMBO_BOX (widget);
576 gtk_combo_box_set_active (combo_box, -1);
581 gail_combo_box_ref_selection (AtkSelection *selection,
584 GtkComboBox *combo_box;
586 #ifdef GAIL_COMBOX_BOX_A11y_COMPLETE
591 widget = GTK_ACCESSIBLE (selection)->widget;
598 combo_box = GTK_COMBO_BOX (widget);
601 * A combo_box box can have only one selection.
606 #ifdef GAIL_COMBOX_BOX_A11y_COMPLETE
607 obj = gtk_combo_box_get_popup_accessible (combo_box);
608 index = gtk_combo_box_get_active (combo_box);
609 return atk_object_ref_accessible_child (obj, index);
616 gail_combo_box_get_selection_count (AtkSelection *selection)
618 GtkComboBox *combo_box;
621 widget = GTK_ACCESSIBLE (selection)->widget;
628 combo_box = GTK_COMBO_BOX (widget);
630 return (gtk_combo_box_get_active (combo_box) == -1) ? 0 : 1;
634 gail_combo_box_is_child_selected (AtkSelection *selection,
637 GtkComboBox *combo_box;
641 widget = GTK_ACCESSIBLE (selection)->widget;
648 combo_box = GTK_COMBO_BOX (widget);
650 j = gtk_combo_box_get_active (combo_box);
656 gail_combo_box_remove_selection (AtkSelection *selection,
659 if (atk_selection_is_child_selected (selection, i))
660 atk_selection_clear_selection (selection);
666 gail_combo_box_finalize (GObject *object)
668 GailComboBox *combo_box = GAIL_COMBO_BOX (object);
670 g_free (combo_box->press_description);
671 g_free (combo_box->press_keybinding);
672 g_free (combo_box->name);
673 if (combo_box->action_idle_handler)
675 g_source_remove (combo_box->action_idle_handler);
676 combo_box->action_idle_handler = 0;
678 G_OBJECT_CLASS (parent_class)->finalize (object);