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 #undef GTK_DISABLE_DEPRECATED
25 #include "gailcombo.h"
27 static void gail_combo_class_init (GailComboClass *klass);
28 static void gail_combo_init (GailCombo *combo);
29 static void gail_combo_real_initialize (AtkObject *obj,
32 static void gail_combo_selection_changed_gtk (GtkWidget *widget,
35 static gint gail_combo_get_n_children (AtkObject *obj);
36 static AtkObject* gail_combo_ref_child (AtkObject *obj,
38 static void gail_combo_finalize (GObject *object);
39 static void atk_action_interface_init (AtkActionIface *iface);
41 static gboolean gail_combo_do_action (AtkAction *action,
43 static gboolean idle_do_action (gpointer data);
44 static gint gail_combo_get_n_actions (AtkAction *action)
46 static G_CONST_RETURN gchar* gail_combo_get_description(AtkAction *action,
48 static G_CONST_RETURN gchar* gail_combo_get_name (AtkAction *action,
50 static gboolean gail_combo_set_description(AtkAction *action,
54 static void atk_selection_interface_init (AtkSelectionIface *iface);
55 static gboolean gail_combo_add_selection (AtkSelection *selection,
57 static gboolean gail_combo_clear_selection (AtkSelection *selection);
58 static AtkObject* gail_combo_ref_selection (AtkSelection *selection,
60 static gint gail_combo_get_selection_count (AtkSelection *selection);
61 static gboolean gail_combo_is_child_selected (AtkSelection *selection,
63 static gboolean gail_combo_remove_selection (AtkSelection *selection,
66 static gint _gail_combo_button_release (gpointer data);
67 static gint _gail_combo_popup_release (gpointer data);
70 G_DEFINE_TYPE_WITH_CODE (GailCombo, gail_combo, GAIL_TYPE_CONTAINER,
71 G_IMPLEMENT_INTERFACE (ATK_TYPE_ACTION, atk_action_interface_init)
72 G_IMPLEMENT_INTERFACE (ATK_TYPE_SELECTION, atk_selection_interface_init))
75 gail_combo_class_init (GailComboClass *klass)
77 GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
78 AtkObjectClass *class = ATK_OBJECT_CLASS (klass);
80 gobject_class->finalize = gail_combo_finalize;
82 class->get_n_children = gail_combo_get_n_children;
83 class->ref_child = gail_combo_ref_child;
84 class->initialize = gail_combo_real_initialize;
88 gail_combo_init (GailCombo *combo)
90 combo->press_description = NULL;
91 combo->old_selection = NULL;
92 combo->deselect_idle_handler = 0;
93 combo->select_idle_handler = 0;
97 gail_combo_real_initialize (AtkObject *obj,
103 GailCombo *gail_combo;
105 ATK_OBJECT_CLASS (gail_combo_parent_class)->initialize (obj, data);
107 combo = GTK_COMBO (data);
109 list = GTK_LIST (combo->list);
110 slist = list->selection;
112 gail_combo = GAIL_COMBO (obj);
113 if (slist && slist->data)
115 gail_combo->old_selection = slist->data;
117 g_signal_connect (combo->list,
119 G_CALLBACK (gail_combo_selection_changed_gtk),
121 atk_object_set_parent (gtk_widget_get_accessible (combo->entry), obj);
122 atk_object_set_parent (gtk_widget_get_accessible (combo->popup), obj);
124 obj->role = ATK_ROLE_COMBO_BOX;
128 notify_deselect (gpointer data)
132 combo = GAIL_COMBO (data);
134 combo->old_selection = NULL;
135 combo->deselect_idle_handler = 0;
136 g_signal_emit_by_name (data, "selection_changed");
142 notify_select (gpointer data)
146 combo = GAIL_COMBO (data);
148 combo->select_idle_handler = 0;
149 g_signal_emit_by_name (data, "selection_changed");
155 gail_combo_selection_changed_gtk (GtkWidget *widget,
162 GailCombo *gail_combo;
164 combo = GTK_COMBO (data);
165 list = GTK_LIST (combo->list);
167 slist = list->selection;
169 obj = gtk_widget_get_accessible (GTK_WIDGET (data));
170 gail_combo = GAIL_COMBO (obj);
171 if (slist && slist->data)
173 if (slist->data != gail_combo->old_selection)
175 gail_combo->old_selection = slist->data;
176 if (gail_combo->select_idle_handler == 0)
177 gail_combo->select_idle_handler = gdk_threads_add_idle (notify_select, gail_combo);
179 if (gail_combo->deselect_idle_handler)
181 g_source_remove (gail_combo->deselect_idle_handler);
182 gail_combo->deselect_idle_handler = 0;
187 if (gail_combo->deselect_idle_handler == 0)
188 gail_combo->deselect_idle_handler = gdk_threads_add_idle (notify_deselect, gail_combo);
189 if (gail_combo->select_idle_handler)
191 g_source_remove (gail_combo->select_idle_handler);
192 gail_combo->select_idle_handler = 0;
198 * The children of a GailCombo are the list of items and the entry field
201 gail_combo_get_n_children (AtkObject* obj)
206 g_return_val_if_fail (GAIL_IS_COMBO (obj), 0);
208 widget = GTK_ACCESSIBLE (obj)->widget;
219 gail_combo_ref_child (AtkObject *obj,
222 AtkObject *accessible;
225 g_return_val_if_fail (GAIL_IS_COMBO (obj), NULL);
230 widget = GTK_ACCESSIBLE (obj)->widget;
238 accessible = gtk_widget_get_accessible (GTK_COMBO (widget)->popup);
240 accessible = gtk_widget_get_accessible (GTK_COMBO (widget)->entry);
242 g_object_ref (accessible);
247 atk_action_interface_init (AtkActionIface *iface)
249 iface->do_action = gail_combo_do_action;
250 iface->get_n_actions = gail_combo_get_n_actions;
251 iface->get_description = gail_combo_get_description;
252 iface->get_name = gail_combo_get_name;
253 iface->set_description = gail_combo_set_description;
257 gail_combo_do_action (AtkAction *action,
263 widget = GTK_ACCESSIBLE (action)->widget;
270 if (!gtk_widget_get_sensitive (widget) || !gtk_widget_get_visible (widget))
273 combo = GAIL_COMBO (action);
276 if (combo->action_idle_handler)
279 combo->action_idle_handler = gdk_threads_add_idle (idle_do_action, combo);
287 * This action is the pressing of the button on the combo box.
288 * The behavior is different depending on whether the list is being
289 * displayed or removed.
291 * A button press event is simulated on the appropriate widget and
292 * a button release event is simulated in an idle function.
295 idle_do_action (gpointer data)
298 GtkWidget *action_widget;
300 GailCombo *gail_combo;
304 gail_combo = GAIL_COMBO (data);
305 gail_combo->action_idle_handler = 0;
306 widget = GTK_ACCESSIBLE (gail_combo)->widget;
307 if (widget == NULL /* State is defunct */ ||
308 !gtk_widget_get_sensitive (widget) || !gtk_widget_get_visible (widget))
311 combo = GTK_COMBO (widget);
313 do_popup = !GTK_WIDGET_MAPPED (combo->popwin);
315 tmp_event.button.type = GDK_BUTTON_PRESS;
316 tmp_event.button.window = widget->window;
317 tmp_event.button.button = 1;
318 tmp_event.button.send_event = TRUE;
319 tmp_event.button.time = GDK_CURRENT_TIME;
320 tmp_event.button.axes = NULL;
325 action_widget = combo->button;
327 gtk_widget_event (action_widget, &tmp_event);
330 g_idle_add (_gail_combo_button_release, combo);
335 tmp_event.button.window = combo->list->window;
336 gdk_window_set_user_data (combo->list->window, combo->button);
337 action_widget = combo->popwin;
339 gtk_widget_event (action_widget, &tmp_event);
341 g_idle_add (_gail_combo_popup_release, combo);
348 gail_combo_get_n_actions (AtkAction *action)
351 * The default behavior of a combo box is to have one action -
356 static G_CONST_RETURN gchar*
357 gail_combo_get_description (AtkAction *action,
364 combo = GAIL_COMBO (action);
365 return combo->press_description;
371 static G_CONST_RETURN gchar*
372 gail_combo_get_name (AtkAction *action,
382 atk_selection_interface_init (AtkSelectionIface *iface)
384 iface->add_selection = gail_combo_add_selection;
385 iface->clear_selection = gail_combo_clear_selection;
386 iface->ref_selection = gail_combo_ref_selection;
387 iface->get_selection_count = gail_combo_get_selection_count;
388 iface->is_child_selected = gail_combo_is_child_selected;
389 iface->remove_selection = gail_combo_remove_selection;
391 * select_all_selection does not make sense for a combo box
392 * so no implementation is provided.
397 gail_combo_add_selection (AtkSelection *selection,
403 widget = GTK_ACCESSIBLE (selection)->widget;
410 combo = GTK_COMBO (widget);
412 gtk_list_select_item (GTK_LIST (combo->list), i);
417 gail_combo_clear_selection (AtkSelection *selection)
422 widget = GTK_ACCESSIBLE (selection)->widget;
429 combo = GTK_COMBO (widget);
431 gtk_list_unselect_all (GTK_LIST (combo->list));
436 gail_combo_ref_selection (AtkSelection *selection,
445 widget = GTK_ACCESSIBLE (selection)->widget;
452 combo = GTK_COMBO (widget);
455 * A combo box can have only one selection.
460 list = GTK_LIST (combo->list)->selection;
465 item = GTK_WIDGET (list->data);
467 obj = gtk_widget_get_accessible (item);
473 gail_combo_get_selection_count (AtkSelection *selection)
479 widget = GTK_ACCESSIBLE (selection)->widget;
486 combo = GTK_COMBO (widget);
489 * The number of children currently selected is either 1 or 0 so we
490 * do not bother to count the elements of the selected list.
492 list = GTK_LIST (combo->list)->selection;
501 gail_combo_is_child_selected (AtkSelection *selection,
510 widget = GTK_ACCESSIBLE (selection)->widget;
517 combo = GTK_COMBO (widget);
519 list = GTK_LIST (combo->list)->selection;
524 item = GTK_WIDGET (list->data);
526 j = g_list_index (GTK_LIST (combo->list)->children, item);
532 gail_combo_remove_selection (AtkSelection *selection,
535 if (atk_selection_is_child_selected (selection, i))
536 atk_selection_clear_selection (selection);
542 _gail_combo_popup_release (gpointer data)
545 GtkWidget *action_widget;
548 GDK_THREADS_ENTER ();
550 combo = GTK_COMBO (data);
551 if (combo->current_button == 0)
553 GDK_THREADS_LEAVE ();
557 tmp_event.button.type = GDK_BUTTON_RELEASE;
558 tmp_event.button.button = 1;
559 tmp_event.button.time = GDK_CURRENT_TIME;
560 action_widget = combo->button;
562 gtk_widget_event (action_widget, &tmp_event);
564 GDK_THREADS_LEAVE ();
570 _gail_combo_button_release (gpointer data)
573 GtkWidget *action_widget;
576 GDK_THREADS_ENTER ();
578 combo = GTK_COMBO (data);
579 if (combo->current_button == 0)
581 GDK_THREADS_LEAVE ();
585 tmp_event.button.type = GDK_BUTTON_RELEASE;
586 tmp_event.button.button = 1;
587 tmp_event.button.window = combo->list->window;
588 tmp_event.button.time = GDK_CURRENT_TIME;
589 gdk_window_set_user_data (combo->list->window, combo->button);
590 action_widget = combo->list;
592 gtk_widget_event (action_widget, &tmp_event);
594 GDK_THREADS_LEAVE ();
600 gail_combo_set_description (AtkAction *action,
608 combo = GAIL_COMBO (action);
609 g_free (combo->press_description);
610 combo->press_description = g_strdup (desc);
618 gail_combo_finalize (GObject *object)
620 GailCombo *combo = GAIL_COMBO (object);
622 g_free (combo->press_description);
623 if (combo->action_idle_handler)
625 g_source_remove (combo->action_idle_handler);
626 combo->action_idle_handler = 0;
628 if (combo->deselect_idle_handler)
630 g_source_remove (combo->deselect_idle_handler);
631 combo->deselect_idle_handler = 0;
633 if (combo->select_idle_handler)
635 g_source_remove (combo->select_idle_handler);
636 combo->select_idle_handler = 0;
638 G_OBJECT_CLASS (gail_combo_parent_class)->finalize (object);