Revert "Revert "Merge remote-tracking branch 'origin/sandbox/mniesluchow/upstream_2_1...
[platform/upstream/atk.git] / atk / atkregistry.c
1 /* ATK - Accessibility Toolkit
2  * Copyright 2001 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 Library 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  * Library General Public License for more details.
13  *
14  * You should have received a copy of the GNU Library 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.
18  */
19
20 #include "config.h"
21
22 #include "atkregistry.h"
23 #include "atknoopobjectfactory.h"
24
25 /**
26  * SECTION:atkregistry
27  * @Short_description: An object used to store the GType of the
28  * factories used to create an accessible object for an object of a
29  * particular GType.
30  * @Title:AtkRegistry
31  *
32  * The AtkRegistry is normally used to create appropriate ATK "peers"
33  * for user interface components.  Application developers usually need
34  * only interact with the AtkRegistry by associating appropriate ATK
35  * implementation classes with GObject classes via the
36  * atk_registry_set_factory_type call, passing the appropriate GType
37  * for application custom widget classes.
38  */
39
40 static AtkRegistry *default_registry = NULL;
41
42 static void              atk_registry_init           (AtkRegistry      *instance,
43                                                       AtkRegistryClass *klass);
44 static void              atk_registry_finalize       (GObject          *instance);
45 static void              atk_registry_class_init     (AtkRegistryClass *klass);
46 static AtkRegistry*      atk_registry_new            (void);
47
48 static gpointer parent_class = NULL;
49
50 GType
51 atk_registry_get_type (void)
52 {
53   static GType type = 0;
54
55   if (!type)
56     {
57       static const GTypeInfo info =
58       {
59         sizeof (AtkRegistryClass),
60         (GBaseInitFunc) NULL,                             /* base_init */
61         (GBaseFinalizeFunc) NULL,                         /* base_finalize */
62         (GClassInitFunc) atk_registry_class_init,         /* class_init */
63         (GClassFinalizeFunc) NULL,                        /* class_finalize */
64         NULL,                                             /* class_data */
65         sizeof (AtkRegistry),                             /* instance size */
66         0,                                                /* n_preallocs */
67         (GInstanceInitFunc) atk_registry_init,            /* instance init */
68         NULL                                              /* value table */
69       };
70
71       type = g_type_register_static (G_TYPE_OBJECT, "AtkRegistry", &info, 0);
72     }
73
74   return type;
75 }
76
77 static void
78 atk_registry_class_init (AtkRegistryClass *klass)
79 {
80   GObjectClass *object_class = (GObjectClass *) klass;
81
82   parent_class = g_type_class_peek_parent (klass);
83
84   object_class->finalize = atk_registry_finalize;
85 }
86
87 #if 0
88 /*
89  * Cannot define a class_finalize function when calling
90  * g_type_register_static()
91  */
92 static void
93 atk_registry_class_finalize (GObjectClass *klass)
94 {
95   g_return_if_fail (ATK_IS_REGISTRY_CLASS (klass));
96
97   g_object_unref (G_OBJECT (default_registry));
98 }
99 #endif
100
101 static void
102 atk_registry_init (AtkRegistry *instance, AtkRegistryClass *klass)
103 {
104   instance->factory_type_registry = g_hash_table_new ((GHashFunc) NULL, 
105                                                       (GEqualFunc) NULL);
106   instance->factory_singleton_cache = g_hash_table_new ((GHashFunc) NULL, 
107                                                         (GEqualFunc) NULL);
108 }
109
110 static AtkRegistry *
111 atk_registry_new (void)
112 {
113   GObject *object;
114
115   object = g_object_new (ATK_TYPE_REGISTRY, NULL);
116
117   g_return_val_if_fail (ATK_IS_REGISTRY (object), NULL);
118
119   return (AtkRegistry *) object;
120 }
121
122 static void
123 atk_registry_finalize (GObject *object)
124 {
125   AtkRegistry *registry = ATK_REGISTRY (object);
126
127   g_hash_table_destroy (registry->factory_type_registry);
128   g_hash_table_destroy (registry->factory_singleton_cache);
129
130   G_OBJECT_CLASS (parent_class)->finalize (object);
131 }
132
133 /**
134  * atk_registry_set_factory_type:
135  * @registry: the #AtkRegistry in which to register the type association
136  * @type: an #AtkObject type 
137  * @factory_type: an #AtkObjectFactory type to associate with @type.  Must
138  * implement AtkObject appropriate for @type.
139  *
140  * Associate an #AtkObjectFactory subclass with a #GType. Note:
141  * The associated @factory_type will thereafter be responsible for
142  * the creation of new #AtkObject implementations for instances
143  * appropriate for @type.
144  **/
145 void
146 atk_registry_set_factory_type (AtkRegistry *registry,
147                                GType type,
148                                GType factory_type)
149 {
150   GType old_type;
151   gpointer value;
152   AtkObjectFactory *old_factory;
153
154   g_return_if_fail (ATK_IS_REGISTRY (registry));
155
156   value = g_hash_table_lookup (registry->factory_type_registry, 
157                                   (gpointer) type);
158   old_type = (GType) value;
159   if (old_type && old_type != factory_type)
160     {
161       g_hash_table_remove (registry->factory_type_registry, 
162                            (gpointer) type);
163       /*
164        * If the old factory was created, notify it that it has
165        * been replaced, then free it.
166        */
167       old_factory = g_hash_table_lookup (registry->factory_singleton_cache, 
168                                          (gpointer) old_type);
169       if (old_factory)
170         {
171           atk_object_factory_invalidate (old_factory);
172           g_type_free_instance ((GTypeInstance *) old_factory);
173         }
174     }
175   g_hash_table_insert (registry->factory_type_registry, 
176                        (gpointer) type, 
177                        (gpointer) factory_type);
178 }
179
180 /**
181  * atk_registry_get_factory_type:
182  * @registry: an #AtkRegistry
183  * @type: a #GType with which to look up the associated #AtkObjectFactory
184  * subclass
185  *
186  * Provides a #GType indicating the #AtkObjectFactory subclass
187  * associated with @type.
188  *
189  * Returns: a #GType associated with type @type
190  **/
191 GType
192 atk_registry_get_factory_type (AtkRegistry *registry,
193                                GType type)
194 {
195   GType factory_type;
196   gpointer value;
197
198   /*
199    * look up factory type in first hash;
200    * if there isn't an explicitly registered factory type,
201    * try inheriting one...
202    */
203   do {
204     value =
205         g_hash_table_lookup (registry->factory_type_registry, 
206                              (gpointer) type);
207     type = g_type_parent (type);
208     if (type == G_TYPE_INVALID)
209       {
210         break;
211       }
212   } while (value == NULL);
213
214   factory_type = (GType) value;
215   return factory_type;
216 }
217
218 /**
219  * atk_registry_get_factory:
220  * @registry: an #AtkRegistry
221  * @type: a #GType with which to look up the associated #AtkObjectFactory
222  *
223  * Gets an #AtkObjectFactory appropriate for creating #AtkObjects
224  * appropriate for @type.
225  *
226  * Returns: (transfer none): an #AtkObjectFactory appropriate for creating
227  * #AtkObjects appropriate for @type.
228  **/
229 AtkObjectFactory*
230 atk_registry_get_factory (AtkRegistry *registry,
231                           GType type)
232 {
233   gpointer factory_pointer = NULL;
234   GType factory_type;
235
236   factory_type = atk_registry_get_factory_type (registry, type);
237
238   if (factory_type == G_TYPE_INVALID)
239   {
240   /* Factory type has not been specified for this object type */
241     static AtkObjectFactory* default_factory = NULL;
242
243     if (!default_factory)
244       default_factory = atk_no_op_object_factory_new ();
245
246     return default_factory;
247   }
248
249   /* ask second hashtable for instance of factory type */
250   factory_pointer =
251         g_hash_table_lookup (registry->factory_singleton_cache, 
252         (gpointer) factory_type);
253
254   /* if there isn't one already, create one and save it */
255   if (factory_pointer == NULL)
256     {
257       factory_pointer = g_type_create_instance (factory_type);
258       g_hash_table_insert (registry->factory_singleton_cache,
259                            (gpointer) factory_type,
260                            factory_pointer);
261     }
262
263   return ATK_OBJECT_FACTORY (factory_pointer);
264 }
265
266 /**
267  * atk_get_default_registry:
268  *
269  * Gets a default implementation of the #AtkObjectFactory/type
270  * registry.
271  * Note: For most toolkit maintainers, this will be the correct
272  * registry for registering new #AtkObject factories. Following
273  * a call to this function, maintainers may call atk_registry_set_factory_type()
274  * to associate an #AtkObjectFactory subclass with the GType of objects
275  * for whom accessibility information will be provided.
276  *
277  * Returns: (transfer full): a default implementation of the
278  * #AtkObjectFactory/type registry
279  **/
280 AtkRegistry*
281 atk_get_default_registry (void)
282 {
283   if (!default_registry)
284     {
285       default_registry = atk_registry_new ();
286     }
287   return default_registry;
288 }