]> Pileus Git - ~andy/gtk/blob - gtk/gtkarg.c
documented necessary changes for 1.4 transition.
[~andy/gtk] / gtk / gtkarg.c
1 /* GTK - The GIMP Toolkit
2  * Copyright (C) 1995-1997 Peter Mattis, Spencer Kimball and Josh MacDonald
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 /*
21  * Modified by the GTK+ Team and others 1997-1999.  See the AUTHORS
22  * file for a list of people on the GTK+ Team.  See the ChangeLog
23  * files for a list of changes.  These files are distributed with
24  * GTK+ at ftp://ftp.gtk.org/pub/gtk/. 
25  */
26
27 #include <stdarg.h>
28 #include <string.h>
29 #include "gtkobject.h"
30 #include "gtkargcollector.c"
31
32
33 #define MAX_ARG_LENGTH  (256)
34
35
36 /* --- typedefs --- */
37 typedef struct _GtkArgQueryData GtkArgQueryData;
38
39
40 /* --- structures --- */
41 struct _GtkArgQueryData
42 {
43   GList *arg_list;
44   GtkType class_type;
45 };
46
47
48
49 /* --- functions --- */
50 GtkArgInfo*
51 gtk_arg_type_new_static (GtkType      base_class_type,
52                          const gchar *arg_name,
53                          guint        class_n_args_offset,
54                          GHashTable  *arg_info_hash_table,
55                          GtkType      arg_type,
56                          guint        arg_flags,
57                          guint        arg_id)
58 {
59   GtkArgInfo *info;
60   gchar class_part[MAX_ARG_LENGTH];
61   gchar *arg_part;
62   GtkType class_type;
63   guint class_offset;
64   guint *n_args_p;
65   gchar *p;
66
67   g_return_val_if_fail (arg_name != NULL, NULL);
68   g_return_val_if_fail (GTK_TYPE_IS_OBJECT (base_class_type), NULL);
69   g_return_val_if_fail (class_n_args_offset != 0, NULL);
70   g_return_val_if_fail (arg_info_hash_table != NULL, NULL);
71   g_return_val_if_fail (arg_type > GTK_TYPE_NONE, NULL);
72   g_return_val_if_fail (arg_id > 0, NULL);
73   g_return_val_if_fail ((arg_flags & GTK_ARG_READWRITE) != 0, NULL);
74   /* g_return_val_if_fail ((arg_flags & GTK_ARG_CHILD_ARG) == 0, NULL); */
75   
76   arg_flags &= GTK_ARG_MASK;
77
78   arg_part = strchr (arg_name, ':');
79   if (!arg_part || (arg_part[0] != ':') || (arg_part[1] != ':'))
80     {
81       g_warning ("gtk_arg_type_new(): invalid arg name: \"%s\"\n", arg_name);
82       return NULL;
83     }
84
85   class_offset = (guint) (arg_part - arg_name);
86   strncpy (class_part, arg_name, class_offset);
87   class_part[class_offset] = 0;
88
89   class_type = gtk_type_from_name (class_part);
90   if (!gtk_type_is_a (class_type, base_class_type))
91     {
92       g_warning ("gtk_arg_type_new(): argument class in \"%s\" is not in the `%s' ancestry",
93                  arg_name,
94                  gtk_type_name (base_class_type));
95       return NULL;
96     }
97
98   p = gtk_type_class (class_type);
99   p += class_n_args_offset;
100   n_args_p = (guint*) p;
101   *n_args_p += 1;
102
103   info = g_new (GtkArgInfo, 1);
104   info->class_type = class_type;
105   info->full_name = (gchar*) arg_name; /* _static */
106   info->name = info->full_name + class_offset + 2;
107   info->type = arg_type;
108   info->arg_flags = arg_flags;
109   info->arg_id = arg_id;
110   info->seq_id = *n_args_p;
111
112   g_hash_table_insert (arg_info_hash_table, info, info);
113
114   return info;
115 }
116
117 gchar*
118 gtk_arg_name_strip_type (const gchar   *arg_name)
119 {
120   gchar buffer[MAX_ARG_LENGTH];
121   gchar *p;
122
123   /* security audit
124    */
125   if (!arg_name || strlen (arg_name) > MAX_ARG_LENGTH - 8)
126     return NULL;
127
128   p = strchr (arg_name, ':');
129   if (p)
130     {
131       guint len;
132
133       if ((p[0] != ':') || (p[1] != ':') || (p[2] == 0))
134         return NULL;
135       len = (guint) (p - arg_name);
136       strncpy (buffer, arg_name, len);
137       buffer[len] = 0;
138
139       if (gtk_type_from_name (buffer) != GTK_TYPE_INVALID)
140         return p + 2;
141     }
142
143   return (gchar*) arg_name;
144 }
145
146 gchar*
147 gtk_arg_get_info (GtkType       object_type,
148                   GHashTable   *arg_info_hash_table,
149                   const gchar  *arg_name,
150                   GtkArgInfo  **info_p)
151 {
152   GtkType otype;
153   gchar buffer[MAX_ARG_LENGTH];
154   guint len;
155   gchar *p;
156   
157   *info_p = NULL;
158   
159   /* security audit
160    */
161   if (!arg_name || strlen (arg_name) > MAX_ARG_LENGTH - 8)
162     return g_strdup ("argument name exceeds maximum size.");
163
164   /* split off the object-type part
165    */
166   p = strchr (arg_name, ':');
167   if (p)
168     {
169       if ((p[0] != ':') || (p[1] != ':'))
170         return g_strconcat ("invalid argument syntax: \"",
171                             arg_name,
172                             "\"",
173                             NULL);
174       len = (guint) (p - arg_name);
175       strncpy (buffer, arg_name, len);
176       buffer[len] = 0;
177
178       otype = gtk_type_from_name (buffer);
179       if (otype != GTK_TYPE_INVALID)
180         arg_name = p + 2;
181     }
182   else
183     otype = GTK_TYPE_INVALID;
184
185   /* split off the argument name
186    */
187   p = strchr (arg_name, ':');
188   if (p)
189     {
190       if ((p[0] != ':') || (p[1] != ':'))
191         return g_strconcat ("invalid argument syntax: \"",
192                             arg_name,
193                             "\"",
194                             NULL);
195       len = (guint) (p - arg_name);
196       strncpy (buffer, arg_name, len);
197       buffer[len] = 0;
198       arg_name = buffer;
199     }
200
201   /* lookup the argument
202    */
203   if (otype != GTK_TYPE_INVALID)
204     {
205       GtkArgInfo info;
206
207       info.class_type = otype;
208       info.name = (gchar*) arg_name;
209
210       *info_p = g_hash_table_lookup (arg_info_hash_table, &info);
211       if (*info_p && !gtk_type_is_a (object_type, (*info_p)->class_type))
212         *info_p = NULL;
213     }
214   else
215     {
216       otype = object_type;
217       while (!*info_p && GTK_TYPE_IS_OBJECT (otype))
218         {
219           GtkArgInfo info;
220           
221           info.class_type = otype;
222           info.name = (gchar*) arg_name;
223           
224           *info_p = g_hash_table_lookup (arg_info_hash_table, &info);
225           
226           otype = gtk_type_parent (otype);
227         }
228     }
229   
230   if (!*info_p)
231     return g_strconcat ("could not find argument \"",
232                         arg_name,
233                         "\" in the `",
234                         gtk_type_name (object_type),
235                         "' class ancestry",
236                         NULL);
237
238   return NULL;
239 }
240
241 gchar*
242 gtk_args_collect (GtkType         object_type,
243                   GHashTable     *arg_info_hash_table,
244                   GSList        **arg_list_p,
245                   GSList        **info_list_p,
246                   const gchar   *first_arg_name,
247                   va_list        var_args)
248 {
249   GSList *arg_list;
250   GSList *info_list;
251   const gchar *arg_name;
252
253   g_return_val_if_fail (arg_list_p != NULL, NULL);
254   *arg_list_p = NULL;
255   g_return_val_if_fail (info_list_p != NULL, NULL);
256   *info_list_p = 0;
257   g_return_val_if_fail (arg_info_hash_table != NULL, NULL);
258
259   arg_list = NULL;
260   info_list = NULL;
261   arg_name = first_arg_name;
262   while (arg_name)
263     {
264       GtkArgInfo *info = NULL;
265       gchar *error;
266
267       error = gtk_arg_get_info (object_type, arg_info_hash_table, arg_name, &info);
268       if (!error)
269         {
270           GtkArg *arg;
271
272           info_list = g_slist_prepend (info_list, info);
273
274           arg = gtk_arg_new (info->type);
275           arg->name = (gchar*) arg_name;
276           GTK_ARG_COLLECT_VALUE (arg, var_args, error);
277           arg_list = g_slist_prepend (arg_list, arg);
278         }
279       if (error)
280         {
281           gtk_args_collect_cleanup (arg_list, info_list);
282
283           return error;
284         }
285
286       arg_name = va_arg (var_args, gchar*);
287     }
288
289   *arg_list_p = g_slist_reverse (arg_list);
290   *info_list_p = g_slist_reverse (info_list);
291
292   return NULL;
293 }
294
295 void
296 gtk_args_collect_cleanup (GSList        *arg_list,
297                           GSList        *info_list)
298 {
299   GSList *slist;
300   
301   g_slist_free (info_list);
302
303   for (slist = arg_list; slist; slist = slist->next)
304     gtk_arg_free (slist->data, FALSE);
305   g_slist_free (arg_list);
306 }
307
308 static void
309 gtk_args_query_foreach (gpointer key,
310                         gpointer value,
311                         gpointer user_data)
312 {
313   register GtkArgInfo *info;
314   register GtkArgQueryData *data;
315
316   g_assert (key == value); /* paranoid */
317
318   info = value;
319   data = user_data;
320
321   if (info->class_type == data->class_type)
322     data->arg_list = g_list_prepend (data->arg_list, info);
323 }
324
325 GtkArg*
326 gtk_args_query (GtkType     class_type,
327                 GHashTable *arg_info_hash_table,
328                 guint32   **arg_flags,
329                 guint      *n_args_p)
330 {
331   GtkArg *args;
332   GtkArgQueryData query_data;
333
334   if (arg_flags)
335     *arg_flags = NULL;
336   g_return_val_if_fail (n_args_p != NULL, NULL);
337   *n_args_p = 0;
338   g_return_val_if_fail (arg_info_hash_table != NULL, NULL);
339
340   /* make sure the types class has been initialized, because
341    * the argument setup happens in the gtk_*_class_init() functions.
342    */
343   gtk_type_class (class_type);
344
345   query_data.arg_list = NULL;
346   query_data.class_type = class_type;
347   g_hash_table_foreach (arg_info_hash_table, gtk_args_query_foreach, &query_data);
348
349   if (query_data.arg_list)
350     {
351       register GList    *list;
352       register guint    len;
353
354       list = query_data.arg_list;
355       len = 1;
356       while (list->next)
357         {
358           len++;
359           list = list->next;
360         }
361
362       args = g_new0 (GtkArg, len);
363       *n_args_p = len;
364       if (arg_flags)
365         *arg_flags = g_new (guint32, len);
366
367       do
368         {
369           GtkArgInfo *info;
370
371           info = list->data;
372           list = list->prev;
373
374           g_assert (info->seq_id > 0 && info->seq_id <= len); /* paranoid */
375
376           args[info->seq_id - 1].type = info->type;
377           args[info->seq_id - 1].name = info->full_name;
378           if (arg_flags)
379             (*arg_flags)[info->seq_id - 1] = info->arg_flags;
380         }
381       while (list);
382
383       g_list_free (query_data.arg_list);
384     }
385   else
386     args = NULL;
387
388   return args;
389 }
390
391 GtkArg*
392 gtk_arg_new (GtkType  arg_type)
393 {
394   GtkArg *arg;
395
396   arg = g_new0 (GtkArg, 1);
397   arg->type = arg_type;
398   arg->name = NULL;
399
400   return arg;
401 }
402
403 GtkArg*
404 gtk_arg_copy (GtkArg         *src_arg,
405               GtkArg         *dest_arg)
406 {
407   g_return_val_if_fail (src_arg != NULL, NULL);
408
409   if (!dest_arg)
410     {
411       dest_arg = g_new0 (GtkArg, 1);
412       dest_arg->name = src_arg->name;
413     }
414
415   dest_arg->type = src_arg->type;
416   dest_arg->d = src_arg->d;
417
418   if (GTK_FUNDAMENTAL_TYPE (src_arg->type) == GTK_TYPE_STRING)
419     GTK_VALUE_STRING (*dest_arg) = g_strdup (GTK_VALUE_STRING (*src_arg));
420
421   return dest_arg;
422 }
423
424 void
425 gtk_arg_free (GtkArg  *arg,
426               gboolean free_contents)
427 {
428   g_return_if_fail (arg != NULL);
429
430   if (free_contents)
431     gtk_arg_reset (arg);
432   g_free (arg);
433 }
434
435 void
436 gtk_arg_reset (GtkArg *arg)
437 {
438   GtkType fundamental_type;
439
440   g_return_if_fail (arg != NULL);
441
442   fundamental_type = GTK_FUNDAMENTAL_TYPE (arg->type);
443
444   if (fundamental_type == GTK_TYPE_STRING)
445     {
446       g_free (GTK_VALUE_STRING (*arg));
447       arg->type = GTK_TYPE_INVALID;
448     }
449   else if (arg->type != GTK_TYPE_INVALID)
450     arg->type = GTK_TYPE_INVALID;
451 }
452
453 gint
454 gtk_arg_info_equal (gconstpointer arg_info_1,
455                     gconstpointer arg_info_2)
456 {
457   register const GtkArgInfo *info1 = arg_info_1;
458   register const GtkArgInfo *info2 = arg_info_2;
459   
460   return ((info1->class_type == info2->class_type) &&
461           strcmp (info1->name, info2->name) == 0);
462 }
463
464 guint
465 gtk_arg_info_hash (gconstpointer arg_info)
466 {
467   register const GtkArgInfo *info = arg_info;
468   register const gchar *p;
469   register guint h = info->class_type >> 8;
470   
471   for (p = info->name; *p; p++)
472     {
473       register guint g;
474       
475       h = (h << 4) + *p;
476       g = h & 0xf0000000;
477       if (g)
478         {
479           h = h ^ (g >> 24);
480           h = h ^ g;
481         }
482     }
483   
484   return h;
485 }
486
487 gboolean
488 gtk_arg_values_equal (const GtkArg *arg1,
489                       const GtkArg *arg2)
490 {
491   GtkType fundamental_type;
492   gboolean equal;
493   
494   g_return_val_if_fail (arg1 != NULL, FALSE);
495   g_return_val_if_fail (arg2 != NULL, FALSE);
496   g_return_val_if_fail (GTK_FUNDAMENTAL_TYPE (arg1->type) ==
497                         GTK_FUNDAMENTAL_TYPE (arg2->type), FALSE);
498   
499   fundamental_type = GTK_FUNDAMENTAL_TYPE (arg1->type);
500   
501   switch (fundamental_type)
502     {
503     case GTK_TYPE_INVALID:
504       equal = TRUE;
505       break;
506     case GTK_TYPE_CHAR:
507       equal = GTK_VALUE_CHAR (*arg1) == GTK_VALUE_CHAR (*arg2);
508       break;
509     case GTK_TYPE_BOOL:
510       equal = (GTK_VALUE_BOOL (*arg1) != FALSE) == (GTK_VALUE_BOOL (*arg2) != FALSE);
511       break;
512     case GTK_TYPE_INT:
513       equal = GTK_VALUE_INT (*arg1) == GTK_VALUE_INT (*arg2);
514       break;
515     case GTK_TYPE_UINT:
516       equal = GTK_VALUE_UINT (*arg1) == GTK_VALUE_UINT (*arg2);
517       break;
518     case GTK_TYPE_LONG:
519       equal = GTK_VALUE_LONG (*arg1) == GTK_VALUE_LONG (*arg2);
520       break;
521     case GTK_TYPE_ULONG:
522       equal = GTK_VALUE_ULONG (*arg1) == GTK_VALUE_ULONG (*arg2);
523       break;
524     case GTK_TYPE_FLOAT:
525       equal = GTK_VALUE_FLOAT (*arg1) == GTK_VALUE_FLOAT (*arg2);
526       break;
527     case GTK_TYPE_DOUBLE:
528       equal = GTK_VALUE_DOUBLE (*arg1) == GTK_VALUE_DOUBLE (*arg2);
529       break;
530     case GTK_TYPE_STRING:
531       if (!GTK_VALUE_STRING (*arg1) ||
532           !GTK_VALUE_STRING (*arg2))
533         equal = GTK_VALUE_STRING (*arg1) == GTK_VALUE_STRING (*arg2);
534       else
535         equal = g_str_equal (GTK_VALUE_STRING (*arg1), GTK_VALUE_STRING (*arg2));
536       break;
537     case GTK_TYPE_ENUM:
538       equal = GTK_VALUE_ENUM (*arg1) == GTK_VALUE_ENUM (*arg2);
539       break;
540     case GTK_TYPE_FLAGS:
541       equal = GTK_VALUE_FLAGS (*arg1) == GTK_VALUE_FLAGS (*arg2);
542       break;
543     case GTK_TYPE_BOXED:
544       equal = GTK_VALUE_BOXED (*arg1) == GTK_VALUE_BOXED (*arg2);
545       break;
546     case G_TYPE_OBJECT:
547       equal = GTK_VALUE_OBJECT (*arg1) == GTK_VALUE_OBJECT (*arg2);
548       break;
549     case GTK_TYPE_POINTER:
550       equal = GTK_VALUE_POINTER (*arg1) == GTK_VALUE_POINTER (*arg2);
551       break;
552     case GTK_TYPE_SIGNAL:
553       equal = (GTK_VALUE_SIGNAL (*arg1).f == GTK_VALUE_SIGNAL (*arg2).f &&
554                GTK_VALUE_SIGNAL (*arg1).d == GTK_VALUE_SIGNAL (*arg2).d);
555       break;
556     default:
557       g_warning ("gtk_arg_values_equal() used with unknown type `%s'", gtk_type_name (arg1->type));
558       equal = FALSE;
559       break;
560     }
561   
562   return equal;
563 }
564
565 void
566 gtk_arg_to_valueloc (GtkArg  *arg,
567                      gpointer value_pointer)
568 {
569   GtkType fundamental_type;
570   
571   g_return_if_fail (arg != NULL);
572   g_return_if_fail (value_pointer != NULL);
573   
574   fundamental_type = GTK_FUNDAMENTAL_TYPE (arg->type);
575   
576   switch (fundamental_type)
577     {
578       gchar *p_char;
579       guchar *p_uchar;
580       gboolean *p_boolean;
581       gint *p_int;
582       guint *p_uint;
583       glong *p_long;
584       gulong *p_ulong;
585       gfloat *p_float;
586       gdouble *p_double;
587       gpointer *p_pointer;
588     case GTK_TYPE_CHAR:
589       p_char = value_pointer;
590       *p_char = GTK_VALUE_CHAR (*arg);
591       break;
592     case GTK_TYPE_UCHAR:
593       p_uchar = value_pointer;
594       *p_uchar = GTK_VALUE_UCHAR (*arg);
595       break;
596     case GTK_TYPE_BOOL:
597       p_boolean = value_pointer;
598       *p_boolean = GTK_VALUE_BOOL (*arg);
599       break;
600     case GTK_TYPE_INT:
601     case GTK_TYPE_ENUM:
602       p_int = value_pointer;
603       *p_int = GTK_VALUE_INT (*arg);
604       break;
605     case GTK_TYPE_UINT:
606     case GTK_TYPE_FLAGS:
607       p_uint = value_pointer;
608       *p_uint = GTK_VALUE_UINT (*arg);
609       break;
610     case GTK_TYPE_LONG:
611       p_long = value_pointer;
612       *p_long = GTK_VALUE_LONG (*arg);
613       break;
614     case GTK_TYPE_ULONG:
615       p_ulong = value_pointer;
616       *p_ulong = GTK_VALUE_ULONG (*arg);
617       break;
618     case GTK_TYPE_FLOAT:
619       p_float = value_pointer;
620       *p_float = GTK_VALUE_FLOAT (*arg);
621       break;
622     case GTK_TYPE_DOUBLE:
623       p_double = value_pointer;
624       *p_double = GTK_VALUE_DOUBLE (*arg);
625       break;
626     case GTK_TYPE_STRING:
627     case GTK_TYPE_POINTER:
628     case GTK_TYPE_BOXED:
629     case G_TYPE_OBJECT:
630       p_pointer = value_pointer;
631       *p_pointer = GTK_VALUE_POINTER (*arg);
632       break;
633     case GTK_TYPE_SIGNAL:
634     case GTK_TYPE_NONE:
635     case GTK_TYPE_INVALID:
636       /* it doesn't make much sense to retrive these values,
637        * they either are always read-only args, or require
638        * multiple pointers.
639        */
640       g_warning ("gtk_arg_fill_retloc(): unsupported argument type `%s'",
641                  gtk_type_name (arg->type));
642       break;
643     }
644 }