1 /* GTK+ - accessibility implementations
2  * Copyright 2001, 2002, 2003 Sun Microsystems Inc.
3  *
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.
8  *
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.
13  *
14  * You should have received a copy of the GNU Lesser General Public
15  * License along with this library. If not, see <http://www.gnu.org/licenses/>.
16  */
17 
18 #include "config.h"
19 
20 #include "gtkcontaineraccessible.h"
21 #include "gtkcontaineraccessibleprivate.h"
22 
23 #include <gtk/gtk.h>
24 
25 #include "gtkwidgetprivate.h"
26 
27 struct _GtkContainerAccessiblePrivate
28 {
29   GList *children;
30 };
31 
G_DEFINE_TYPE_WITH_PRIVATE(GtkContainerAccessible,gtk_container_accessible,GTK_TYPE_WIDGET_ACCESSIBLE)32 G_DEFINE_TYPE_WITH_PRIVATE (GtkContainerAccessible, gtk_container_accessible, GTK_TYPE_WIDGET_ACCESSIBLE)
33 
34 static void
35 count_widget (GtkWidget *widget,
36               gint      *count)
37 {
38   (*count)++;
39 }
40 
41 static gint
gtk_container_accessible_get_n_children(AtkObject * obj)42 gtk_container_accessible_get_n_children (AtkObject* obj)
43 {
44   GtkWidget *widget;
45   gint count = 0;
46 
47   widget = gtk_accessible_get_widget (GTK_ACCESSIBLE (obj));
48   if (widget == NULL)
49     return 0;
50 
51   gtk_container_foreach (GTK_CONTAINER (widget), (GtkCallback) count_widget, &count);
52   return count;
53 }
54 
55 static AtkObject *
gtk_container_accessible_ref_child(AtkObject * obj,gint i)56 gtk_container_accessible_ref_child (AtkObject *obj,
57                                     gint       i)
58 {
59   GList *children, *tmp_list;
60   AtkObject  *accessible;
61   GtkWidget *widget;
62 
63   widget = gtk_accessible_get_widget (GTK_ACCESSIBLE (obj));
64   if (widget == NULL)
65     return NULL;
66 
67   children = gtk_container_get_children (GTK_CONTAINER (widget));
68   tmp_list = g_list_nth (children, i);
69   if (!tmp_list)
70     {
71       g_list_free (children);
72       return NULL;
73     }
74   accessible = gtk_widget_get_accessible (GTK_WIDGET (tmp_list->data));
75 
76   g_list_free (children);
77   g_object_ref (accessible);
78 
79   return accessible;
80 }
81 
82 void
_gtk_container_accessible_add(GtkWidget * parent,GtkWidget * child)83 _gtk_container_accessible_add (GtkWidget *parent,
84                                GtkWidget *child)
85 {
86   GtkContainerAccessible *accessible;
87   GtkContainerAccessibleClass *klass;
88   AtkObject *obj;
89 
90   obj = _gtk_widget_peek_accessible (GTK_WIDGET (parent));
91   if (!GTK_IS_CONTAINER_ACCESSIBLE (obj))
92     return;
93 
94   accessible = GTK_CONTAINER_ACCESSIBLE (obj);
95   klass = GTK_CONTAINER_ACCESSIBLE_GET_CLASS (accessible);
96 
97   if (klass->add_gtk)
98     klass->add_gtk (GTK_CONTAINER (parent), child, obj);
99 }
100 
101 void
_gtk_container_accessible_remove(GtkWidget * parent,GtkWidget * child)102 _gtk_container_accessible_remove (GtkWidget *parent,
103                                   GtkWidget *child)
104 {
105   GtkContainerAccessible *accessible;
106   GtkContainerAccessibleClass *klass;
107   AtkObject *obj;
108 
109   obj = _gtk_widget_peek_accessible (GTK_WIDGET (parent));
110   if (!GTK_IS_CONTAINER_ACCESSIBLE (obj))
111     return;
112 
113   accessible = GTK_CONTAINER_ACCESSIBLE (obj);
114   klass = GTK_CONTAINER_ACCESSIBLE_GET_CLASS (accessible);
115 
116   if (klass->remove_gtk)
117     klass->remove_gtk (GTK_CONTAINER (parent), child, obj);
118 }
119 
120 static gint
gtk_container_accessible_real_add_gtk(GtkContainer * container,GtkWidget * widget,gpointer data)121 gtk_container_accessible_real_add_gtk (GtkContainer *container,
122                                        GtkWidget    *widget,
123                                        gpointer      data)
124 {
125   AtkObject *atk_parent;
126   AtkObject *atk_child;
127   GtkContainerAccessible *accessible;
128   gint index;
129 
130   atk_parent = ATK_OBJECT (data);
131   atk_child = gtk_widget_get_accessible (widget);
132   accessible = GTK_CONTAINER_ACCESSIBLE (atk_parent);
133 
134   g_list_free (accessible->priv->children);
135   accessible->priv->children = gtk_container_get_children (container);
136   index = g_list_index (accessible->priv->children, widget);
137   _gtk_container_accessible_add_child (accessible, atk_child, index);
138 
139   return 1;
140 }
141 
142 static gint
gtk_container_accessible_real_remove_gtk(GtkContainer * container,GtkWidget * widget,gpointer data)143 gtk_container_accessible_real_remove_gtk (GtkContainer *container,
144                                           GtkWidget    *widget,
145                                           gpointer      data)
146 {
147   AtkObject* atk_parent;
148   AtkObject *atk_child;
149   GtkContainerAccessible *accessible;
150   gint index;
151 
152   atk_parent = ATK_OBJECT (data);
153   atk_child = _gtk_widget_peek_accessible (widget);
154   if (atk_child == NULL)
155     return 1;
156   accessible = GTK_CONTAINER_ACCESSIBLE (atk_parent);
157 
158   index = g_list_index (accessible->priv->children, widget);
159   g_list_free (accessible->priv->children);
160   accessible->priv->children = gtk_container_get_children (container);
161   if (index >= 0)
162     _gtk_container_accessible_remove_child (accessible, atk_child, index);
163 
164   return 1;
165 }
166 
167 static void
gtk_container_accessible_real_initialize(AtkObject * obj,gpointer data)168 gtk_container_accessible_real_initialize (AtkObject *obj,
169                                           gpointer   data)
170 {
171   GtkContainerAccessible *accessible = GTK_CONTAINER_ACCESSIBLE (obj);
172 
173   ATK_OBJECT_CLASS (gtk_container_accessible_parent_class)->initialize (obj, data);
174 
175   accessible->priv->children = gtk_container_get_children (GTK_CONTAINER (data));
176 
177   obj->role = ATK_ROLE_PANEL;
178 }
179 
180 static void
gtk_container_accessible_finalize(GObject * object)181 gtk_container_accessible_finalize (GObject *object)
182 {
183   GtkContainerAccessible *accessible = GTK_CONTAINER_ACCESSIBLE (object);
184 
185   g_list_free (accessible->priv->children);
186 
187   G_OBJECT_CLASS (gtk_container_accessible_parent_class)->finalize (object);
188 }
189 
190 static void
gtk_container_accessible_class_init(GtkContainerAccessibleClass * klass)191 gtk_container_accessible_class_init (GtkContainerAccessibleClass *klass)
192 {
193   GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
194   AtkObjectClass *class = ATK_OBJECT_CLASS (klass);
195 
196   gobject_class->finalize = gtk_container_accessible_finalize;
197 
198   class->get_n_children = gtk_container_accessible_get_n_children;
199   class->ref_child = gtk_container_accessible_ref_child;
200   class->initialize = gtk_container_accessible_real_initialize;
201 
202   klass->add_gtk = gtk_container_accessible_real_add_gtk;
203   klass->remove_gtk = gtk_container_accessible_real_remove_gtk;
204 }
205 
206 static void
gtk_container_accessible_init(GtkContainerAccessible * container)207 gtk_container_accessible_init (GtkContainerAccessible *container)
208 {
209   container->priv = gtk_container_accessible_get_instance_private (container);
210 }
211 
212 void
_gtk_container_accessible_add_child(GtkContainerAccessible * accessible,AtkObject * child,gint index)213 _gtk_container_accessible_add_child (GtkContainerAccessible *accessible,
214                                      AtkObject              *child,
215                                      gint                    index)
216 {
217   g_object_notify (G_OBJECT (child), "accessible-parent");
218   g_signal_emit_by_name (accessible, "children-changed::add", index, child, NULL);
219 }
220 
221 void
_gtk_container_accessible_remove_child(GtkContainerAccessible * accessible,AtkObject * child,gint index)222 _gtk_container_accessible_remove_child (GtkContainerAccessible *accessible,
223                                         AtkObject              *child,
224                                         gint                    index)
225 {
226   g_object_notify (G_OBJECT (child), "accessible-parent");
227   g_signal_emit_by_name (accessible, "children-changed::remove", index, child, NULL);
228 }
229