]> Pileus Git - ~andy/gtk/blob - gtk/gtktexttagtable.c
to simplify parsing for exported functions: - made implementation
[~andy/gtk] / gtk / gtktexttagtable.c
1
2 #include "gtktexttagtable.h"
3 #include "gtksignal.h"
4
5 #include <stdlib.h>
6
7 enum {
8   TAG_CHANGED,
9   TAG_ADDED,
10   TAG_REMOVED,
11   LAST_SIGNAL
12 };
13
14 enum {
15   LAST_ARG
16 };
17
18 static void gtk_text_tag_table_init         (GtkTextTagTable      *table);
19 static void gtk_text_tag_table_class_init   (GtkTextTagTableClass *klass);
20 static void gtk_text_tag_table_finalize     (GObject              *object);
21 static void gtk_text_tag_table_set_property (GObject              *object,
22                                              guint                 prop_id,
23                                              const GValue         *value,
24                                              GParamSpec           *pspec);
25 static void gtk_text_tag_table_get_property (GObject              *object,
26                                              guint                 prop_id,
27                                              GValue               *value,
28                                              GParamSpec           *pspec);
29
30 static GObjectClass *parent_class = NULL;
31 static guint signals[LAST_SIGNAL] = { 0 };
32
33 GType
34 gtk_text_tag_table_get_type (void)
35 {
36   static GType our_type = 0;
37
38   if (our_type == 0)
39     {
40       static const GTypeInfo our_info =
41       {
42         sizeof (GtkTextTagTableClass),
43         (GBaseInitFunc) NULL,
44         (GBaseFinalizeFunc) NULL,
45         (GClassInitFunc) gtk_text_tag_table_class_init,
46         NULL,           /* class_finalize */
47         NULL,           /* class_data */
48         sizeof (GtkTextTagTable),
49         0,              /* n_preallocs */
50         (GInstanceInitFunc) gtk_text_tag_table_init
51       };
52
53       our_type = g_type_register_static (G_TYPE_OBJECT,
54                                          "GtkTextTagTable",
55                                          &our_info,
56                                          0);
57     }
58
59   return our_type;
60 }
61
62 static void
63 gtk_text_tag_table_class_init (GtkTextTagTableClass *klass)
64 {
65   GObjectClass *object_class = G_OBJECT_CLASS (klass);
66
67   parent_class = g_type_class_peek_parent (klass);
68
69   object_class->set_property = gtk_text_tag_table_set_property;
70   object_class->get_property = gtk_text_tag_table_get_property;
71   
72   object_class->finalize = gtk_text_tag_table_finalize;
73   
74   signals[TAG_CHANGED] =
75     g_signal_new ("tag_changed",
76                   G_OBJECT_CLASS_TYPE (object_class),
77                   G_SIGNAL_RUN_LAST,
78                   G_STRUCT_OFFSET (GtkTextTagTableClass, tag_changed),
79                   NULL, NULL,
80                   gtk_marshal_VOID__OBJECT_BOOLEAN,
81                   G_TYPE_NONE,
82                   2,
83                   G_TYPE_OBJECT,
84                   G_TYPE_BOOLEAN);  
85
86   signals[TAG_ADDED] =
87     g_signal_new ("tag_added",
88                   GTK_CLASS_TYPE (object_class),
89                   G_SIGNAL_RUN_LAST,
90                   G_STRUCT_OFFSET (GtkTextTagTableClass, tag_added),
91                   NULL, NULL,
92                   gtk_marshal_VOID__OBJECT,
93                   GTK_TYPE_NONE,
94                   1,
95                   G_TYPE_OBJECT);
96
97   signals[TAG_REMOVED] =
98     g_signal_new ("tag_removed",                   
99                   GTK_CLASS_TYPE (object_class),
100                   G_SIGNAL_RUN_LAST,
101                   G_STRUCT_OFFSET (GtkTextTagTableClass, tag_removed),
102                   NULL, NULL,
103                   gtk_marshal_VOID__OBJECT,
104                   GTK_TYPE_NONE,
105                   1,
106                   G_TYPE_OBJECT);
107 }
108
109 static void
110 gtk_text_tag_table_init (GtkTextTagTable *table)
111 {
112   table->hash = g_hash_table_new (g_str_hash, g_str_equal);
113 }
114
115 /**
116  * gtk_text_tag_table_new:
117  * 
118  * Creates a new #GtkTextTagTable. The table contains no tags by
119  * default.
120  * 
121  * Return value: a new #GtkTextTagTable
122  **/
123 GtkTextTagTable*
124 gtk_text_tag_table_new (void)
125 {
126   GtkTextTagTable *table;
127
128   table = GTK_TEXT_TAG_TABLE (g_object_new (gtk_text_tag_table_get_type (), NULL));
129
130   return table;
131 }
132
133 static void
134 foreach_unref (GtkTextTag *tag, gpointer data)
135 {
136   /* We don't want to emit the remove signal here; so we just unparent
137    * and unref the tag.
138    */
139
140   tag->table = NULL;
141   g_object_unref (G_OBJECT (tag));
142 }
143
144 static void
145 gtk_text_tag_table_finalize (GObject *object)
146 {
147   GtkTextTagTable *table;
148
149   table = GTK_TEXT_TAG_TABLE (object);
150
151   gtk_text_tag_table_foreach (table, foreach_unref, NULL);
152
153   g_hash_table_destroy (table->hash);
154   g_slist_free (table->anonymous);
155
156   (* G_OBJECT_CLASS (parent_class)->finalize) (object);
157 }
158 static void
159 gtk_text_tag_table_set_property (GObject      *object,
160                                  guint         prop_id,
161                                  const GValue *value,
162                                  GParamSpec   *pspec)
163 {
164   GtkTextTagTable *table;
165
166   table = GTK_TEXT_TAG_TABLE (object);
167
168   switch (prop_id)
169     {
170
171     default:
172       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
173       break;
174     }
175 }
176
177
178 static void
179 gtk_text_tag_table_get_property (GObject      *object,
180                                  guint         prop_id,
181                                  GValue       *value,
182                                  GParamSpec   *pspec)
183 {
184   GtkTextTagTable *table;
185
186   table = GTK_TEXT_TAG_TABLE (object);
187
188   switch (prop_id)
189     {
190
191     default:
192       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
193       break;
194     }
195 }
196
197 /**
198  * gtk_text_tag_table_add:
199  * @table: a #GtkTextTagTable
200  * @tag: a #GtkTextTag
201  *
202  * Add a tag to the table. The tag is assigned the highest priority
203  * in the table.
204  *
205  * @tag must not be in a tag table already, and may not have
206  * the same name as an already-added tag.
207  **/
208 void
209 gtk_text_tag_table_add (GtkTextTagTable *table,
210                         GtkTextTag      *tag)
211 {
212   guint size;
213
214   g_return_if_fail (GTK_IS_TEXT_TAG_TABLE (table));
215   g_return_if_fail (GTK_IS_TEXT_TAG (tag));
216   g_return_if_fail (tag->table == NULL);
217
218   if (tag->name && g_hash_table_lookup (table->hash, tag->name))
219     {
220       g_warning ("A tag named '%s' is already in the tag table.",
221                  tag->name);
222       return;
223     }
224   
225   g_object_ref (G_OBJECT (tag));
226
227   if (tag->name)
228     g_hash_table_insert (table->hash, tag->name, tag);
229   else
230     {
231       table->anonymous = g_slist_prepend (table->anonymous, tag);
232       table->anon_count += 1;
233     }
234
235   tag->table = table;
236
237   /* We get the highest tag priority, as the most-recently-added
238      tag. Note that we do NOT use gtk_text_tag_set_priority,
239      as it assumes the tag is already in the table. */
240   size = gtk_text_tag_table_get_size (table);
241   g_assert (size > 0);
242   tag->priority = size - 1;
243
244   g_signal_emit (G_OBJECT (table), signals[TAG_ADDED], 0, tag);
245 }
246
247 /**
248  * gtk_text_tag_table_lookup:
249  * @table: a #GtkTextTagTable 
250  * @name: name of a tag
251  * 
252  * Look up a named tag.
253  * 
254  * Return value: The tag, or %NULL if none by that name is in the table.
255  **/
256 GtkTextTag*
257 gtk_text_tag_table_lookup (GtkTextTagTable *table,
258                            const gchar     *name)
259 {
260   g_return_val_if_fail (GTK_IS_TEXT_TAG_TABLE (table), NULL);
261   g_return_val_if_fail (name != NULL, NULL);
262
263   return g_hash_table_lookup (table->hash, name);
264 }
265
266 /**
267  * gtk_text_tag_table_remove:
268  * @table: a #GtkTextTagTable
269  * @tag: a #GtkTextTag
270  * 
271  * Remove a tag from the table. This will remove the table's
272  * reference to the tag, so be careful - the tag will end
273  * up destroyed if you don't have a reference to it.
274  **/
275 void
276 gtk_text_tag_table_remove (GtkTextTagTable *table,
277                            GtkTextTag      *tag)
278 {
279   g_return_if_fail (GTK_IS_TEXT_TAG_TABLE (table));
280   g_return_if_fail (GTK_IS_TEXT_TAG (tag));
281   g_return_if_fail (tag->table == table);
282
283   /* Set ourselves to the highest priority; this means
284      when we're removed, there won't be any gaps in the
285      priorities of the tags in the table. */
286   gtk_text_tag_set_priority (tag, gtk_text_tag_table_get_size (table) - 1);
287
288   tag->table = NULL;
289
290   if (tag->name)
291     g_hash_table_remove (table->hash, tag->name);
292   else
293     {
294       table->anonymous = g_slist_remove (table->anonymous, tag);
295       table->anon_count -= 1;
296     }
297
298   g_signal_emit (G_OBJECT (table), signals[TAG_REMOVED], 0, tag);
299
300   g_object_unref (G_OBJECT (tag));
301 }
302
303 struct ForeachData
304 {
305   GtkTextTagTableForeach func;
306   gpointer data;
307 };
308
309 static void
310 hash_foreach (gpointer key, gpointer value, gpointer data)
311 {
312   struct ForeachData *fd = data;
313
314   g_return_if_fail (GTK_IS_TEXT_TAG (value));
315
316   (* fd->func) (value, fd->data);
317 }
318
319 static void
320 list_foreach (gpointer data, gpointer user_data)
321 {
322   struct ForeachData *fd = user_data;
323
324   g_return_if_fail (GTK_IS_TEXT_TAG (data));
325
326   (* fd->func) (data, fd->data);
327 }
328
329 /**
330  * gtk_text_tag_table_foreach:
331  * @table: a #GtkTextTagTable
332  * @func: a function to call on each tag
333  * @data: user data
334  *
335  * Calls @func on each tag in @table, with user data @data.
336  * 
337  **/
338 void
339 gtk_text_tag_table_foreach (GtkTextTagTable       *table,
340                             GtkTextTagTableForeach func,
341                             gpointer               data)
342 {
343   struct ForeachData d;
344
345   g_return_if_fail (GTK_IS_TEXT_TAG_TABLE (table));
346   g_return_if_fail (func != NULL);
347
348   d.func = func;
349   d.data = data;
350
351   g_hash_table_foreach (table->hash, hash_foreach, &d);
352   g_slist_foreach (table->anonymous, list_foreach, &d);
353 }
354
355 /**
356  * gtk_text_tag_table_get_size:
357  * @table: a #GtkTextTagTable
358  * 
359  * Returns the size of the table (number of tags)
360  * 
361  * Return value: number of tags in @table
362  **/
363 gint
364 gtk_text_tag_table_get_size (GtkTextTagTable *table)
365 {
366   g_return_val_if_fail (GTK_IS_TEXT_TAG_TABLE (table), 0);
367
368   return g_hash_table_size (table->hash) + table->anon_count;
369 }