]> Pileus Git - ~andy/gtk/blob - gtk/gtktexttagtable.c
marshaller fixes.
[~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_newc ("tag_changed",
76                    G_OBJECT_CLASS_TYPE (object_class),
77                    G_SIGNAL_RUN_LAST,
78                    G_STRUCT_OFFSET (GtkTextTagTableClass, tag_changed),
79                    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_newc ("tag_added",
88                    GTK_CLASS_TYPE (object_class),
89                    G_SIGNAL_RUN_LAST,
90                    G_STRUCT_OFFSET (GtkTextTagTableClass, tag_added),
91                    NULL,
92                    gtk_marshal_VOID__OBJECT,
93                    GTK_TYPE_NONE,
94                    1,
95                    G_TYPE_OBJECT);
96
97   signals[TAG_REMOVED] =
98     g_signal_newc ("tag_removed",                   
99                    GTK_CLASS_TYPE (object_class),
100                    G_SIGNAL_RUN_LAST,
101                    G_STRUCT_OFFSET (GtkTextTagTableClass, tag_removed),
102                    NULL,
103                    gtk_marshal_VOID__OBJECT,
104                    GTK_TYPE_NONE,
105                    1,
106                    G_TYPE_OBJECT);
107 }
108
109 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  **/
206 void
207 gtk_text_tag_table_add (GtkTextTagTable *table,
208                         GtkTextTag      *tag)
209 {
210   guint size;
211
212   g_return_if_fail (GTK_IS_TEXT_TAG_TABLE (table));
213   g_return_if_fail (GTK_IS_TEXT_TAG (tag));
214   g_return_if_fail (tag->name == NULL ||
215                     g_hash_table_lookup (table->hash, tag->name) == NULL);
216   g_return_if_fail (tag->table == NULL);
217
218   g_object_ref (G_OBJECT (tag));
219
220   if (tag->name)
221     g_hash_table_insert (table->hash, tag->name, tag);
222   else
223     {
224       table->anonymous = g_slist_prepend (table->anonymous, tag);
225       table->anon_count += 1;
226     }
227
228   tag->table = table;
229
230   /* We get the highest tag priority, as the most-recently-added
231      tag. Note that we do NOT use gtk_text_tag_set_priority,
232      as it assumes the tag is already in the table. */
233   size = gtk_text_tag_table_size (table);
234   g_assert (size > 0);
235   tag->priority = size - 1;
236
237   g_signal_emit (G_OBJECT (table), signals[TAG_ADDED], 0, tag);
238 }
239
240 /**
241  * gtk_text_tag_table_lookup:
242  * @table: a #GtkTextTagTable 
243  * @name: name of a tag
244  * 
245  * Look up a named tag.
246  * 
247  * Return value: The tag, or %NULL if none by that name is in the table.
248  **/
249 GtkTextTag*
250 gtk_text_tag_table_lookup (GtkTextTagTable *table,
251                            const gchar     *name)
252 {
253   g_return_val_if_fail (GTK_IS_TEXT_TAG_TABLE (table), NULL);
254   g_return_val_if_fail (name != NULL, NULL);
255
256   return g_hash_table_lookup (table->hash, name);
257 }
258
259 /**
260  * gtk_text_tag_table_remove:
261  * @table: a #GtkTextTagTable
262  * @tag: a #GtkTextTag
263  * 
264  * Remove a tag from the table. This will remove the table's
265  * reference to the tag, so be careful - the tag will end
266  * up destroyed if you don't have a reference to it.
267  **/
268 void
269 gtk_text_tag_table_remove (GtkTextTagTable *table,
270                            GtkTextTag      *tag)
271 {
272   g_return_if_fail (GTK_IS_TEXT_TAG_TABLE (table));
273   g_return_if_fail (GTK_IS_TEXT_TAG (tag));
274   g_return_if_fail (tag->table == table);
275
276   /* Set ourselves to the highest priority; this means
277      when we're removed, there won't be any gaps in the
278      priorities of the tags in the table. */
279   gtk_text_tag_set_priority (tag, gtk_text_tag_table_size (table) - 1);
280
281   tag->table = NULL;
282
283   if (tag->name)
284     g_hash_table_remove (table->hash, tag->name);
285   else
286     {
287       table->anonymous = g_slist_remove (table->anonymous, tag);
288       table->anon_count -= 1;
289     }
290
291   g_signal_emit (G_OBJECT (table), signals[TAG_REMOVED], 0, tag);
292
293   g_object_unref (G_OBJECT (tag));
294 }
295
296 struct ForeachData
297 {
298   GtkTextTagTableForeach func;
299   gpointer data;
300 };
301
302 static void
303 hash_foreach (gpointer key, gpointer value, gpointer data)
304 {
305   struct ForeachData *fd = data;
306
307   g_return_if_fail (GTK_IS_TEXT_TAG (value));
308
309   (* fd->func) (value, fd->data);
310 }
311
312 static void
313 list_foreach (gpointer data, gpointer user_data)
314 {
315   struct ForeachData *fd = user_data;
316
317   g_return_if_fail (GTK_IS_TEXT_TAG (data));
318
319   (* fd->func) (data, fd->data);
320 }
321
322 /**
323  * gtk_text_tag_table_foreach:
324  * @table: a #GtkTextTagTable
325  * @func: a function to call on each tag
326  * @data: user data
327  *
328  * Calls @func on each tag in @table, with user data @data.
329  * 
330  **/
331 void
332 gtk_text_tag_table_foreach (GtkTextTagTable       *table,
333                             GtkTextTagTableForeach func,
334                             gpointer               data)
335 {
336   struct ForeachData d;
337
338   g_return_if_fail (GTK_IS_TEXT_TAG_TABLE (table));
339   g_return_if_fail (func != NULL);
340
341   d.func = func;
342   d.data = data;
343
344   g_hash_table_foreach (table->hash, hash_foreach, &d);
345   g_slist_foreach (table->anonymous, list_foreach, &d);
346 }
347
348 /**
349  * gtk_text_tag_table_size:
350  * @table: a #GtkTextTagTable
351  * 
352  * Returns the size of the table (number of tags)
353  * 
354  * Return value: number of tags in @table
355  **/
356 gint
357 gtk_text_tag_table_size (GtkTextTagTable *table)
358 {
359   g_return_val_if_fail (GTK_IS_TEXT_TAG_TABLE (table), 0);
360
361   return g_hash_table_size (table->hash) + table->anon_count;
362 }