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.
23 #include "gailcombo.h"
25 static void gail_combo_class_init (GailComboClass *klass);
26 static void gail_combo_init (GailCombo *combo);
27 static void gail_combo_real_initialize (AtkObject *obj,
30 static void gail_combo_selection_changed_gtk (GtkWidget *widget,
33 static gint gail_combo_get_n_children (AtkObject *obj);
34 static AtkObject* gail_combo_ref_child (AtkObject *obj,
36 static void gail_combo_finalize (GObject *object);
37 static void atk_action_interface_init (AtkActionIface *iface);
39 static gboolean gail_combo_do_action (AtkAction *action,
41 static gboolean idle_do_action (gpointer data);
42 static gint gail_combo_get_n_actions (AtkAction *action)
44 static G_CONST_RETURN gchar* gail_combo_get_description(AtkAction *action,
46 static G_CONST_RETURN gchar* gail_combo_get_name (AtkAction *action,
48 static gboolean gail_combo_set_description(AtkAction *action,
52 static void atk_selection_interface_init (AtkSelectionIface *iface);
53 static gboolean gail_combo_add_selection (AtkSelection *selection,
55 static gboolean gail_combo_clear_selection (AtkSelection *selection);
56 static AtkObject* gail_combo_ref_selection (AtkSelection *selection,
58 static gint gail_combo_get_selection_count (AtkSelection *selection);
59 static gboolean gail_combo_is_child_selected (AtkSelection *selection,
61 static gboolean gail_combo_remove_selection (AtkSelection *selection,
64 static gint _gail_combo_button_release (gpointer data);
65 static gint _gail_combo_popup_release (gpointer data);
68 G_DEFINE_TYPE_WITH_CODE (GailCombo, gail_combo, GAIL_TYPE_CONTAINER,
69 G_IMPLEMENT_INTERFACE (ATK_TYPE_ACTION, atk_action_interface_init)
70 G_IMPLEMENT_INTERFACE (ATK_TYPE_SELECTION, atk_selection_interface_init))
73 gail_combo_class_init (GailComboClass *klass)
75 GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
76 AtkObjectClass *class = ATK_OBJECT_CLASS (klass);
78 gobject_class->finalize = gail_combo_finalize;
80 class->get_n_children = gail_combo_get_n_children;
81 class->ref_child = gail_combo_ref_child;
82 class->initialize = gail_combo_real_initialize;
86 gail_combo_init (GailCombo *combo)
88 combo->press_description = NULL;
89 combo->old_selection = NULL;
90 combo->deselect_idle_handler = 0;
91 combo->select_idle_handler = 0;
95 gail_combo_real_initialize (AtkObject *obj,
101 GailCombo *gail_combo;
103 ATK_OBJECT_CLASS (gail_combo_parent_class)->initialize (obj, data);
105 combo = GTK_COMBO (data);
107 list = GTK_LIST (combo->list);
108 slist = list->selection;
110 gail_combo = GAIL_COMBO (obj);
111 if (slist && slist->data)
113 gail_combo->old_selection = slist->data;
115 g_signal_connect (combo->list,
117 G_CALLBACK (gail_combo_selection_changed_gtk),
119 atk_object_set_parent (gtk_widget_get_accessible (combo->entry), obj);
120 atk_object_set_parent (gtk_widget_get_accessible (combo->popup), obj);
122 obj->role = ATK_ROLE_COMBO_BOX;
126 notify_deselect (gpointer data)
130 combo = GAIL_COMBO (data);
132 combo->old_selection = NULL;
133 combo->deselect_idle_handler = 0;
134 g_signal_emit_by_name (data, "selection_changed");
140 notify_select (gpointer data)
144 combo = GAIL_COMBO (data);
146 combo->select_idle_handler = 0;
147 g_signal_emit_by_name (data, "selection_changed");
153 gail_combo_selection_changed_gtk (GtkWidget *widget,
160 GailCombo *gail_combo;
162 combo = GTK_COMBO (data);
163 list = GTK_LIST (combo->list);
165 slist = list->selection;
167 obj = gtk_widget_get_accessible (GTK_WIDGET (data));
168 gail_combo = GAIL_COMBO (obj);
169 if (slist && slist->data)
171 if (slist->data != gail_combo->old_selection)
173 gail_combo->old_selection = slist->data;
174 if (gail_combo->select_idle_handler == 0)
175 gail_combo->select_idle_handler = gdk_threads_add_idle (notify_select, gail_combo);
177 if (gail_combo->deselect_idle_handler)
179 g_source_remove (gail_combo->deselect_idle_handler);
180 gail_combo->deselect_idle_handler = 0;
185 if (gail_combo->deselect_idle_handler == 0)
186 gail_combo->deselect_idle_handler = gdk_threads_add_idle (notify_deselect, gail_combo);
187 if (gail_combo->select_idle_handler)
189 g_source_remove (gail_combo->select_idle_handler);
190 gail_combo->select_idle_handler = 0;
196 * The children of a GailCombo are the list of items and the entry field
199 gail_combo_get_n_children (AtkObject* obj)
204 g_return_val_if_fail (GAIL_IS_COMBO (obj), 0);
206 widget = GTK_ACCESSIBLE (obj)->widget;
217 gail_combo_ref_child (AtkObject *obj,
220 AtkObject *accessible;
223 g_return_val_if_fail (GAIL_IS_COMBO (obj), NULL);
228 widget = GTK_ACCESSIBLE (obj)->widget;
236 accessible = gtk_widget_get_accessible (GTK_COMBO (widget)->popup);
238 accessible = gtk_widget_get_accessible (GTK_COMBO (widget)->entry);
240 g_object_ref (accessible);
245 atk_action_interface_init (AtkActionIface *iface)
247 iface->do_action = gail_combo_do_action;
248 iface->get_n_actions = gail_combo_get_n_actions;
249 iface->get_description = gail_combo_get_description;
250 iface->get_name = gail_combo_get_name;
251 iface->set_description = gail_combo_set_description;
255 gail_combo_do_action (AtkAction *action,
261 widget = GTK_ACCESSIBLE (action)->widget;
268 if (!GTK_WIDGET_SENSITIVE (widget) || !GTK_WIDGET_VISIBLE (widget))
271 combo = GAIL_COMBO (action);
274 if (combo->action_idle_handler)
277 combo->action_idle_handler = gdk_threads_add_idle (idle_do_action, combo);
285 * This action is the pressing of the button on the combo box.
286 * The behavior is different depending on whether the list is being
287 * displayed or removed.
289 * A button press event is simulated on the appropriate widget and
290 * a button release event is simulated in an idle function.
293 idle_do_action (gpointer data)
296 GtkWidget *action_widget;
298 GailCombo *gail_combo;
302 gail_combo = GAIL_COMBO (data);
303 gail_combo->action_idle_handler = 0;
304 widget = GTK_ACCESSIBLE (gail_combo)->widget;
305 if (widget == NULL /* State is defunct */ ||
306 !GTK_WIDGET_SENSITIVE (widget) || !GTK_WIDGET_VISIBLE (widget))
309 combo = GTK_COMBO (widget);
311 do_popup = !GTK_WIDGET_MAPPED (combo->popwin);
313 tmp_event.button.type = GDK_BUTTON_PRESS;
314 tmp_event.button.window = widget->window;
315 tmp_event.button.button = 1;
316 tmp_event.button.send_event = TRUE;
317 tmp_event.button.time = GDK_CURRENT_TIME;
318 tmp_event.button.axes = NULL;
323 action_widget = combo->button;
325 gtk_widget_event (action_widget, &tmp_event);
328 g_idle_add (_gail_combo_button_release, combo);
333 tmp_event.button.window = combo->list->window;
334 gdk_window_set_user_data (combo->list->window, combo->button);
335 action_widget = combo->popwin;
337 gtk_widget_event (action_widget, &tmp_event);
339 g_idle_add (_gail_combo_popup_release, combo);
346 gail_combo_get_n_actions (AtkAction *action)
349 * The default behavior of a combo box is to have one action -
354 static G_CONST_RETURN gchar*
355 gail_combo_get_description (AtkAction *action,
362 combo = GAIL_COMBO (action);
363 return combo->press_description;
369 static G_CONST_RETURN gchar*
370 gail_combo_get_name (AtkAction *action,
380 atk_selection_interface_init (AtkSelectionIface *iface)
382 iface->add_selection = gail_combo_add_selection;
383 iface->clear_selection = gail_combo_clear_selection;
384 iface->ref_selection = gail_combo_ref_selection;
385 iface->get_selection_count = gail_combo_get_selection_count;
386 iface->is_child_selected = gail_combo_is_child_selected;
387 iface->remove_selection = gail_combo_remove_selection;
389 * select_all_selection does not make sense for a combo box
390 * so no implementation is provided.
395 gail_combo_add_selection (AtkSelection *selection,
401 widget = GTK_ACCESSIBLE (selection)->widget;
408 combo = GTK_COMBO (widget);
410 gtk_list_select_item (GTK_LIST (combo->list), i);
415 gail_combo_clear_selection (AtkSelection *selection)
420 widget = GTK_ACCESSIBLE (selection)->widget;
427 combo = GTK_COMBO (widget);
429 gtk_list_unselect_all (GTK_LIST (combo->list));
434 gail_combo_ref_selection (AtkSelection *selection,
443 widget = GTK_ACCESSIBLE (selection)->widget;
450 combo = GTK_COMBO (widget);
453 * A combo box can have only one selection.
458 list = GTK_LIST (combo->list)->selection;
463 item = GTK_WIDGET (list->data);
465 obj = gtk_widget_get_accessible (item);
471 gail_combo_get_selection_count (AtkSelection *selection)
477 widget = GTK_ACCESSIBLE (selection)->widget;
484 combo = GTK_COMBO (widget);
487 * The number of children currently selected is either 1 or 0 so we
488 * do not bother to count the elements of the selected list.
490 list = GTK_LIST (combo->list)->selection;
499 gail_combo_is_child_selected (AtkSelection *selection,
508 widget = GTK_ACCESSIBLE (selection)->widget;
515 combo = GTK_COMBO (widget);
517 list = GTK_LIST (combo->list)->selection;
522 item = GTK_WIDGET (list->data);
524 j = g_list_index (GTK_LIST (combo->list)->children, item);
530 gail_combo_remove_selection (AtkSelection *selection,
533 if (atk_selection_is_child_selected (selection, i))
534 atk_selection_clear_selection (selection);
540 _gail_combo_popup_release (gpointer data)
543 GtkWidget *action_widget;
546 GDK_THREADS_ENTER ();
548 combo = GTK_COMBO (data);
549 if (combo->current_button == 0)
551 GDK_THREADS_LEAVE ();
555 tmp_event.button.type = GDK_BUTTON_RELEASE;
556 tmp_event.button.button = 1;
557 tmp_event.button.time = GDK_CURRENT_TIME;
558 action_widget = combo->button;
560 gtk_widget_event (action_widget, &tmp_event);
562 GDK_THREADS_LEAVE ();
568 _gail_combo_button_release (gpointer data)
571 GtkWidget *action_widget;
574 GDK_THREADS_ENTER ();
576 combo = GTK_COMBO (data);
577 if (combo->current_button == 0)
579 GDK_THREADS_LEAVE ();
583 tmp_event.button.type = GDK_BUTTON_RELEASE;
584 tmp_event.button.button = 1;
585 tmp_event.button.window = combo->list->window;
586 tmp_event.button.time = GDK_CURRENT_TIME;
587 gdk_window_set_user_data (combo->list->window, combo->button);
588 action_widget = combo->list;
590 gtk_widget_event (action_widget, &tmp_event);
592 GDK_THREADS_LEAVE ();
598 gail_combo_set_description (AtkAction *action,
606 combo = GAIL_COMBO (action);
607 g_free (combo->press_description);
608 combo->press_description = g_strdup (desc);
616 gail_combo_finalize (GObject *object)
618 GailCombo *combo = GAIL_COMBO (object);
620 g_free (combo->press_description);
621 if (combo->action_idle_handler)
623 g_source_remove (combo->action_idle_handler);
624 combo->action_idle_handler = 0;
626 if (combo->deselect_idle_handler)
628 g_source_remove (combo->deselect_idle_handler);
629 combo->deselect_idle_handler = 0;
631 if (combo->select_idle_handler)
633 g_source_remove (combo->select_idle_handler);
634 combo->select_idle_handler = 0;
636 G_OBJECT_CLASS (gail_combo_parent_class)->finalize (object);