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