atkregistry.c 8.48 KB
Newer Older
Bill Haneman's avatar
Bill Haneman committed
1
2
3
4
5
6
7
8
9
10
11
12
13
14
/* ATK - Accessibility Toolkit
 * Copyright 2001 Sun Microsystems Inc.
 *
 * This library is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Library General Public
 * License as published by the Free Software Foundation; either
 * version 2 of the License, or (at your option) any later version.
 *
 * This library is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 * Library General Public License for more details.
 *
 * You should have received a copy of the GNU Library General Public
Piotr Drąg's avatar
Piotr Drąg committed
15
16
17
 * License along with this library; if not, write to the
 * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
 * Boston, MA 02111-1307, USA.
Bill Haneman's avatar
Bill Haneman committed
18
19
 */

20
21
#include "config.h"

Bill Haneman's avatar
Bill Haneman committed
22
23
24
#include "atkregistry.h"
#include "atknoopobjectfactory.h"

25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
/**
 * SECTION:atkregistry
 * @Short_description: An object used to store the GType of the
 * factories used to create an accessible object for an object of a
 * particular GType.
 * @Title:AtkRegistry
 *
 * The AtkRegistry is normally used to create appropriate ATK "peers"
 * for user interface components.  Application developers usually need
 * only interact with the AtkRegistry by associating appropriate ATK
 * implementation classes with GObject classes via the
 * atk_registry_set_factory_type call, passing the appropriate GType
 * for application custom widget classes.
 */

40
static AtkRegistry *default_registry = NULL;
Bill Haneman's avatar
Bill Haneman committed
41
42
43
44
45

static void              atk_registry_init           (AtkRegistry      *instance,
                                                      AtkRegistryClass *klass);
static void              atk_registry_finalize       (GObject          *instance);
static void              atk_registry_class_init     (AtkRegistryClass *klass);
46
static AtkRegistry*      atk_registry_new            (void);
Bill Haneman's avatar
Bill Haneman committed
47

48
static gpointer parent_class = NULL;
Bill Haneman's avatar
Bill Haneman committed
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79

GType
atk_registry_get_type (void)
{
  static GType type = 0;

  if (!type)
    {
      static const GTypeInfo info =
      {
        sizeof (AtkRegistryClass),
        (GBaseInitFunc) NULL,                             /* base_init */
        (GBaseFinalizeFunc) NULL,                         /* base_finalize */
        (GClassInitFunc) atk_registry_class_init,         /* class_init */
        (GClassFinalizeFunc) NULL,                        /* class_finalize */
        NULL,                                             /* class_data */
        sizeof (AtkRegistry),                             /* instance size */
        0,                                                /* n_preallocs */
        (GInstanceInitFunc) atk_registry_init,            /* instance init */
        NULL                                              /* value table */
      };

      type = g_type_register_static (G_TYPE_OBJECT, "AtkRegistry", &info, 0);
    }

  return type;
}

static void
atk_registry_class_init (AtkRegistryClass *klass)
{
80
  GObjectClass *object_class = (GObjectClass *) klass;
Bill Haneman's avatar
Bill Haneman committed
81

82
  parent_class = g_type_class_peek_parent (klass);
Bill Haneman's avatar
Bill Haneman committed
83
84
85
86
87
88
89

  object_class->finalize = atk_registry_finalize;
}

static void
atk_registry_init (AtkRegistry *instance, AtkRegistryClass *klass)
{
90
91
92
93
  instance->factory_type_registry = g_hash_table_new ((GHashFunc) NULL, 
                                                      (GEqualFunc) NULL);
  instance->factory_singleton_cache = g_hash_table_new ((GHashFunc) NULL, 
                                                        (GEqualFunc) NULL);
Bill Haneman's avatar
Bill Haneman committed
94
95
}

96
97
static AtkRegistry *
atk_registry_new (void)
Bill Haneman's avatar
Bill Haneman committed
98
99
100
101
102
103
104
105
106
107
108
{
  GObject *object;

  object = g_object_new (ATK_TYPE_REGISTRY, NULL);

  g_return_val_if_fail (ATK_IS_REGISTRY (object), NULL);

  return (AtkRegistry *) object;
}

static void
109
atk_registry_finalize (GObject *object)
Bill Haneman's avatar
Bill Haneman committed
110
{
111
  AtkRegistry *registry = ATK_REGISTRY (object);
Bill Haneman's avatar
Bill Haneman committed
112

113
114
115
  g_hash_table_destroy (registry->factory_type_registry);
  g_hash_table_destroy (registry->factory_singleton_cache);

116
  G_OBJECT_CLASS (parent_class)->finalize (object);
Bill Haneman's avatar
Bill Haneman committed
117
118
}

Brian Cameron's avatar
Brian Cameron committed
119
/**
120
121
122
 * atk_registry_set_factory_type:
 * @registry: the #AtkRegistry in which to register the type association
 * @type: an #AtkObject type 
123
124
 * @factory_type: an #AtkObjectFactory type to associate with @type.  Must
 * implement AtkObject appropriate for @type.
Brian Cameron's avatar
Brian Cameron committed
125
 *
126
 * Associate an #AtkObjectFactory subclass with a #GType. Note:
Brian Cameron's avatar
Brian Cameron committed
127
128
 * The associated @factory_type will thereafter be responsible for
 * the creation of new #AtkObject implementations for instances
129
 * appropriate for @type.
Brian Cameron's avatar
Brian Cameron committed
130
 **/
Bill Haneman's avatar
Bill Haneman committed
131
132
133
134
135
136
137
138
139
140
141
142
void
atk_registry_set_factory_type (AtkRegistry *registry,
                               GType type,
                               GType factory_type)
{
  GType old_type;
  gpointer value;
  AtkObjectFactory *old_factory;

  g_return_if_fail (ATK_IS_REGISTRY (registry));

  value = g_hash_table_lookup (registry->factory_type_registry, 
143
144
                                  (gpointer) type);
  old_type = (GType) value;
Bill Haneman's avatar
Bill Haneman committed
145
146
147
  if (old_type && old_type != factory_type)
    {
      g_hash_table_remove (registry->factory_type_registry, 
148
                           (gpointer) type);
Bill Haneman's avatar
Bill Haneman committed
149
150
151
152
153
      /*
       * If the old factory was created, notify it that it has
       * been replaced, then free it.
       */
      old_factory = g_hash_table_lookup (registry->factory_singleton_cache, 
154
                                         (gpointer) old_type);
Bill Haneman's avatar
Bill Haneman committed
155
156
157
158
159
160
161
      if (old_factory)
        {
          atk_object_factory_invalidate (old_factory);
          g_type_free_instance ((GTypeInstance *) old_factory);
        }
    }
  g_hash_table_insert (registry->factory_type_registry, 
162
163
                       (gpointer) type, 
                       (gpointer) factory_type);
Bill Haneman's avatar
Bill Haneman committed
164
165
}

Brian Cameron's avatar
Brian Cameron committed
166
/**
167
168
169
 * atk_registry_get_factory_type:
 * @registry: an #AtkRegistry
 * @type: a #GType with which to look up the associated #AtkObjectFactory
Brian Cameron's avatar
Brian Cameron committed
170
171
 * subclass
 *
172
 * Provides a #GType indicating the #AtkObjectFactory subclass
Brian Cameron's avatar
Brian Cameron committed
173
 * associated with @type.
Brian Cameron's avatar
Brian Cameron committed
174
 *
175
 * Returns: a #GType associated with type @type
Brian Cameron's avatar
Brian Cameron committed
176
 **/
Bill Haneman's avatar
Bill Haneman committed
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
GType
atk_registry_get_factory_type (AtkRegistry *registry,
                               GType type)
{
  GType factory_type;
  gpointer value;

  /*
   * look up factory type in first hash;
   * if there isn't an explicitly registered factory type,
   * try inheriting one...
   */
  do {
    value =
        g_hash_table_lookup (registry->factory_type_registry, 
192
                             (gpointer) type);
Bill Haneman's avatar
Bill Haneman committed
193
194
195
196
197
198
199
    type = g_type_parent (type);
    if (type == G_TYPE_INVALID)
      {
        break;
      }
  } while (value == NULL);

200
  factory_type = (GType) value;
Bill Haneman's avatar
Bill Haneman committed
201
202
203
  return factory_type;
}

Brian Cameron's avatar
Brian Cameron committed
204
/**
205
206
207
 * atk_registry_get_factory:
 * @registry: an #AtkRegistry
 * @type: a #GType with which to look up the associated #AtkObjectFactory
Brian Cameron's avatar
Brian Cameron committed
208
 *
209
 * Gets an #AtkObjectFactory appropriate for creating #AtkObjects
210
 * appropriate for @type.
Brian Cameron's avatar
Brian Cameron committed
211
 *
212
213
 * Returns: (transfer none): an #AtkObjectFactory appropriate for creating
 * #AtkObjects appropriate for @type.
Brian Cameron's avatar
Brian Cameron committed
214
 **/
Bill Haneman's avatar
Bill Haneman committed
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
AtkObjectFactory*
atk_registry_get_factory (AtkRegistry *registry,
                          GType type)
{
  gpointer factory_pointer = NULL;
  GType factory_type;

  factory_type = atk_registry_get_factory_type (registry, type);

  if (factory_type == G_TYPE_INVALID)
  {
  /* Factory type has not been specified for this object type */
    static AtkObjectFactory* default_factory = NULL;

    if (!default_factory)
      default_factory = atk_no_op_object_factory_new ();

    return default_factory;
  }

  /* ask second hashtable for instance of factory type */
  factory_pointer =
        g_hash_table_lookup (registry->factory_singleton_cache, 
238
        (gpointer) factory_type);
Bill Haneman's avatar
Bill Haneman committed
239
240
241
242
243
244

  /* if there isn't one already, create one and save it */
  if (factory_pointer == NULL)
    {
      factory_pointer = g_type_create_instance (factory_type);
      g_hash_table_insert (registry->factory_singleton_cache,
245
                           (gpointer) factory_type,
Bill Haneman's avatar
Bill Haneman committed
246
247
248
249
250
251
                           factory_pointer);
    }

  return ATK_OBJECT_FACTORY (factory_pointer);
}

Brian Cameron's avatar
Brian Cameron committed
252
/**
253
 * atk_get_default_registry:
Brian Cameron's avatar
Brian Cameron committed
254
 *
255
 * Gets a default implementation of the #AtkObjectFactory/type
Brian Cameron's avatar
Brian Cameron committed
256
 * registry.
257
 * Note: For most toolkit maintainers, this will be the correct
Brian Cameron's avatar
Brian Cameron committed
258
259
260
 * registry for registering new #AtkObject factories. Following
 * a call to this function, maintainers may call atk_registry_set_factory_type()
 * to associate an #AtkObjectFactory subclass with the GType of objects
261
 * for whom accessibility information will be provided.
Brian Cameron's avatar
Brian Cameron committed
262
 *
263
264
 * Returns: (transfer full): a default implementation of the
 * #AtkObjectFactory/type registry
Brian Cameron's avatar
Brian Cameron committed
265
 **/
Bill Haneman's avatar
Bill Haneman committed
266
AtkRegistry*
267
atk_get_default_registry (void)
Bill Haneman's avatar
Bill Haneman committed
268
269
{
  if (!default_registry)
270
271
272
    {
      default_registry = atk_registry_new ();
    }
Bill Haneman's avatar
Bill Haneman committed
273
274
  return default_registry;
}