Initial revision
[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 static AtkRegistry *default_registry = NULL;;
24
25 static void              atk_registry_init           (AtkRegistry      *instance,
26                                                       AtkRegistryClass *klass);
27 static void              atk_registry_finalize       (GObject          *instance);
28 static void              atk_registry_class_init     (AtkRegistryClass *klass);
29
30 static AtkRegistry*      atk_registry_new            ();
31 static GType           atk_registry_get_factory_type (AtkRegistry      *registry,
32                                                       GType            type);
33
34 GType
35 atk_registry_get_type (void)
36 {
37   static GType type = 0;
38
39   if (!type)
40     {
41       static const GTypeInfo info =
42       {
43         sizeof (AtkRegistryClass),
44         (GBaseInitFunc) NULL,                             /* base_init */
45         (GBaseFinalizeFunc) NULL,                         /* base_finalize */
46         (GClassInitFunc) atk_registry_class_init,         /* class_init */
47         (GClassFinalizeFunc) NULL,                        /* class_finalize */
48         NULL,                                             /* class_data */
49         sizeof (AtkRegistry),                             /* instance size */
50         0,                                                /* n_preallocs */
51         (GInstanceInitFunc) atk_registry_init,            /* instance init */
52         NULL                                              /* value table */
53       };
54
55       type = g_type_register_static (G_TYPE_OBJECT, "AtkRegistry", &info, 0);
56     }
57
58   return type;
59 }
60
61 static void
62 atk_registry_class_init (AtkRegistryClass *klass)
63 {
64   GObjectClass *object_class;
65
66   /* is paranoia appropriate in a class initializer ? */
67   g_return_if_fail (G_IS_OBJECT_CLASS (klass));
68
69   object_class = G_OBJECT_CLASS (klass);
70   object_class->finalize = atk_registry_finalize;
71   default_registry = atk_registry_new ();
72 }
73
74 #if 0
75 /*
76  * Cannot define a class_finalize function when calling
77  * g_type_register_static()
78  */
79 static void
80 atk_registry_class_finalize (GObjectClass *klass)
81 {
82   g_return_if_fail (ATK_IS_REGISTRY_CLASS (klass));
83
84   g_free (default_registry);
85 }
86 #endif
87
88 static void
89 atk_registry_init (AtkRegistry *instance, AtkRegistryClass *klass)
90 {
91   instance->factory_type_registry = g_hash_table_new (NULL, NULL);
92   instance->factory_singleton_cache = g_hash_table_new (NULL, NULL);
93 }
94
95 static AtkRegistry*
96 atk_registry_new ()
97 {
98   GObject *object;
99
100   object = g_object_new (ATK_TYPE_REGISTRY, NULL);
101
102   g_return_val_if_fail ((object != NULL), NULL);
103   g_return_val_if_fail (ATK_IS_REGISTRY (object), NULL);
104
105   return (AtkRegistry *) object;
106 }
107
108 static void
109 atk_registry_finalize (GObject *instance)
110 {
111   AtkRegistry *registry;
112
113   g_return_if_fail (ATK_IS_REGISTRY (instance));
114   registry = ATK_REGISTRY (instance);
115   g_free (registry->factory_type_registry);
116   g_free (registry->factory_singleton_cache);
117 }
118
119
120 void
121 atk_registry_set_factory_type (AtkRegistry *registry,
122                                GType type,
123                                GType factory_type)
124 {
125   GType old_type;
126   gpointer value;
127   AtkObjectFactory *old_factory;
128
129   g_return_if_fail (ATK_IS_REGISTRY (registry));
130
131   value = g_hash_table_lookup (registry->factory_type_registry, 
132                                   GUINT_TO_POINTER (type));
133   old_type = GPOINTER_TO_UINT (value);
134   if (old_type && old_type != factory_type)
135     {
136       g_hash_table_remove (registry->factory_type_registry, 
137                            GUINT_TO_POINTER (type));
138       /*
139        * If the old factory was created, notify it that it has
140        * been replaced, then free it.
141        */
142       old_factory = g_hash_table_lookup (registry->factory_singleton_cache, 
143                                          GUINT_TO_POINTER (old_type));
144       if (old_factory)
145         {
146           atk_object_factory_invalidate (old_factory);
147           g_type_free_instance ((GTypeInstance *) old_factory);
148         }
149     }
150   g_hash_table_insert (registry->factory_type_registry, 
151                        GUINT_TO_POINTER (type), 
152                        GUINT_TO_POINTER (factory_type));
153 }
154
155 GType
156 atk_registry_get_factory_type (AtkRegistry *registry,
157                                GType type)
158 {
159   GType factory_type;
160   gpointer value;
161
162   /*
163    * look up factory type in first hash;
164    * if there isn't an explicitly registered factory type,
165    * try inheriting one...
166    */
167   do {
168     value =
169         g_hash_table_lookup (registry->factory_type_registry, 
170                              GUINT_TO_POINTER (type));
171     type = g_type_parent (type);
172     if (type == G_TYPE_INVALID)
173       {
174         break;
175       }
176   } while (value == NULL);
177
178   factory_type = GPOINTER_TO_UINT (value);
179   return factory_type;
180 }
181
182
183 AtkObjectFactory*
184 atk_registry_get_factory (AtkRegistry *registry,
185                           GType type)
186 {
187   gpointer factory_pointer = NULL;
188   GType factory_type;
189
190   factory_type = atk_registry_get_factory_type (registry, type);
191
192   if (factory_type == G_TYPE_INVALID)
193   {
194   /* Factory type has not been specified for this object type */
195     static AtkObjectFactory* default_factory = NULL;
196
197     if (!default_factory)
198       default_factory = atk_no_op_object_factory_new ();
199
200     return default_factory;
201   }
202
203   /* ask second hashtable for instance of factory type */
204   factory_pointer =
205         g_hash_table_lookup (registry->factory_singleton_cache, 
206         GUINT_TO_POINTER (factory_type));
207
208   /* if there isn't one already, create one and save it */
209   if (factory_pointer == NULL)
210     {
211       factory_pointer = g_type_create_instance (factory_type);
212       g_hash_table_insert (registry->factory_singleton_cache,
213                            GUINT_TO_POINTER (factory_type),
214                            factory_pointer);
215     }
216
217   return ATK_OBJECT_FACTORY (factory_pointer);
218 }
219
220
221 AtkRegistry*
222 atk_get_default_registry ()
223 {
224   if (!default_registry)
225   {
226     default_registry = atk_registry_new();
227   }
228   return default_registry;
229 }