1 /*
2  * Copyright (C) 2001 Ximian, Inc.
3  *
4  * This program is free software; you can redistribute it and/or modify
5  * it under the terms of the GNU General Public License as
6  * published by the Free Software Foundation; either version 2 of the
7  * License, or (at your option) any later version.
8  *
9  * This program 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
12  * GNU General Public License for more details.
13  *
14  * You should have received a copy of the GNU General Public License
15  * along with this program; if not, write to the Free Software
16  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
17  *
18  * Authors:
19  *   Tristan Van Berkom <tvb@gnome.org>
20  */
21 
22 #include <config.h>
23 
24 /**
25  * SECTION:glade-widget-adaptor
26  * @Short_Description: Adaptor base class to add runtime support for each widget class.
27  *
28  * The #GladeWidgetAdaptor object is a proxy for widget class support in Glade.
29  * it is automatically generated from the xml and allows you to override its
30  * methods in the plugin library for fine grained support on how you load/save
31  * widgets and handle thier properties in the runtime and more.
32  *
33  */
34 
35 #include "glade.h"
36 #include "glade-widget-adaptor.h"
37 #include "glade-xml-utils.h"
38 #include "glade-property-class.h"
39 #include "glade-signal.h"
40 #include "glade-marshallers.h"
41 #include "glade-accumulators.h"
42 #include "glade-displayable-values.h"
43 #include "glade-editor-table.h"
44 #include "glade-cursor.h"
45 #include "glade-private.h"
46 
47 /* For g_file_exists */
48 #include <sys/types.h>
49 #include <string.h>
50 
51 #include <glib.h>
52 #include <glib/gi18n-lib.h>
53 #include <gmodule.h>
54 #include <ctype.h>
55 
56 #define DEFAULT_ICON_NAME "widget-gtk-frame"
57 
58 struct _GladeWidgetAdaptorPrivate
59 {
60   GType        type;                /* GType of the widget */
61   GType        real_type;
62 
63   gchar       *name;                /* Name of the widget, for example GtkButton */
64   gchar       *generic_name;        /* Used to generate names of new widgets, for
65 				     * example "button" so that we generate button1,
66 				     * button2, buttonX ..
67 				     */
68   gchar       *icon_name;           /* icon name to use for widget class */
69   gchar       *missing_icon;        /* the name of the missing icon if it was not found */
70 
71   gchar       *title;               /* Translated class name used in the UI */
72   GList       *properties;          /* List of GladePropertyClass objects.
73 				     * [see glade-property.h] this list contains
74 				     * properties about the widget that we are going
75 				     * to modify. Like "title", "label", "rows" .
76 				     * Each property creates an input in the propety
77 				     * editor.
78 				     */
79   GList       *packing_props;       /* List of GladePropertyClass objects that describe
80 				     * properties for child objects packing definition -
81 				     * note there may be more than one type of child supported
82 				     * by a widget and thus they may have different sets
83 				     * of properties for each type - this association is
84 				     * managed on the GladePropertyClass proper.
85 				     */
86   GList       *signals;              /* List of GladeSignalClass objects */
87   GList       *child_packings;       /* Default packing property values */
88   GList       *actions;              /* A list of GWActionClass */
89   GList       *packing_actions;      /* A list of GWActionClass for child objects */
90   GList       *internal_children;    /* A list of GladeInternalChild */
91   gchar       *catalog;              /* The name of the widget catalog this class
92 				      * was declared by.
93 				      */
94   gchar       *book;                 /* DevHelp search namespace for this widget class
95 				      */
96 
97   GdkCursor   *cursor;                /* a cursor for inserting widgets */
98 
99   gchar       *special_child_type;    /* Special case code for children that
100 				       * are special children (like notebook tab
101 				       * widgets for example).
102 				       */
103   gboolean     query;                 /* Do we have to query the user, see glade_widget_adaptor_query() */
104 };
105 
106 struct _GladeChildPacking
107 {
108   gchar *parent_name;
109   GList *packing_defaults;
110 };
111 
112 
113 struct _GladePackingDefault
114 {
115   gchar *id;
116   gchar *value;
117 };
118 
119 struct _GladeInternalChild
120 {
121   gchar *name;
122   gboolean anarchist;
123   GList *children;
124 };
125 
126 enum
127 {
128   PROP_0,
129   PROP_NAME,
130   PROP_TYPE,
131   PROP_TITLE,
132   PROP_GENERIC_NAME,
133   PROP_ICON_NAME,
134   PROP_CATALOG,
135   PROP_BOOK,
136   PROP_SPECIAL_TYPE,
137   PROP_CURSOR,
138   PROP_QUERY
139 };
140 
141 typedef struct _GladeChildPacking GladeChildPacking;
142 typedef struct _GladePackingDefault GladePackingDefault;
143 typedef struct _GladeInternalChild GladeInternalChild;
144 
145 static GHashTable *adaptor_hash = NULL;
146 
147 /* This object used to be registered as GladeGObjectAdaptor but there is
148  * no reason for it since the autogenerated class for GtWidget is GladeGtkWidgetAdaptor
149  * TODO: rename GladeWidgetAdaptor to GladeGObjectAdator or GladeObjectAdator
150  */
151 G_DEFINE_TYPE_WITH_PRIVATE (GladeWidgetAdaptor, glade_widget_adaptor, G_TYPE_OBJECT);
152 
153 /*******************************************************************************
154                               Helper functions
155  *******************************************************************************/
156 
157 static void
gwa_create_cursor(GladeWidgetAdaptor * adaptor)158 gwa_create_cursor (GladeWidgetAdaptor *adaptor)
159 {
160   GdkPixbuf *tmp_pixbuf, *widget_pixbuf;
161   const GdkPixbuf *add_pixbuf;
162   GdkDisplay *display;
163   GError *error = NULL;
164 
165   /* only certain widget classes need to have cursors */
166   if (G_TYPE_IS_INSTANTIATABLE (adaptor->priv->type) == FALSE ||
167       G_TYPE_IS_ABSTRACT (adaptor->priv->type) != FALSE ||
168       adaptor->priv->generic_name == NULL)
169     return;
170 
171   /* cannot continue if 'add widget' cursor pixbuf has not been loaded for any reason */
172   if ((add_pixbuf = glade_cursor_get_add_widget_pixbuf ()) == NULL)
173     return;
174 
175   display = gdk_display_get_default ();
176 
177   /* create a temporary pixbuf clear to transparent black */
178   tmp_pixbuf = gdk_pixbuf_new (GDK_COLORSPACE_RGB, TRUE, 8, 32, 32);
179   gdk_pixbuf_fill (tmp_pixbuf, 0x00000000);
180 
181   if (gtk_icon_theme_has_icon
182       (gtk_icon_theme_get_default (), adaptor->priv->icon_name))
183     {
184       widget_pixbuf = gtk_icon_theme_load_icon (gtk_icon_theme_get_default (),
185                                                 adaptor->priv->icon_name,
186                                                 22, 0, &error);
187 
188       if (error)
189         {
190           g_warning ("Could not load image data for named icon '%s': %s",
191                      adaptor->priv->icon_name, error->message);
192           g_error_free (error);
193           return;
194         }
195 
196     }
197   else
198     {
199       return;
200     }
201 
202   /* composite pixbufs */
203   gdk_pixbuf_composite (widget_pixbuf, tmp_pixbuf,
204                         8, 8, 22, 22, 8, 8, 1, 1, GDK_INTERP_NEAREST, 255);
205 
206   gdk_pixbuf_composite (add_pixbuf, tmp_pixbuf,
207                         0, 0, 12, 12, 0, 0, 1, 1, GDK_INTERP_NEAREST, 255);
208 
209 
210   adaptor->priv->cursor =
211       gdk_cursor_new_from_pixbuf (display, tmp_pixbuf, 6, 6);
212 
213   g_object_unref (tmp_pixbuf);
214   g_object_unref (widget_pixbuf);
215 }
216 
217 static gboolean
glade_widget_adaptor_hash_find(gpointer key,gpointer value,gpointer user_data)218 glade_widget_adaptor_hash_find (gpointer key,
219                                 gpointer value,
220                                 gpointer user_data)
221 {
222   GladeWidgetAdaptor *adaptor = value;
223   GType *type = user_data;
224 
225   if (g_type_is_a (adaptor->priv->type, *type))
226     {
227       *type = adaptor->priv->type;
228       return TRUE;
229     }
230 
231   return FALSE;
232 }
233 
234 static void
glade_abort_if_derived_adaptors_exist(GType type)235 glade_abort_if_derived_adaptors_exist (GType type)
236 {
237   if (adaptor_hash)
238     {
239       GType retval = type;
240 
241       g_hash_table_find (adaptor_hash, glade_widget_adaptor_hash_find, &retval);
242       if (retval != type)
243         g_error (_("A derived adaptor (%s) of %s already exist!"),
244                  g_type_name (retval), g_type_name (type));
245     }
246 }
247 
248 static GladeInternalChild *
gwa_internal_child_find(GList * list,const gchar * name)249 gwa_internal_child_find (GList *list, const gchar *name)
250 {
251   GList *l;
252 
253   for (l = list; l; l = g_list_next (l))
254     {
255       GladeInternalChild *data = l->data;
256 
257       if (strcmp (data->name, name) == 0)
258         return data;
259 
260       if (data->children)
261         {
262           GladeInternalChild *child;
263           if ((child = gwa_internal_child_find (data->children, name)))
264             return child;
265         }
266     }
267 
268   return NULL;
269 }
270 
271 /*******************************************************************************
272                      Base Object Implementation detail
273  *******************************************************************************/
274 #define gwa_get_parent_adaptor(a) glade_widget_adaptor_get_parent_adaptor (a)
275 
276 static GladeWidgetAdaptor *
glade_widget_adaptor_get_parent_adaptor_by_type(GType adaptor_type)277 glade_widget_adaptor_get_parent_adaptor_by_type (GType adaptor_type)
278 {
279   GladeWidgetAdaptor *parent_adaptor = NULL;
280   GType iter_type;
281 
282   for (iter_type = g_type_parent (adaptor_type);
283        iter_type > 0; iter_type = g_type_parent (iter_type))
284     {
285       if ((parent_adaptor =
286            glade_widget_adaptor_get_by_type (iter_type)) != NULL)
287         return parent_adaptor;
288     }
289 
290   return NULL;
291 }
292 
293 /* XXX DOCME
294  */
295 GladeWidgetAdaptor *
glade_widget_adaptor_get_parent_adaptor(GladeWidgetAdaptor * adaptor)296 glade_widget_adaptor_get_parent_adaptor (GladeWidgetAdaptor *adaptor)
297 {
298   g_return_val_if_fail (GLADE_IS_WIDGET_ADAPTOR (adaptor), NULL);
299 
300   return glade_widget_adaptor_get_parent_adaptor_by_type (adaptor->priv->type);
301 }
302 
303 gboolean
glade_widget_adaptor_has_internal_children(GladeWidgetAdaptor * adaptor)304 glade_widget_adaptor_has_internal_children (GladeWidgetAdaptor *adaptor)
305 {
306   g_return_val_if_fail (GLADE_IS_WIDGET_ADAPTOR (adaptor), FALSE);
307   return adaptor->priv->internal_children != NULL;
308 }
309 
310 static gint
gwa_signal_comp(gpointer a,gpointer b)311 gwa_signal_comp (gpointer a, gpointer b)
312 {
313   GladeSignalClass *signal_a = a, *signal_b = b;
314 
315   return strcmp (glade_signal_class_get_name (signal_b),
316 		 glade_signal_class_get_name (signal_a));
317 }
318 
319 static gint
gwa_signal_find_comp(gpointer a,gpointer b)320 gwa_signal_find_comp (gpointer a, gpointer b)
321 {
322   GladeSignalClass *signal = a;
323   gchar *name = b;
324   return strcmp (name, glade_signal_class_get_name (signal));
325 }
326 
327 static void
gwa_add_signals(GladeWidgetAdaptor * adaptor,GList ** signals,GType type)328 gwa_add_signals (GladeWidgetAdaptor *adaptor, GList **signals, GType type)
329 {
330   guint               count, *sig_ids, num_signals;
331   GladeWidgetAdaptor *type_adaptor;
332   GladeSignalClass   *signal;
333   GList              *list = NULL;
334 
335   type_adaptor = glade_widget_adaptor_get_by_type (type);
336 
337   sig_ids = g_signal_list_ids (type, &num_signals);
338 
339   for (count = 0; count < num_signals; count++)
340     {
341       signal = glade_signal_class_new (type_adaptor ?
342 				       type_adaptor : adaptor,
343 				       type, sig_ids[count]);
344 
345       list = g_list_prepend (list, signal);
346     }
347   g_free (sig_ids);
348 
349   list = g_list_sort (list, (GCompareFunc)gwa_signal_comp);
350   *signals = g_list_concat (list, *signals);
351 }
352 
353 static GList *
gwa_list_signals(GladeWidgetAdaptor * adaptor,GType real_type)354 gwa_list_signals (GladeWidgetAdaptor *adaptor, GType real_type)
355 {
356   GList *signals = NULL;
357   GType type, parent, *i, *p;
358 
359   g_return_val_if_fail (real_type != 0, NULL);
360 
361   for (type = real_type; g_type_is_a (type, G_TYPE_OBJECT); type = parent)
362     {
363       parent = g_type_parent (type);
364 
365       /* Add class signals */
366       gwa_add_signals (adaptor, &signals, type);
367 
368       /* Add class interfaces signals */
369       for (i = p = g_type_interfaces (type, NULL); *i; i++)
370         if (!g_type_is_a (parent, *i))
371           gwa_add_signals (adaptor, &signals, *i);
372 
373       g_free (p);
374     }
375 
376   return g_list_reverse (signals);
377 }
378 
379 static GList *
gwa_clone_parent_properties(GladeWidgetAdaptor * adaptor,gboolean is_packing)380 gwa_clone_parent_properties (GladeWidgetAdaptor *adaptor, gboolean is_packing)
381 {
382   GladeWidgetAdaptor *parent_adaptor;
383   GList *properties = NULL, *list, *proplist;
384 
385   if ((parent_adaptor = gwa_get_parent_adaptor (adaptor)) != NULL)
386     {
387       gboolean reset_version;
388 
389       proplist = is_packing ?
390           parent_adaptor->priv->packing_props : parent_adaptor->priv->properties;
391 
392       /* Reset versioning in derived catalogs just once */
393       reset_version = strcmp (adaptor->priv->catalog, parent_adaptor->priv->catalog) != 0;
394 
395       for (list = proplist; list; list = list->next)
396         {
397           GladePropertyClass *pclass = glade_property_class_clone (list->data, reset_version);
398 
399 	  glade_property_class_set_adaptor (pclass, adaptor);
400 
401           properties = g_list_prepend (properties, pclass);
402         }
403     }
404 
405   return g_list_reverse (properties);
406 }
407 
408 static void
gwa_setup_introspected_props_from_pspecs(GladeWidgetAdaptor * adaptor,GParamSpec ** specs,gint n_specs,gboolean is_packing)409 gwa_setup_introspected_props_from_pspecs (GladeWidgetAdaptor *adaptor,
410                                           GParamSpec        **specs,
411                                           gint                n_specs,
412                                           gboolean            is_packing)
413 {
414   GladeWidgetAdaptor *parent_adaptor = gwa_get_parent_adaptor (adaptor);
415   GladePropertyClass *property_class;
416   gint i;
417   GList *list = NULL;
418 
419   for (i = 0; i < n_specs; i++)
420     {
421       if (parent_adaptor == NULL ||
422           /* Dont create it if it already exists */
423           (!is_packing &&
424            !glade_widget_adaptor_get_property_class (parent_adaptor,
425                                                      specs[i]->name)) ||
426           (is_packing &&
427            !glade_widget_adaptor_get_pack_property_class (parent_adaptor,
428                                                           specs[i]->name)))
429         {
430           if ((property_class =
431                glade_property_class_new_from_spec (adaptor, specs[i])) != NULL)
432             list = g_list_prepend (list, property_class);
433         }
434     }
435 
436   if (is_packing)
437     adaptor->priv->packing_props =
438         g_list_concat (adaptor->priv->packing_props, g_list_reverse (list));
439   else
440     adaptor->priv->properties =
441         g_list_concat (adaptor->priv->properties, g_list_reverse (list));
442 }
443 
444 static void
gwa_setup_properties(GladeWidgetAdaptor * adaptor,GObjectClass * object_class,gboolean is_packing)445 gwa_setup_properties (GladeWidgetAdaptor *adaptor,
446                       GObjectClass       *object_class,
447                       gboolean            is_packing)
448 {
449   GParamSpec **specs = NULL;
450   guint n_specs = 0;
451   GList *l;
452 
453   /* only GtkContainer child propeties can be introspected */
454   if (is_packing && !g_type_is_a (adaptor->priv->type, GTK_TYPE_CONTAINER))
455     return;
456 
457   /* First clone the parents properties */
458   if (is_packing)
459     adaptor->priv->packing_props = gwa_clone_parent_properties (adaptor, is_packing);
460   else
461     adaptor->priv->properties = gwa_clone_parent_properties (adaptor, is_packing);
462 
463   /* Now automaticly introspect new properties added in this class,
464    * allow the class writer to decide what to override in the resulting
465    * list of properties.
466    */
467   if (is_packing)
468     specs = gtk_container_class_list_child_properties (object_class, &n_specs);
469   else
470     specs = g_object_class_list_properties (object_class, &n_specs);
471   gwa_setup_introspected_props_from_pspecs (adaptor, specs, n_specs,
472                                             is_packing);
473   g_free (specs);
474 
475   if (is_packing)
476     {
477       /* We have to mark packing properties from GladeWidgetAdaptor
478        * because GladePropertyClass doesnt have a valid parent GType
479        * to introspect it.
480        *
481        * (which could be used to call gtk_container_class_find_child_property()
482        * and properly introspect whether or not its a packing property).
483        */
484       for (l = adaptor->priv->packing_props; l; l = l->next)
485         {
486           GladePropertyClass *property_class = l->data;
487 
488 	  glade_property_class_set_is_packing (property_class, TRUE);
489         }
490     }
491 }
492 
493 static GList *
gwa_inherit_child_packing(GladeWidgetAdaptor * adaptor)494 gwa_inherit_child_packing (GladeWidgetAdaptor *adaptor)
495 {
496   GladeWidgetAdaptor *parent_adaptor;
497   GList *child_packings = NULL, *packing_list, *default_list;
498 
499   if ((parent_adaptor = gwa_get_parent_adaptor (adaptor)) != NULL)
500     {
501       for (packing_list = parent_adaptor->priv->child_packings;
502            packing_list; packing_list = packing_list->next)
503         {
504           GladeChildPacking *packing = packing_list->data;
505           GladeChildPacking *packing_dup = g_new0 (GladeChildPacking, 1);
506 
507           packing_dup->parent_name = g_strdup (packing->parent_name);
508 
509           for (default_list = packing->packing_defaults;
510                default_list; default_list = default_list->next)
511             {
512               GladePackingDefault *def = default_list->data;
513               GladePackingDefault *def_dup = g_new0 (GladePackingDefault, 1);
514 
515               def_dup->id = g_strdup (def->id);
516               def_dup->value = g_strdup (def->value);
517 
518               packing_dup->packing_defaults =
519                   g_list_prepend (packing_dup->packing_defaults, def_dup);
520             }
521 
522           child_packings = g_list_prepend (child_packings, packing_dup);
523         }
524     }
525   return child_packings;
526 }
527 
528 static void
gwa_inherit_signals(GladeWidgetAdaptor * adaptor)529 gwa_inherit_signals (GladeWidgetAdaptor *adaptor)
530 {
531   GladeWidgetAdaptor *parent_adaptor;
532   GList *list, *node;
533   GladeSignalClass *signal, *parent_signal;
534 
535   if ((parent_adaptor = gwa_get_parent_adaptor (adaptor)) != NULL)
536     {
537       for (list = adaptor->priv->signals; list; list = list->next)
538         {
539           signal = list->data;
540 
541           if ((node = g_list_find_custom (parent_adaptor->priv->signals,
542 					  glade_signal_class_get_name (signal),
543 					  (GCompareFunc) gwa_signal_find_comp)) != NULL)
544             {
545               parent_signal = node->data;
546 
547               /* XXX FIXME: This is questionable, why should derived catalogs
548 	       * reset the derived signal versions ???
549 	       *
550 	       * Reset versioning in derived catalogs just once
551 	       */
552               if (strcmp (adaptor->priv->catalog,
553                           parent_adaptor->priv->catalog))
554 		glade_signal_class_set_since (signal, 0, 0);
555               else
556 		glade_signal_class_set_since (signal,
557 					      glade_signal_class_since_major (parent_signal),
558 					      glade_signal_class_since_minor (parent_signal));
559 
560 	      glade_signal_class_set_deprecated (signal, glade_signal_class_deprecated (parent_signal));
561             }
562         }
563     }
564 }
565 
566 static GladeInternalChild *
gwa_internal_children_new(gchar * name,gboolean anarchist)567 gwa_internal_children_new (gchar *name, gboolean anarchist)
568 {
569   GladeInternalChild *data = g_slice_new0 (GladeInternalChild);
570 
571   data->name = g_strdup (name);
572   data->anarchist = anarchist;
573 
574   return data;
575 }
576 
577 static GList *
gwa_internal_children_clone(GList * children)578 gwa_internal_children_clone (GList *children)
579 {
580   GList *l, *retval = NULL;
581 
582   for (l = children; l; l = g_list_next (l))
583     {
584       GladeInternalChild *data, *child = l->data;
585 
586       data = gwa_internal_children_new (child->name, child->anarchist);
587       retval = g_list_prepend (retval, data);
588 
589       if (child->children)
590         data->children = gwa_internal_children_clone (child->children);
591     }
592 
593   return g_list_reverse (retval);
594 }
595 
596 static GObject *
glade_widget_adaptor_constructor(GType type,guint n_construct_properties,GObjectConstructParam * construct_properties)597 glade_widget_adaptor_constructor (GType                  type,
598                                   guint                  n_construct_properties,
599                                   GObjectConstructParam *construct_properties)
600 {
601   GladeWidgetAdaptor *adaptor, *parent_adaptor;
602   GObject *ret_obj;
603   GObjectClass *object_class;
604 
605   glade_abort_if_derived_adaptors_exist (type);
606 
607   ret_obj = G_OBJECT_CLASS (glade_widget_adaptor_parent_class)->constructor
608       (type, n_construct_properties, construct_properties);
609 
610   adaptor = GLADE_WIDGET_ADAPTOR (ret_obj);
611   parent_adaptor = gwa_get_parent_adaptor (adaptor);
612 
613   if (adaptor->priv->type == G_TYPE_NONE)
614     g_warning ("Adaptor created without a type");
615   if (adaptor->priv->name == NULL)
616     g_warning ("Adaptor created without a name");
617 
618   /* Build decorations */
619   if (!adaptor->priv->icon_name)
620     adaptor->priv->icon_name = g_strdup ("gtk-missing-image");
621 
622   /* Let it leek */
623   if ((object_class = g_type_class_ref (adaptor->priv->type)))
624     {
625       /* Build signals & properties */
626       adaptor->priv->signals = gwa_list_signals (adaptor, adaptor->priv->type);
627 
628       gwa_inherit_signals (adaptor);
629       gwa_setup_properties (adaptor, object_class, FALSE);
630       gwa_setup_properties (adaptor, object_class, TRUE);
631     }
632 
633   /* Inherit packing defaults here */
634   adaptor->priv->child_packings = gwa_inherit_child_packing (adaptor);
635 
636   /* Inherit special-child-type */
637   if (parent_adaptor)
638     adaptor->priv->special_child_type =
639         parent_adaptor->priv->special_child_type ?
640         g_strdup (parent_adaptor->priv->special_child_type) : NULL;
641 
642 
643   /* Reset version numbering if we're in a new catalog just once */
644   if (parent_adaptor &&
645       strcmp (adaptor->priv->catalog, parent_adaptor->priv->catalog))
646     {
647       GLADE_WIDGET_ADAPTOR_GET_CLASS (adaptor)->version_since_major =
648           GLADE_WIDGET_ADAPTOR_GET_CLASS (adaptor)->version_since_minor = 0;
649     }
650 
651   /* Copy parent actions */
652   if (parent_adaptor)
653     {
654       GList *l;
655 
656       if (parent_adaptor->priv->actions)
657         {
658           for (l = parent_adaptor->priv->actions; l; l = g_list_next (l))
659             {
660               GWActionClass *child = glade_widget_action_class_clone (l->data);
661               adaptor->priv->actions = g_list_prepend (adaptor->priv->actions, child);
662             }
663           adaptor->priv->actions = g_list_reverse (adaptor->priv->actions);
664         }
665 
666       if (parent_adaptor->priv->packing_actions)
667         {
668           for (l = parent_adaptor->priv->packing_actions; l; l = g_list_next (l))
669             {
670               GWActionClass *child = glade_widget_action_class_clone (l->data);
671               adaptor->priv->packing_actions =
672                   g_list_prepend (adaptor->priv->packing_actions, child);
673             }
674           adaptor->priv->packing_actions = g_list_reverse (adaptor->priv->packing_actions);
675         }
676     }
677 
678   /* Copy parent internal children */
679   if (parent_adaptor && parent_adaptor->priv->internal_children)
680     adaptor->priv->internal_children = gwa_internal_children_clone (parent_adaptor->priv->internal_children);
681 
682   return ret_obj;
683 }
684 
685 static void
gwa_packing_default_free(GladePackingDefault * def)686 gwa_packing_default_free (GladePackingDefault *def)
687 {
688   g_free (def->id);
689   g_free (def->value);
690 }
691 
692 static void
gwa_child_packing_free(GladeChildPacking * packing)693 gwa_child_packing_free (GladeChildPacking *packing)
694 {
695   g_free (packing->parent_name);
696 
697   g_list_foreach (packing->packing_defaults,
698                   (GFunc) gwa_packing_default_free, NULL);
699   g_list_free (packing->packing_defaults);
700 }
701 
702 static void
gwa_glade_internal_child_free(GladeInternalChild * child)703 gwa_glade_internal_child_free (GladeInternalChild *child)
704 {
705   g_free (child->name);
706 
707   if (child->children)
708     {
709       g_list_foreach (child->children, (GFunc) gwa_glade_internal_child_free, NULL);
710       g_list_free (child->children);
711     }
712 
713   g_slice_free (GladeInternalChild, child);
714 }
715 
716 static void
gwa_internal_children_free(GladeWidgetAdaptor * adaptor)717 gwa_internal_children_free (GladeWidgetAdaptor *adaptor)
718 {
719   if (adaptor->priv->internal_children)
720     {
721       g_list_foreach (adaptor->priv->internal_children,
722                       (GFunc) gwa_glade_internal_child_free, NULL);
723       g_list_free (adaptor->priv->internal_children);
724       adaptor->priv->internal_children = NULL;
725     }
726 }
727 
728 static void
glade_widget_adaptor_finalize(GObject * object)729 glade_widget_adaptor_finalize (GObject *object)
730 {
731   GladeWidgetAdaptor *adaptor = GLADE_WIDGET_ADAPTOR (object);
732 
733   /* Free properties and signals */
734   g_list_foreach (adaptor->priv->properties, (GFunc) glade_property_class_free, NULL);
735   g_list_free (adaptor->priv->properties);
736 
737   g_list_foreach (adaptor->priv->packing_props, (GFunc) glade_property_class_free,
738                   NULL);
739   g_list_free (adaptor->priv->packing_props);
740 
741   /* Be careful, this list holds GladeSignalClass* not GladeSignal,
742    * thus g_free is enough as all members are const */
743   g_list_foreach (adaptor->priv->signals, (GFunc) g_free, NULL);
744   g_list_free (adaptor->priv->signals);
745 
746 
747   /* Free child packings */
748   g_list_foreach (adaptor->priv->child_packings,
749                   (GFunc) gwa_child_packing_free, NULL);
750   g_list_free (adaptor->priv->child_packings);
751 
752   if (adaptor->priv->book)
753     g_free (adaptor->priv->book);
754   if (adaptor->priv->catalog)
755     g_free (adaptor->priv->catalog);
756   if (adaptor->priv->special_child_type)
757     g_free (adaptor->priv->special_child_type);
758 
759   if (adaptor->priv->cursor != NULL)
760     g_object_unref (adaptor->priv->cursor);
761 
762   if (adaptor->priv->name)
763     g_free (adaptor->priv->name);
764   if (adaptor->priv->generic_name)
765     g_free (adaptor->priv->generic_name);
766   if (adaptor->priv->title)
767     g_free (adaptor->priv->title);
768   if (adaptor->priv->icon_name)
769     g_free (adaptor->priv->icon_name);
770   if (adaptor->priv->missing_icon)
771     g_free (adaptor->priv->missing_icon);
772 
773   if (adaptor->priv->actions)
774     {
775       g_list_foreach (adaptor->priv->actions,
776                       (GFunc) glade_widget_action_class_free, NULL);
777       g_list_free (adaptor->priv->actions);
778     }
779 
780   if (adaptor->priv->packing_actions)
781     {
782       g_list_foreach (adaptor->priv->packing_actions,
783                       (GFunc) glade_widget_action_class_free, NULL);
784       g_list_free (adaptor->priv->packing_actions);
785     }
786 
787   gwa_internal_children_free (adaptor);
788 
789   G_OBJECT_CLASS (glade_widget_adaptor_parent_class)->finalize (object);
790 }
791 
792 static void
glade_widget_adaptor_real_set_property(GObject * object,guint prop_id,const GValue * value,GParamSpec * pspec)793 glade_widget_adaptor_real_set_property (GObject      *object,
794                                         guint         prop_id,
795                                         const GValue *value,
796                                         GParamSpec   *pspec)
797 {
798   GladeWidgetAdaptor *adaptor;
799 
800   adaptor = GLADE_WIDGET_ADAPTOR (object);
801 
802   switch (prop_id)
803     {
804       case PROP_NAME:
805         /* assume once (construct-only) */
806         adaptor->priv->name = g_value_dup_string (value);
807         adaptor->priv->real_type = g_type_from_name (adaptor->priv->name);
808         break;
809       case PROP_ICON_NAME:
810         /* assume once (construct-only) */
811         adaptor->priv->icon_name = g_value_dup_string (value);
812         break;
813       case PROP_TYPE:
814         adaptor->priv->type = g_value_get_gtype (value);
815         break;
816       case PROP_TITLE:
817         if (adaptor->priv->title)
818           g_free (adaptor->priv->title);
819         adaptor->priv->title = g_value_dup_string (value);
820         break;
821       case PROP_GENERIC_NAME:
822         if (adaptor->priv->generic_name)
823           g_free (adaptor->priv->generic_name);
824         adaptor->priv->generic_name = g_value_dup_string (value);
825         break;
826       case PROP_CATALOG:
827         /* assume once (construct-only) */
828 	g_free (adaptor->priv->catalog);
829         adaptor->priv->catalog = g_value_dup_string (value);
830         break;
831       case PROP_BOOK:
832         /* assume once (construct-only) */
833 	g_free (adaptor->priv->book);
834         adaptor->priv->book = g_value_dup_string (value);
835         break;
836       case PROP_SPECIAL_TYPE:
837         /* assume once (construct-only) */
838 	g_free (adaptor->priv->special_child_type);
839 	adaptor->priv->special_child_type = g_value_dup_string (value);
840         break;
841       case PROP_QUERY:
842         adaptor->priv->query = g_value_get_boolean (value);
843         break;
844       default:
845         G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
846         break;
847     }
848 }
849 
850 static void
glade_widget_adaptor_real_get_property(GObject * object,guint prop_id,GValue * value,GParamSpec * pspec)851 glade_widget_adaptor_real_get_property (GObject    *object,
852                                         guint       prop_id,
853                                         GValue     *value,
854                                         GParamSpec *pspec)
855 {
856 
857   GladeWidgetAdaptor *adaptor;
858 
859   adaptor = GLADE_WIDGET_ADAPTOR (object);
860 
861   switch (prop_id)
862     {
863       case PROP_NAME:
864         g_value_set_string (value, adaptor->priv->name);
865         break;
866       case PROP_TYPE:
867         g_value_set_gtype (value, adaptor->priv->type);
868         break;
869       case PROP_TITLE:
870         g_value_set_string (value, adaptor->priv->title);
871         break;
872       case PROP_GENERIC_NAME:
873         g_value_set_string (value, adaptor->priv->generic_name);
874         break;
875       case PROP_ICON_NAME:
876         g_value_set_string (value, adaptor->priv->icon_name);
877         break;
878       case PROP_CATALOG:
879         g_value_set_string (value, adaptor->priv->catalog);
880         break;
881       case PROP_BOOK:
882         g_value_set_string (value, adaptor->priv->book);
883         break;
884       case PROP_SPECIAL_TYPE:
885         g_value_set_string (value, adaptor->priv->special_child_type);
886         break;
887       case PROP_CURSOR:
888         g_value_set_pointer (value, adaptor->priv->cursor);
889         break;
890       case PROP_QUERY:
891         g_value_set_boolean (value, adaptor->priv->query);
892         break;
893       default:
894         G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
895         break;
896     }
897 }
898 
899 /*******************************************************************************
900                   GladeWidgetAdaptor base class implementations
901  *******************************************************************************/
902 static GladeWidget *
glade_widget_adaptor_object_create_widget(GladeWidgetAdaptor * adaptor,const gchar * first_property_name,va_list var_args)903 glade_widget_adaptor_object_create_widget (GladeWidgetAdaptor *adaptor,
904                                            const gchar        *first_property_name,
905                                            va_list             var_args)
906 {
907   return GLADE_WIDGET (g_object_new_valist (GLADE_TYPE_WIDGET,
908                                             first_property_name, var_args));
909 }
910 
911 static GObject *
glade_widget_adaptor_object_construct_object(GladeWidgetAdaptor * adaptor,guint n_parameters,GParameter * parameters)912 glade_widget_adaptor_object_construct_object (GladeWidgetAdaptor *adaptor,
913                                               guint               n_parameters,
914                                               GParameter         *parameters)
915 {
916   return g_object_newv (adaptor->priv->type, n_parameters, parameters);
917 }
918 
919 static void
glade_widget_adaptor_object_destroy_object(GladeWidgetAdaptor * adaptor,GObject * object)920 glade_widget_adaptor_object_destroy_object (GladeWidgetAdaptor *adaptor,
921 					    GObject            *object)
922 {
923   /* Do nothing, just have a method here incase classes chain up */
924 }
925 
926 
927 static GObject *
glade_widget_adaptor_object_get_internal_child(GladeWidgetAdaptor * adaptor,GObject * object,const gchar * name)928 glade_widget_adaptor_object_get_internal_child (GladeWidgetAdaptor *adaptor,
929                                                 GObject            *object,
930                                                 const gchar        *name)
931 {
932   static GtkBuilder *builder = NULL;
933 
934   g_return_val_if_fail (GTK_IS_BUILDABLE (object), NULL);
935 
936   /* Dummy object just in case the interface use it for something */
937   if (builder == NULL) builder = gtk_builder_new ();
938 
939   return gtk_buildable_get_internal_child (GTK_BUILDABLE (object), builder, name);
940 }
941 
942 static gboolean
glade_widget_adaptor_object_add_verify(GladeWidgetAdaptor * adaptor,GObject * parent,GObject * child,gboolean user_feedback)943 glade_widget_adaptor_object_add_verify (GladeWidgetAdaptor *adaptor,
944 					GObject            *parent,
945 					GObject            *child,
946 					gboolean            user_feedback)
947 {
948   if (user_feedback)
949     glade_util_ui_message (glade_app_get_window (),
950 			   GLADE_UI_INFO, NULL,
951 			   _("%s does not support adding any children."),
952 			   adaptor->priv->title);
953 
954   return FALSE;
955 }
956 
957 static void
glade_widget_adaptor_object_set_property(GladeWidgetAdaptor * adaptor,GObject * object,const gchar * property_name,const GValue * value)958 glade_widget_adaptor_object_set_property (GladeWidgetAdaptor *adaptor,
959                                           GObject            *object,
960                                           const gchar        *property_name,
961                                           const GValue       *value)
962 {
963   g_object_set_property (object, property_name, value);
964 }
965 
966 static void
glade_widget_adaptor_object_get_property(GladeWidgetAdaptor * adaptor,GObject * object,const gchar * property_name,GValue * value)967 glade_widget_adaptor_object_get_property (GladeWidgetAdaptor *adaptor,
968                                           GObject            *object,
969                                           const gchar        *property_name,
970                                           GValue             *value)
971 {
972   g_object_get_property (object, property_name, value);
973 }
974 
975 static void
glade_widget_adaptor_object_action_activate(GladeWidgetAdaptor * adaptor,GObject * object,const gchar * action_id)976 glade_widget_adaptor_object_action_activate (GladeWidgetAdaptor *adaptor,
977                                              GObject            *object,
978                                              const gchar        *action_id)
979 {
980   g_message ("No action_activate() support in adaptor %s for action '%s'",
981              adaptor->priv->name, action_id);
982 }
983 
984 static void
glade_widget_adaptor_object_child_action_activate(GladeWidgetAdaptor * adaptor,GObject * container,GObject * object,const gchar * action_id)985 glade_widget_adaptor_object_child_action_activate (GladeWidgetAdaptor *adaptor,
986                                                    GObject            *container,
987                                                    GObject            *object,
988                                                    const gchar        *action_id)
989 {
990   g_message ("No child_action_activate() support in adaptor %s for action '%s'",
991              adaptor->priv->name, action_id);
992 }
993 
994 static void
glade_widget_adaptor_object_read_widget(GladeWidgetAdaptor * adaptor,GladeWidget * widget,GladeXmlNode * node)995 glade_widget_adaptor_object_read_widget (GladeWidgetAdaptor *adaptor,
996                                          GladeWidget        *widget,
997                                          GladeXmlNode       *node)
998 {
999   GladeXmlNode *iter_node;
1000   GladeSignal *signal;
1001   GladeProperty *property;
1002   gchar *name, *prop_name;
1003   GList *read_properties = NULL, *l;
1004 
1005   /* Read in the properties */
1006   for (iter_node = glade_xml_node_get_children (node);
1007        iter_node; iter_node = glade_xml_node_next (iter_node))
1008     {
1009       if (!glade_xml_node_verify_silent (iter_node, GLADE_XML_TAG_PROPERTY))
1010         continue;
1011 
1012       /* Get prop name from node and lookup property ... */
1013       if (!(name = glade_xml_get_property_string_required
1014             (iter_node, GLADE_XML_TAG_NAME, NULL)))
1015         continue;
1016 
1017       prop_name = glade_util_read_prop_name (name);
1018 
1019       /* Some properties may be special child type of custom, just leave them for the adaptor */
1020       if ((property = glade_widget_get_property (widget, prop_name)) != NULL)
1021         {
1022           glade_property_read (property, glade_widget_get_project (widget), iter_node);
1023           read_properties = g_list_prepend (read_properties, property);
1024         }
1025 
1026       g_free (prop_name);
1027       g_free (name);
1028     }
1029 
1030   /* Sync the remaining values not read in from the Glade file.. */
1031   for (l = glade_widget_get_properties (widget); l; l = l->next)
1032     {
1033       property = l->data;
1034 
1035       if (!g_list_find (read_properties, property))
1036         glade_property_sync (property);
1037     }
1038   g_list_free (read_properties);
1039 
1040   /* Read in the signals */
1041   for (iter_node = glade_xml_node_get_children (node);
1042        iter_node; iter_node = glade_xml_node_next (iter_node))
1043     {
1044       if (!glade_xml_node_verify_silent (iter_node, GLADE_XML_TAG_SIGNAL))
1045         continue;
1046 
1047       if (!(signal = glade_signal_read (iter_node, adaptor)))
1048         continue;
1049 
1050       /* The widget doesnt use the signal handler directly but rather
1051        * creates it's own copy */
1052       glade_widget_add_signal_handler (widget, signal);
1053       g_object_unref (signal);
1054     }
1055 
1056   /* Read in children */
1057   for (iter_node = glade_xml_node_get_children (node);
1058        iter_node; iter_node = glade_xml_node_next (iter_node))
1059     {
1060       if (glade_xml_node_verify_silent (iter_node, GLADE_XML_TAG_CHILD))
1061         glade_widget_read_child (widget, iter_node);
1062 
1063       if (glade_project_load_cancelled (glade_widget_get_project (widget)))
1064         return;
1065     }
1066 }
1067 
1068 static void
glade_widget_adaptor_object_write_widget(GladeWidgetAdaptor * adaptor,GladeWidget * widget,GladeXmlContext * context,GladeXmlNode * node)1069 glade_widget_adaptor_object_write_widget (GladeWidgetAdaptor *adaptor,
1070                                           GladeWidget        *widget,
1071                                           GladeXmlContext    *context,
1072                                           GladeXmlNode       *node)
1073 {
1074   GList *props;
1075 
1076   /* Write the properties */
1077   for (props = glade_widget_get_properties (widget); props; props = props->next)
1078     {
1079       GladeProperty      *property = props->data;
1080       GladePropertyClass *klass = glade_property_get_class (property);
1081 
1082       if (glade_property_class_save (klass) &&
1083 	  glade_property_get_enabled (property))
1084         glade_property_write (GLADE_PROPERTY (props->data), context, node);
1085     }
1086 }
1087 
1088 static void
glade_widget_adaptor_object_write_widget_after(GladeWidgetAdaptor * adaptor,GladeWidget * widget,GladeXmlContext * context,GladeXmlNode * node)1089 glade_widget_adaptor_object_write_widget_after (GladeWidgetAdaptor *adaptor,
1090 						GladeWidget        *widget,
1091 						GladeXmlContext    *context,
1092 						GladeXmlNode       *node)
1093 {
1094 
1095 }
1096 
1097 static void
glade_widget_adaptor_object_read_child(GladeWidgetAdaptor * adaptor,GladeWidget * widget,GladeXmlNode * node)1098 glade_widget_adaptor_object_read_child (GladeWidgetAdaptor *adaptor,
1099                                         GladeWidget        *widget,
1100                                         GladeXmlNode       *node)
1101 {
1102   GladeXmlNode *widget_node, *packing_node, *iter_node;
1103   GladeWidget *child_widget;
1104   gchar *internal_name;
1105   gchar *name, *prop_name;
1106   GladeProperty *property;
1107 
1108   if (!glade_xml_node_verify (node, GLADE_XML_TAG_CHILD))
1109     return;
1110 
1111   internal_name =
1112       glade_xml_get_property_string (node, GLADE_XML_TAG_INTERNAL_CHILD);
1113 
1114   if ((widget_node =
1115        glade_xml_search_child (node, GLADE_XML_TAG_WIDGET)) != NULL)
1116     {
1117       child_widget =
1118 	glade_widget_read (glade_widget_get_project (widget),
1119 			   widget, widget_node, internal_name);
1120 
1121       if (child_widget)
1122         {
1123           if (!internal_name)
1124             {
1125               glade_widget_set_child_type_from_node
1126 		(widget, glade_widget_get_object (child_widget), node);
1127               glade_widget_add_child (widget, child_widget, FALSE);
1128             }
1129 
1130           if ((packing_node =
1131                glade_xml_search_child (node, GLADE_XML_TAG_PACKING)) != NULL)
1132             {
1133 
1134               /* Read in the properties */
1135               for (iter_node = glade_xml_node_get_children (packing_node);
1136                    iter_node; iter_node = glade_xml_node_next (iter_node))
1137                 {
1138                   if (!glade_xml_node_verify_silent
1139                       (iter_node, GLADE_XML_TAG_PROPERTY))
1140                     continue;
1141 
1142                   /* Get prop name from node and lookup property ... */
1143                   if (!(name = glade_xml_get_property_string_required
1144                         (iter_node, GLADE_XML_TAG_NAME, NULL)))
1145                     continue;
1146 
1147                   prop_name = glade_util_read_prop_name (name);
1148 
1149                   /* Some properties may be special child type of custom,
1150                    * just leave them for the adaptor */
1151                   if ((property =
1152                        glade_widget_get_pack_property (child_widget,
1153                                                        prop_name)) != NULL)
1154                     glade_property_read (property,
1155 					 glade_widget_get_project (child_widget),
1156                                          iter_node);
1157 
1158                   g_free (prop_name);
1159                   g_free (name);
1160                 }
1161             }
1162         }
1163 
1164     }
1165   else
1166     {
1167       GObject *palaceholder = G_OBJECT (glade_placeholder_new ());
1168       glade_widget_set_child_type_from_node (widget, palaceholder, node);
1169       glade_widget_adaptor_add (adaptor, glade_widget_get_object (widget), palaceholder);
1170     }
1171   g_free (internal_name);
1172 }
1173 
1174 static void
glade_widget_adaptor_object_write_child(GladeWidgetAdaptor * adaptor,GladeWidget * widget,GladeXmlContext * context,GladeXmlNode * node)1175 glade_widget_adaptor_object_write_child (GladeWidgetAdaptor *adaptor,
1176                                          GladeWidget        *widget,
1177                                          GladeXmlContext    *context,
1178                                          GladeXmlNode       *node)
1179 {
1180   GladeXmlNode *child_node, *packing_node;
1181   GList *props;
1182 
1183   child_node = glade_xml_node_new (context, GLADE_XML_TAG_CHILD);
1184   glade_xml_node_append_child (node, child_node);
1185 
1186   /* Set internal child */
1187   if (glade_widget_get_internal (widget))
1188     glade_xml_node_set_property_string (child_node,
1189                                         GLADE_XML_TAG_INTERNAL_CHILD,
1190                                         glade_widget_get_internal (widget));
1191 
1192   /* Write out the widget */
1193   glade_widget_write (widget, context, child_node);
1194 
1195   /* Write out packing properties and special-child-type */
1196   packing_node = glade_xml_node_new (context, GLADE_XML_TAG_PACKING);
1197   glade_xml_node_append_child (child_node, packing_node);
1198 
1199   for (props = glade_widget_get_packing_properties (widget); props; props = props->next)
1200     {
1201       GladeProperty      *property = props->data;
1202       GladePropertyClass *klass = glade_property_get_class (property);
1203 
1204       if (glade_property_class_save (klass) &&
1205 	  glade_property_get_enabled (property))
1206         glade_property_write (GLADE_PROPERTY (props->data),
1207                               context, packing_node);
1208     }
1209 
1210   glade_widget_write_special_child_prop (glade_widget_get_parent (widget),
1211                                          glade_widget_get_object (widget),
1212 					 context, child_node);
1213 
1214   /* Default packing properties and such are not saved,
1215    * so lets check afterwords if there was anything saved
1216    * and then just remove the node.
1217    */
1218   if (!glade_xml_node_get_children (packing_node))
1219     {
1220       glade_xml_node_remove (packing_node);
1221       glade_xml_node_delete (packing_node);
1222     }
1223 }
1224 
1225 static GType
glade_widget_adaptor_get_eprop_type(GParamSpec * pspec)1226 glade_widget_adaptor_get_eprop_type (GParamSpec *pspec)
1227 {
1228   GType type = 0;
1229 
1230   if (G_IS_PARAM_SPEC_ENUM (pspec))
1231     type = GLADE_TYPE_EPROP_ENUM;
1232   else if (G_IS_PARAM_SPEC_FLAGS (pspec))
1233     type = GLADE_TYPE_EPROP_FLAGS;
1234   else if (G_IS_PARAM_SPEC_VALUE_ARRAY (pspec))
1235     {
1236       /* Require deprecated code */
1237       G_GNUC_BEGIN_IGNORE_DEPRECATIONS;
1238       if (pspec->value_type == G_TYPE_VALUE_ARRAY)
1239         type = GLADE_TYPE_EPROP_TEXT;
1240       G_GNUC_BEGIN_IGNORE_DEPRECATIONS;
1241     }
1242   else if (G_IS_PARAM_SPEC_BOXED (pspec))
1243     {
1244       if (pspec->value_type == GDK_TYPE_COLOR ||
1245 	  pspec->value_type == GDK_TYPE_RGBA)
1246         type = GLADE_TYPE_EPROP_COLOR;
1247       else if (pspec->value_type == G_TYPE_STRV)
1248         type = GLADE_TYPE_EPROP_TEXT;
1249     }
1250   else if (G_IS_PARAM_SPEC_STRING (pspec))
1251     type = GLADE_TYPE_EPROP_TEXT;
1252   else if (G_IS_PARAM_SPEC_BOOLEAN (pspec))
1253     type = GLADE_TYPE_EPROP_BOOL;
1254   else if (G_IS_PARAM_SPEC_FLOAT (pspec) ||
1255            G_IS_PARAM_SPEC_DOUBLE (pspec) ||
1256            G_IS_PARAM_SPEC_INT (pspec) ||
1257            G_IS_PARAM_SPEC_UINT (pspec) ||
1258            G_IS_PARAM_SPEC_LONG (pspec) ||
1259            G_IS_PARAM_SPEC_ULONG (pspec) ||
1260            G_IS_PARAM_SPEC_INT64 (pspec) || G_IS_PARAM_SPEC_UINT64 (pspec))
1261     type = GLADE_TYPE_EPROP_NUMERIC;
1262   else if (G_IS_PARAM_SPEC_UNICHAR (pspec))
1263     type = GLADE_TYPE_EPROP_UNICHAR;
1264   else if (G_IS_PARAM_SPEC_OBJECT (pspec))
1265     {
1266       if (pspec->value_type == GDK_TYPE_PIXBUF)
1267         type = GLADE_TYPE_EPROP_TEXT;
1268       else
1269         type = GLADE_TYPE_EPROP_OBJECT;
1270     }
1271   else if (GLADE_IS_PARAM_SPEC_OBJECTS (pspec))
1272     type = GLADE_TYPE_EPROP_OBJECTS;
1273 
1274   return type;
1275 }
1276 
1277 static GladeEditorProperty *
glade_widget_adaptor_object_create_eprop(GladeWidgetAdaptor * adaptor,GladePropertyClass * klass,gboolean use_command)1278 glade_widget_adaptor_object_create_eprop (GladeWidgetAdaptor *adaptor,
1279                                           GladePropertyClass *klass,
1280                                           gboolean            use_command)
1281 {
1282   GladeEditorProperty *eprop;
1283   GParamSpec          *pspec;
1284   GType                type = 0;
1285 
1286   pspec = glade_property_class_get_pspec (klass);
1287 
1288   /* Find the right type of GladeEditorProperty for this
1289    * GladePropertyClass.
1290    */
1291   if ((type = glade_widget_adaptor_get_eprop_type (pspec)) == 0)
1292     return NULL;
1293 
1294   /* special case for string specs that denote themed application icons. */
1295   if (glade_property_class_themed_icon (klass))
1296     type = GLADE_TYPE_EPROP_NAMED_ICON;
1297 
1298   /* Create and return the correct type of GladeEditorProperty */
1299   eprop = g_object_new (type,
1300                         "property-class", klass,
1301                         "use-command", use_command, NULL);
1302 
1303   return eprop;
1304 }
1305 
1306 static gchar *
glade_widget_adaptor_object_string_from_value(GladeWidgetAdaptor * adaptor,GladePropertyClass * klass,const GValue * value)1307 glade_widget_adaptor_object_string_from_value (GladeWidgetAdaptor *adaptor,
1308                                                GladePropertyClass *klass,
1309                                                const GValue       *value)
1310 {
1311   return glade_property_class_make_string_from_gvalue (klass, value);
1312 }
1313 
1314 static GladeEditable *
glade_widget_adaptor_object_create_editable(GladeWidgetAdaptor * adaptor,GladeEditorPageType type)1315 glade_widget_adaptor_object_create_editable (GladeWidgetAdaptor *adaptor,
1316                                              GladeEditorPageType type)
1317 {
1318   return (GladeEditable *) glade_editor_table_new (adaptor, type);
1319 }
1320 
1321 static void
glade_internal_child_append(GladeWidgetAdaptor * adaptor,GObject * object,GList * list,GList ** children)1322 glade_internal_child_append (GladeWidgetAdaptor *adaptor,
1323                              GObject            *object,
1324                              GList              *list,
1325                              GList             **children)
1326 {
1327   GList *l;
1328 
1329   for (l = list; l; l = g_list_next (l))
1330     {
1331       GladeInternalChild *internal = l->data;
1332       GObject *child;
1333 
1334       child = glade_widget_adaptor_get_internal_child (adaptor,
1335                                                        object,
1336                                                        internal->name);
1337       if (child)
1338         *children = g_list_prepend (*children, child);
1339     }
1340 }
1341 
1342 static GList *
glade_widget_adaptor_object_get_children(GladeWidgetAdaptor * adaptor,GObject * object)1343 glade_widget_adaptor_object_get_children (GladeWidgetAdaptor *adaptor,
1344                                           GObject *object)
1345 {
1346   GladeWidget *gwidget = glade_widget_get_from_gobject (object);
1347   GList *children = NULL;
1348   const gchar *name;
1349 
1350   if (gwidget && (name = glade_widget_get_internal (gwidget)))
1351     {
1352       GladeWidget *parent = gwidget;
1353 
1354       /* Get non internal parent */
1355       while ((parent = glade_widget_get_parent (parent)) &&
1356              glade_widget_get_internal (parent));
1357 
1358       if (parent)
1359         {
1360           GladeWidgetAdaptor *padaptor = glade_widget_get_adaptor (parent);
1361           GladeInternalChild *internal;
1362 
1363           internal = gwa_internal_child_find (padaptor->priv->internal_children,
1364                                               name);
1365 
1366           if (internal && internal->children)
1367             glade_internal_child_append (padaptor, glade_widget_get_object (parent),
1368                                          internal->children, &children);
1369         }
1370 
1371       return children;
1372     }
1373 
1374   glade_internal_child_append (adaptor, object,
1375                                adaptor->priv->internal_children,
1376                                &children);
1377 
1378   return children;
1379 }
1380 
1381 
1382 /*******************************************************************************
1383             GladeWidgetAdaptor type registration and class initializer
1384  *******************************************************************************/
1385 static void
glade_widget_adaptor_init(GladeWidgetAdaptor * adaptor)1386 glade_widget_adaptor_init (GladeWidgetAdaptor *adaptor)
1387 {
1388   adaptor->priv = glade_widget_adaptor_get_instance_private (adaptor);
1389 
1390 }
1391 
1392 static void
glade_widget_adaptor_class_init(GladeWidgetAdaptorClass * adaptor_class)1393 glade_widget_adaptor_class_init (GladeWidgetAdaptorClass *adaptor_class)
1394 {
1395   GObjectClass *object_class;
1396   g_return_if_fail (adaptor_class != NULL);
1397 
1398   glade_widget_adaptor_parent_class = g_type_class_peek_parent (adaptor_class);
1399   object_class = G_OBJECT_CLASS (adaptor_class);
1400 
1401   /* GObjectClass */
1402   object_class->constructor = glade_widget_adaptor_constructor;
1403   object_class->finalize = glade_widget_adaptor_finalize;
1404   object_class->set_property = glade_widget_adaptor_real_set_property;
1405   object_class->get_property = glade_widget_adaptor_real_get_property;
1406 
1407   /* Class methods */
1408   adaptor_class->create_widget = glade_widget_adaptor_object_create_widget;
1409   adaptor_class->construct_object = glade_widget_adaptor_object_construct_object;
1410   adaptor_class->destroy_object = glade_widget_adaptor_object_destroy_object;
1411   adaptor_class->deep_post_create = NULL;
1412   adaptor_class->post_create = NULL;
1413   adaptor_class->get_internal_child = glade_widget_adaptor_object_get_internal_child;
1414   adaptor_class->verify_property = NULL;
1415   adaptor_class->set_property = glade_widget_adaptor_object_set_property;
1416   adaptor_class->get_property = glade_widget_adaptor_object_get_property;
1417   adaptor_class->add_verify = glade_widget_adaptor_object_add_verify;
1418   adaptor_class->add = NULL;
1419   adaptor_class->remove = NULL;
1420   adaptor_class->replace_child = NULL;
1421   adaptor_class->get_children = glade_widget_adaptor_object_get_children;
1422   adaptor_class->child_set_property = NULL;
1423   adaptor_class->child_get_property = NULL;
1424   adaptor_class->action_activate = glade_widget_adaptor_object_action_activate;
1425   adaptor_class->child_action_activate = glade_widget_adaptor_object_child_action_activate;
1426   adaptor_class->action_submenu = NULL;
1427   adaptor_class->depends = NULL;
1428   adaptor_class->read_widget = glade_widget_adaptor_object_read_widget;
1429   adaptor_class->write_widget = glade_widget_adaptor_object_write_widget;
1430   adaptor_class->write_widget_after = glade_widget_adaptor_object_write_widget_after;
1431   adaptor_class->read_child = glade_widget_adaptor_object_read_child;
1432   adaptor_class->write_child = glade_widget_adaptor_object_write_child;
1433   adaptor_class->create_eprop = glade_widget_adaptor_object_create_eprop;
1434   adaptor_class->string_from_value = glade_widget_adaptor_object_string_from_value;
1435   adaptor_class->create_editable = glade_widget_adaptor_object_create_editable;
1436 
1437   /* Base defaults here */
1438   adaptor_class->toplevel = FALSE;
1439   adaptor_class->use_placeholders = FALSE;
1440   adaptor_class->default_width = -1;
1441   adaptor_class->default_height = -1;
1442 
1443   /* Properties */
1444   g_object_class_install_property
1445       (object_class, PROP_NAME,
1446        g_param_spec_string
1447        ("name", _("Name"),
1448         _("Name of the class"),
1449         NULL, G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY));
1450 
1451   g_object_class_install_property
1452       (object_class, PROP_TYPE,
1453        g_param_spec_gtype
1454        ("type", _("Type"),
1455         _("GType of the class"),
1456         G_TYPE_NONE, G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY));
1457 
1458   g_object_class_install_property
1459       (object_class, PROP_TITLE,
1460        g_param_spec_string
1461        ("title", _("Title"),
1462         _("Translated title for the class used in the glade UI"),
1463         NULL, G_PARAM_READWRITE));
1464 
1465   g_object_class_install_property
1466       (object_class, PROP_GENERIC_NAME,
1467        g_param_spec_string
1468        ("generic-name", _("Generic Name"),
1469         _("Used to generate names of new widgets"),
1470         NULL, G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY));
1471 
1472   g_object_class_install_property
1473       (object_class, PROP_ICON_NAME,
1474        g_param_spec_string
1475        ("icon-name", _("Icon Name"),
1476         _("The icon name"),
1477         DEFAULT_ICON_NAME, G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY));
1478 
1479   g_object_class_install_property
1480       (object_class, PROP_CATALOG,
1481        g_param_spec_string
1482        ("catalog", _("Catalog"),
1483         _("The name of the widget catalog this class was declared by"),
1484         NULL, G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY));
1485 
1486   g_object_class_install_property
1487       (object_class, PROP_BOOK,
1488        g_param_spec_string
1489        ("book", _("Book"),
1490         _("DevHelp search namespace for this widget class"),
1491         NULL, G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY));
1492 
1493   g_object_class_install_property
1494       (object_class, PROP_SPECIAL_TYPE,
1495        g_param_spec_string
1496        ("special-child-type", _("Special Child Type"),
1497         _("Holds the name of the packing property to depict "
1498           "special children for this container class"),
1499         NULL, G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY));
1500 
1501   g_object_class_install_property
1502       (object_class, PROP_CURSOR,
1503        g_param_spec_pointer
1504        ("cursor", _("Cursor"),
1505         _("A cursor for inserting widgets in the UI"), G_PARAM_READABLE));
1506   g_object_class_install_property
1507       (object_class, PROP_QUERY,
1508        g_param_spec_boolean
1509        ("query", _("Query"),
1510         _("Whether the adaptor should query the use or not"), FALSE, G_PARAM_READWRITE));
1511 }
1512 
1513 /*******************************************************************************
1514                         Synthetic Object Derivation
1515  *******************************************************************************/
1516 typedef struct
1517 {
1518   GladeXmlNode *node;
1519   GModule *module;
1520 } GWADerivedClassData;
1521 
1522 static void
gwa_derived_init(GladeWidgetAdaptor * adaptor,gpointer g_class)1523 gwa_derived_init (GladeWidgetAdaptor *adaptor, gpointer g_class)
1524 {
1525 
1526 }
1527 
1528 static void
gwa_warn_deprecated_if_symbol_found(GladeXmlNode * node,gchar * tagname)1529 gwa_warn_deprecated_if_symbol_found (GladeXmlNode *node, gchar *tagname)
1530 {
1531   gchar *symbol;
1532 
1533   if ((symbol = glade_xml_get_value_string (node, tagname)))
1534     {
1535       g_warning ("GladeWidgetAdaptor %s method is deprecated. %s() will not be used",
1536                  tagname, symbol);
1537       g_free (symbol);
1538     }
1539 }
1540 
1541 static void
gwa_extend_with_node_load_sym(GladeWidgetAdaptorClass * klass,GladeXmlNode * node,GModule * module)1542 gwa_extend_with_node_load_sym (GladeWidgetAdaptorClass *klass,
1543                                GladeXmlNode            *node,
1544                                GModule                 *module)
1545 {
1546   GObjectClass *object_class = G_OBJECT_CLASS (klass);
1547   gpointer symbol;
1548 
1549   /*
1550    * We use a temporary variable to avoid a bogus gcc warning.
1551    * the thing it that g_module_symbol() should use a function pointer
1552    * instead of a gpointer!
1553    */
1554   if (glade_xml_load_sym_from_node (node, module,
1555                                     GLADE_TAG_CONSTRUCTOR_FUNCTION, &symbol))
1556     object_class->constructor = symbol;
1557 
1558   if (glade_xml_load_sym_from_node (node, module,
1559                                     GLADE_TAG_CREATE_WIDGET_FUNCTION, &symbol))
1560     klass->create_widget = symbol;
1561 
1562   if (glade_xml_load_sym_from_node (node, module,
1563                                     GLADE_TAG_CONSTRUCT_OBJECT_FUNCTION,
1564                                     &symbol))
1565     klass->construct_object = symbol;
1566 
1567   if (glade_xml_load_sym_from_node (node, module,
1568                                     GLADE_TAG_DESTROY_OBJECT_FUNCTION,
1569                                     &symbol))
1570     klass->destroy_object = symbol;
1571 
1572   if (glade_xml_load_sym_from_node (node, module,
1573                                     GLADE_TAG_DEEP_POST_CREATE_FUNCTION,
1574                                     &symbol))
1575     klass->deep_post_create = symbol;
1576 
1577   if (glade_xml_load_sym_from_node (node, module,
1578                                     GLADE_TAG_POST_CREATE_FUNCTION, &symbol))
1579     klass->post_create = symbol;
1580 
1581   if (glade_xml_load_sym_from_node (node, module,
1582                                     GLADE_TAG_SET_FUNCTION, &symbol))
1583     klass->set_property = symbol;
1584 
1585   if (glade_xml_load_sym_from_node (node, module,
1586                                     GLADE_TAG_GET_FUNCTION, &symbol))
1587     klass->get_property = symbol;
1588 
1589   if (glade_xml_load_sym_from_node (node, module,
1590                                     GLADE_TAG_VERIFY_FUNCTION, &symbol))
1591     klass->verify_property = symbol;
1592 
1593   if (glade_xml_load_sym_from_node (node, module,
1594                                     GLADE_TAG_ADD_CHILD_VERIFY_FUNCTION, &symbol))
1595     klass->add_verify = symbol;
1596 
1597   if (glade_xml_load_sym_from_node (node, module,
1598                                     GLADE_TAG_ADD_CHILD_FUNCTION, &symbol))
1599     klass->add = symbol;
1600 
1601   if (glade_xml_load_sym_from_node (node, module,
1602                                     GLADE_TAG_REMOVE_CHILD_FUNCTION, &symbol))
1603     klass->remove = symbol;
1604 
1605   if (glade_xml_load_sym_from_node (node, module,
1606                                     GLADE_TAG_REPLACE_CHILD_FUNCTION, &symbol))
1607     klass->replace_child = symbol;
1608 
1609   if (glade_xml_load_sym_from_node (node, module,
1610                                     GLADE_TAG_GET_CHILDREN_FUNCTION, &symbol))
1611     klass->get_children = symbol;
1612 
1613   if (glade_xml_load_sym_from_node (node, module,
1614                                     GLADE_TAG_CHILD_SET_PROP_FUNCTION, &symbol))
1615     klass->child_set_property = symbol;
1616 
1617   if (glade_xml_load_sym_from_node (node, module,
1618                                     GLADE_TAG_CHILD_GET_PROP_FUNCTION, &symbol))
1619     klass->child_get_property = symbol;
1620 
1621   if (glade_xml_load_sym_from_node (node, module,
1622                                     GLADE_TAG_CHILD_VERIFY_FUNCTION, &symbol))
1623     klass->child_verify_property = symbol;
1624 
1625   if (glade_xml_load_sym_from_node (node, module,
1626                                     GLADE_TAG_GET_INTERNAL_CHILD_FUNCTION,
1627                                     &symbol))
1628     klass->get_internal_child = symbol;
1629 
1630   if (glade_xml_load_sym_from_node (node, module,
1631                                     GLADE_TAG_ACTION_ACTIVATE_FUNCTION,
1632                                     &symbol))
1633     klass->action_activate = symbol;
1634 
1635   if (glade_xml_load_sym_from_node (node, module,
1636                                     GLADE_TAG_CHILD_ACTION_ACTIVATE_FUNCTION,
1637                                     &symbol))
1638     klass->child_action_activate = symbol;
1639 
1640   if (glade_xml_load_sym_from_node (node, module,
1641                                     GLADE_TAG_ACTION_SUBMENU_FUNCTION, &symbol))
1642     klass->action_submenu = symbol;
1643 
1644   /* depends method is deprecated, warn the user */
1645   gwa_warn_deprecated_if_symbol_found (node, GLADE_TAG_DEPENDS_FUNCTION);
1646 
1647   if (glade_xml_load_sym_from_node (node, module,
1648                                     GLADE_TAG_READ_WIDGET_FUNCTION, &symbol))
1649     klass->read_widget = symbol;
1650 
1651   if (glade_xml_load_sym_from_node (node, module,
1652                                     GLADE_TAG_WRITE_WIDGET_FUNCTION, &symbol))
1653     klass->write_widget = symbol;
1654 
1655   if (glade_xml_load_sym_from_node (node, module,
1656                                     GLADE_TAG_WRITE_WIDGET_AFTER_FUNCTION, &symbol))
1657     klass->write_widget_after = symbol;
1658 
1659   if (glade_xml_load_sym_from_node (node, module,
1660                                     GLADE_TAG_READ_CHILD_FUNCTION, &symbol))
1661     klass->read_child = symbol;
1662 
1663   if (glade_xml_load_sym_from_node (node, module,
1664                                     GLADE_TAG_WRITE_CHILD_FUNCTION, &symbol))
1665     klass->write_child = symbol;
1666 
1667   if (glade_xml_load_sym_from_node (node, module,
1668                                     GLADE_TAG_CREATE_EPROP_FUNCTION, &symbol))
1669     klass->create_eprop = symbol;
1670 
1671   if (glade_xml_load_sym_from_node (node, module,
1672                                     GLADE_TAG_STRING_FROM_VALUE_FUNCTION,
1673                                     &symbol))
1674     klass->string_from_value = symbol;
1675 
1676   if (glade_xml_load_sym_from_node (node, module,
1677                                     GLADE_TAG_CREATE_EDITABLE_FUNCTION,
1678                                     &symbol))
1679     klass->create_editable = symbol;
1680 
1681 }
1682 
1683 static void
gwa_derived_class_init(GladeWidgetAdaptorClass * adaptor_class,GWADerivedClassData * data)1684 gwa_derived_class_init (GladeWidgetAdaptorClass *adaptor_class,
1685                         GWADerivedClassData     *data)
1686 {
1687   GladeXmlNode *node = data->node;
1688   GModule *module = data->module;
1689 
1690   /* Load catalog symbols from module */
1691   if (module)
1692     gwa_extend_with_node_load_sym (adaptor_class, node, module);
1693 
1694   glade_xml_get_property_version
1695       (node, GLADE_TAG_VERSION_SINCE,
1696        &adaptor_class->version_since_major,
1697        &adaptor_class->version_since_minor);
1698 
1699   adaptor_class->deprecated =
1700       glade_xml_get_property_boolean
1701       (node, GLADE_TAG_DEPRECATED, adaptor_class->deprecated);
1702 
1703   adaptor_class->toplevel =
1704       glade_xml_get_property_boolean
1705       (node, GLADE_TAG_TOPLEVEL, adaptor_class->toplevel);
1706 
1707   adaptor_class->use_placeholders =
1708       glade_xml_get_property_boolean
1709       (node, GLADE_TAG_USE_PLACEHOLDERS, adaptor_class->use_placeholders);
1710 
1711   adaptor_class->default_width =
1712       glade_xml_get_property_int
1713       (node, GLADE_TAG_DEFAULT_WIDTH, adaptor_class->default_width);
1714 
1715   adaptor_class->default_height =
1716       glade_xml_get_property_int
1717       (node, GLADE_TAG_DEFAULT_HEIGHT, adaptor_class->default_height);
1718 }
1719 
1720 static GType
gwa_derive_adaptor_for_type(GType object_type,GWADerivedClassData * data)1721 gwa_derive_adaptor_for_type (GType object_type, GWADerivedClassData *data)
1722 {
1723   GladeWidgetAdaptor *adaptor;
1724   GType iter_type, derived_type;
1725   GType parent_type = GLADE_TYPE_WIDGET_ADAPTOR;
1726   gchar *type_name;
1727   GTypeInfo adaptor_info = {
1728     sizeof (GladeWidgetAdaptorClass),
1729     (GBaseInitFunc) NULL,
1730     (GBaseFinalizeFunc) NULL,
1731     (GClassInitFunc) gwa_derived_class_init,
1732     (GClassFinalizeFunc) NULL,
1733     data,                       /* class_data */
1734     sizeof (GladeWidgetAdaptor),
1735     0,                          /* n_preallocs */
1736     (GInstanceInitFunc) gwa_derived_init,
1737   };
1738 
1739   for (iter_type = g_type_parent (object_type);
1740        iter_type > 0; iter_type = g_type_parent (iter_type))
1741     {
1742       if ((adaptor = glade_widget_adaptor_get_by_type (iter_type)) != NULL)
1743         {
1744           parent_type = G_TYPE_FROM_INSTANCE (adaptor);
1745           break;
1746         }
1747     }
1748 
1749   /* Note that we must pass ownership of the type_name string
1750    * to the type system
1751    */
1752   type_name = g_strdup_printf ("Glade%sAdaptor", g_type_name (object_type));
1753   derived_type = g_type_register_static (parent_type, type_name,
1754                                          &adaptor_info, 0);
1755   g_free (type_name);
1756 
1757   return derived_type;
1758 }
1759 
1760 
1761 /*******************************************************************************
1762                                      API
1763  *******************************************************************************/
1764 GType
glade_widget_adaptor_get_object_type(GladeWidgetAdaptor * adaptor)1765 glade_widget_adaptor_get_object_type (GladeWidgetAdaptor *adaptor)
1766 {
1767   g_return_val_if_fail (GLADE_IS_WIDGET_ADAPTOR (adaptor), G_TYPE_INVALID);
1768 
1769   return adaptor->priv->type;
1770 }
1771 
1772 G_CONST_RETURN gchar *
glade_widget_adaptor_get_name(GladeWidgetAdaptor * adaptor)1773 glade_widget_adaptor_get_name (GladeWidgetAdaptor *adaptor)
1774 {
1775   g_return_val_if_fail (GLADE_IS_WIDGET_ADAPTOR (adaptor), NULL);
1776 
1777   return adaptor->priv->name;
1778 }
1779 
1780 G_CONST_RETURN gchar *
glade_widget_adaptor_get_generic_name(GladeWidgetAdaptor * adaptor)1781 glade_widget_adaptor_get_generic_name (GladeWidgetAdaptor *adaptor)
1782 {
1783   g_return_val_if_fail (GLADE_IS_WIDGET_ADAPTOR (adaptor), NULL);
1784 
1785   return adaptor->priv->generic_name;
1786 }
1787 
1788 G_CONST_RETURN gchar *
glade_widget_adaptor_get_title(GladeWidgetAdaptor * adaptor)1789 glade_widget_adaptor_get_title (GladeWidgetAdaptor *adaptor)
1790 {
1791   g_return_val_if_fail (GLADE_IS_WIDGET_ADAPTOR (adaptor), NULL);
1792 
1793   return adaptor->priv->title;
1794 }
1795 
1796 G_CONST_RETURN gchar *
glade_widget_adaptor_get_icon_name(GladeWidgetAdaptor * adaptor)1797 glade_widget_adaptor_get_icon_name (GladeWidgetAdaptor *adaptor)
1798 {
1799   g_return_val_if_fail (GLADE_IS_WIDGET_ADAPTOR (adaptor), NULL);
1800 
1801   return adaptor->priv->icon_name;
1802 }
1803 
1804 G_CONST_RETURN gchar *
glade_widget_adaptor_get_missing_icon(GladeWidgetAdaptor * adaptor)1805 glade_widget_adaptor_get_missing_icon (GladeWidgetAdaptor *adaptor)
1806 {
1807   g_return_val_if_fail (GLADE_IS_WIDGET_ADAPTOR (adaptor), NULL);
1808 
1809   return adaptor->priv->missing_icon;
1810 }
1811 
1812 G_CONST_RETURN gchar *
glade_widget_adaptor_get_catalog(GladeWidgetAdaptor * adaptor)1813 glade_widget_adaptor_get_catalog (GladeWidgetAdaptor *adaptor)
1814 {
1815   g_return_val_if_fail (GLADE_IS_WIDGET_ADAPTOR (adaptor), NULL);
1816 
1817   return adaptor->priv->catalog;
1818 }
1819 
1820 G_CONST_RETURN gchar *
glade_widget_adaptor_get_book(GladeWidgetAdaptor * adaptor)1821 glade_widget_adaptor_get_book (GladeWidgetAdaptor *adaptor)
1822 {
1823   g_return_val_if_fail (GLADE_IS_WIDGET_ADAPTOR (adaptor), NULL);
1824 
1825   return adaptor->priv->book;
1826 }
1827 
1828 G_CONST_RETURN GList *
glade_widget_adaptor_get_properties(GladeWidgetAdaptor * adaptor)1829 glade_widget_adaptor_get_properties (GladeWidgetAdaptor *adaptor)
1830 {
1831   g_return_val_if_fail (GLADE_IS_WIDGET_ADAPTOR (adaptor), NULL);
1832 
1833   return adaptor->priv->properties;
1834 }
1835 
1836 G_CONST_RETURN GList *
glade_widget_adaptor_get_packing_props(GladeWidgetAdaptor * adaptor)1837 glade_widget_adaptor_get_packing_props (GladeWidgetAdaptor *adaptor)
1838 {
1839   g_return_val_if_fail (GLADE_IS_WIDGET_ADAPTOR (adaptor), NULL);
1840 
1841   return adaptor->priv->packing_props;
1842 }
1843 
1844 G_CONST_RETURN GList *
glade_widget_adaptor_get_signals(GladeWidgetAdaptor * adaptor)1845 glade_widget_adaptor_get_signals (GladeWidgetAdaptor *adaptor)
1846 {
1847   g_return_val_if_fail (GLADE_IS_WIDGET_ADAPTOR (adaptor), NULL);
1848 
1849   return adaptor->priv->signals;
1850 }
1851 
1852 static void
accum_adaptor(gpointer key,GladeWidgetAdaptor * adaptor,GList ** list)1853 accum_adaptor (gpointer key, GladeWidgetAdaptor *adaptor, GList **list)
1854 {
1855   *list = g_list_prepend (*list, adaptor);
1856 }
1857 
1858 /**
1859  * glade_widget_adaptor_list_adaptors:
1860  *
1861  * Compiles a list of all registered adaptors.
1862  *
1863  * Returns: A newly allocated #GList which must be freed with g_list_free()
1864  */
1865 GList *
glade_widget_adaptor_list_adaptors(void)1866 glade_widget_adaptor_list_adaptors (void)
1867 {
1868   GList *adaptors = NULL;
1869 
1870   g_hash_table_foreach (adaptor_hash, (GHFunc) accum_adaptor, &adaptors);
1871 
1872   return adaptors;
1873 }
1874 
1875 /**
1876  * glade_widget_adaptor_register:
1877  * @adaptor: A #GladeWidgetAdaptor
1878  *
1879  * Registers @adaptor into the Glade core (every supported
1880  * object type must have a registered adaptor).
1881  */
1882 void
glade_widget_adaptor_register(GladeWidgetAdaptor * adaptor)1883 glade_widget_adaptor_register (GladeWidgetAdaptor *adaptor)
1884 {
1885 
1886   g_return_if_fail (GLADE_IS_WIDGET_ADAPTOR (adaptor));
1887 
1888   if (glade_widget_adaptor_get_by_name (adaptor->priv->name))
1889     {
1890       g_warning ("Adaptor class for '%s' already registered", adaptor->priv->name);
1891       return;
1892     }
1893 
1894   if (!adaptor_hash)
1895     adaptor_hash = g_hash_table_new_full (g_direct_hash, g_direct_equal,
1896                                           NULL, g_object_unref);
1897 
1898   g_hash_table_insert (adaptor_hash, GSIZE_TO_POINTER (adaptor->priv->real_type), adaptor);
1899 
1900   g_signal_emit_by_name (glade_app_get (), "widget-adaptor-registered", adaptor, NULL);
1901 }
1902 
1903 static GladePackingDefault *
gwa_default_from_child_packing(GladeChildPacking * packing,const gchar * id)1904 gwa_default_from_child_packing (GladeChildPacking *packing, const gchar *id)
1905 {
1906   GList *list;
1907 
1908   for (list = packing->packing_defaults; list; list = list->next)
1909     {
1910       GladePackingDefault *def = list->data;
1911 
1912       if (id && !strcmp (id, def->id))
1913         return def;
1914     }
1915 
1916   return NULL;
1917 }
1918 
1919 static GladeChildPacking *
glade_widget_adaptor_get_child_packing(GladeWidgetAdaptor * child_adaptor,const gchar * parent_name)1920 glade_widget_adaptor_get_child_packing (GladeWidgetAdaptor *child_adaptor,
1921                                         const gchar        *parent_name)
1922 {
1923   GList *l;
1924 
1925   for (l = child_adaptor->priv->child_packings; l; l = l->next)
1926     {
1927       GladeChildPacking *packing;
1928 
1929       packing = (GladeChildPacking *) l->data;
1930 
1931       if (!strcmp (packing->parent_name, parent_name))
1932         return packing;
1933     }
1934 
1935   return NULL;
1936 }
1937 
1938 static void
gwa_set_packing_defaults_from_node(GladeWidgetAdaptor * adaptor,GladeXmlNode * node)1939 gwa_set_packing_defaults_from_node (GladeWidgetAdaptor *adaptor,
1940                                     GladeXmlNode       *node)
1941 {
1942   GladeXmlNode *child;
1943 
1944   for (child = glade_xml_node_get_children (node);
1945        child; child = glade_xml_node_next (child))
1946     {
1947       gchar *name;
1948       GladeXmlNode *prop_node;
1949       GladeChildPacking *packing;
1950 
1951       if (!glade_xml_node_verify (child, GLADE_TAG_PARENT_CLASS))
1952         continue;
1953 
1954       if ((name = glade_xml_get_property_string_required
1955            (child, GLADE_TAG_NAME, adaptor->priv->name)) == NULL)
1956         continue;
1957 
1958       /* If a GladeChildPacking exists for this parent, use it -
1959        * otherwise prepend a new one
1960        */
1961       if ((packing =
1962            glade_widget_adaptor_get_child_packing (adaptor, name)) == NULL)
1963         {
1964 
1965           packing = g_new0 (GladeChildPacking, 1);
1966           packing->parent_name = name;
1967 
1968           adaptor->priv->child_packings =
1969               g_list_prepend (adaptor->priv->child_packings, packing);
1970 
1971         }
1972 
1973       for (prop_node = glade_xml_node_get_children (child);
1974            prop_node; prop_node = glade_xml_node_next (prop_node))
1975         {
1976           GladePackingDefault *def;
1977           gchar *id;
1978           gchar *value;
1979 
1980           if ((id =
1981                glade_xml_get_property_string_required
1982                (prop_node, GLADE_TAG_ID, adaptor->priv->name)) == NULL)
1983             continue;
1984 
1985           if ((value =
1986                glade_xml_get_property_string_required
1987                (prop_node, GLADE_TAG_DEFAULT, adaptor->priv->name)) == NULL)
1988             {
1989               g_free (id);
1990               continue;
1991             }
1992 
1993           if ((def = gwa_default_from_child_packing (packing, id)) == NULL)
1994             {
1995               def = g_new0 (GladePackingDefault, 1);
1996               def->id = id;
1997               def->value = value;
1998 
1999               packing->packing_defaults =
2000                   g_list_prepend (packing->packing_defaults, def);
2001             }
2002           else
2003             {
2004               g_free (id);
2005               g_free (def->value);
2006               def->value = value;
2007             }
2008 
2009           adaptor->priv->child_packings =
2010               g_list_prepend (adaptor->priv->child_packings, packing);
2011 
2012         }
2013     }
2014 }
2015 
2016 static void
gwa_update_properties_from_node(GladeWidgetAdaptor * adaptor,GladeXmlNode * node,GModule * module,GList ** properties,const gchar * domain,gboolean is_packing)2017 gwa_update_properties_from_node (GladeWidgetAdaptor *adaptor,
2018                                  GladeXmlNode       *node,
2019                                  GModule            *module,
2020                                  GList             **properties,
2021                                  const gchar        *domain,
2022                                  gboolean            is_packing)
2023 {
2024   GladeXmlNode *child;
2025 
2026   for (child = glade_xml_node_get_children (node);
2027        child; child = glade_xml_node_next (child))
2028     {
2029       gchar *id;
2030       GList *list;
2031       GladePropertyClass *property_class;
2032       gboolean updated;
2033 
2034       if (!glade_xml_node_verify (child, GLADE_TAG_PROPERTY))
2035         continue;
2036 
2037       id = glade_xml_get_property_string_required
2038           (child, GLADE_TAG_ID, adaptor->priv->name);
2039       if (!id)
2040         continue;
2041 
2042       /* property names from catalogs also need to have the '-' form */
2043       glade_util_replace (id, '_', '-');
2044 
2045       /* find the property in our list, if not found append a new property */
2046       for (list = *properties; list && list->data; list = list->next)
2047         {
2048           property_class = GLADE_PROPERTY_CLASS (list->data);
2049           if (glade_property_class_id (property_class) != NULL &&
2050               g_ascii_strcasecmp (id, glade_property_class_id (property_class)) == 0)
2051             break;
2052         }
2053 
2054       if (list)
2055         {
2056           property_class = GLADE_PROPERTY_CLASS (list->data);
2057         }
2058       else
2059         {
2060           property_class = glade_property_class_new (adaptor, id);
2061 
2062           /* When creating new virtual packing properties,
2063            * make sure we mark them as such here.
2064            */
2065           if (is_packing)
2066             glade_property_class_set_is_packing (property_class, TRUE);
2067 
2068           *properties = g_list_append (*properties, property_class);
2069           list = g_list_last (*properties);
2070         }
2071 
2072       if ((updated = glade_property_class_update_from_node (child,
2073 							    adaptor->priv->type,
2074 							    &property_class,
2075 							    domain)) == FALSE)
2076         {
2077           g_warning ("failed to update %s property of %s from xml",
2078                      id, adaptor->priv->name);
2079           g_free (id);
2080           continue;
2081         }
2082 
2083       /* if this pointer was set to null, its a property we dont handle. */
2084       if (!property_class)
2085         *properties = g_list_delete_link (*properties, list);
2086 
2087       g_free (id);
2088     }
2089 }
2090 
2091 static GParamSpec *
pspec_dup(GParamSpec * spec)2092 pspec_dup (GParamSpec *spec)
2093 {
2094   const gchar *name, *nick, *blurb;
2095   GType spec_type, value_type;
2096   GParamSpec *pspec = NULL;
2097 
2098   spec_type = G_PARAM_SPEC_TYPE (spec);
2099   value_type = spec->value_type;
2100 
2101   name = g_param_spec_get_name (spec);
2102   nick = g_param_spec_get_nick (spec);
2103   blurb = g_param_spec_get_blurb (spec);
2104 
2105   if (spec_type == G_TYPE_PARAM_ENUM ||
2106       spec_type == G_TYPE_PARAM_FLAGS ||
2107       spec_type == G_TYPE_PARAM_BOXED ||
2108       spec_type == G_TYPE_PARAM_OBJECT || spec_type == GLADE_TYPE_PARAM_OBJECTS)
2109     {
2110 
2111       if (spec_type == G_TYPE_PARAM_ENUM)
2112         {
2113           GParamSpecEnum *p = (GParamSpecEnum *) spec;
2114           pspec =
2115               g_param_spec_enum (name, nick, blurb, value_type,
2116                                  p->default_value, 0);
2117         }
2118       else if (spec_type == G_TYPE_PARAM_FLAGS)
2119         {
2120           GParamSpecFlags *p = (GParamSpecFlags *) spec;
2121           pspec =
2122               g_param_spec_flags (name, nick, blurb, value_type,
2123                                   p->default_value, 0);
2124         }
2125       else if (spec_type == G_TYPE_PARAM_OBJECT)
2126         pspec = g_param_spec_object (name, nick, blurb, value_type, 0);
2127       else if (spec_type == GLADE_TYPE_PARAM_OBJECTS)
2128         pspec = glade_param_spec_objects (name, nick, blurb, value_type, 0);
2129       else
2130         pspec = g_param_spec_boxed (name, nick, blurb, value_type, 0);
2131     }
2132   else if (spec_type == G_TYPE_PARAM_STRING)
2133     {
2134       GParamSpecString *p = (GParamSpecString *) spec;
2135       pspec = g_param_spec_string (name, nick, blurb, p->default_value, 0);
2136     }
2137   else if (spec_type == G_TYPE_PARAM_BOOLEAN)
2138     {
2139       GParamSpecBoolean *p = (GParamSpecBoolean *) spec;
2140       pspec = g_param_spec_boolean (name, nick, blurb, p->default_value, 0);
2141     }
2142   else
2143     {
2144       if (spec_type == G_TYPE_PARAM_CHAR)
2145         {
2146           GParamSpecChar *p = (GParamSpecChar *) spec;
2147           pspec = g_param_spec_char (name, nick, blurb,
2148                                      p->minimum, p->maximum, p->default_value,
2149                                      0);
2150         }
2151       else if (spec_type == G_TYPE_PARAM_UCHAR)
2152         {
2153           GParamSpecUChar *p = (GParamSpecUChar *) spec;
2154           pspec = g_param_spec_uchar (name, nick, blurb,
2155                                       p->minimum, p->maximum, p->default_value,
2156                                       0);
2157         }
2158       else if (spec_type == G_TYPE_PARAM_INT)
2159         {
2160           GParamSpecInt *p = (GParamSpecInt *) spec;
2161           pspec = g_param_spec_int (name, nick, blurb,
2162                                     p->minimum, p->maximum, p->default_value,
2163                                     0);
2164         }
2165       else if (spec_type == G_TYPE_PARAM_UINT)
2166         {
2167           GParamSpecUInt *p = (GParamSpecUInt *) spec;
2168           pspec = g_param_spec_uint (name, nick, blurb,
2169                                      p->minimum, p->maximum, p->default_value,
2170                                      0);
2171         }
2172       else if (spec_type == G_TYPE_PARAM_LONG)
2173         {
2174           GParamSpecLong *p = (GParamSpecLong *) spec;
2175           pspec = g_param_spec_long (name, nick, blurb,
2176                                      p->minimum, p->maximum, p->default_value,
2177                                      0);
2178         }
2179       else if (spec_type == G_TYPE_PARAM_ULONG)
2180         {
2181           GParamSpecULong *p = (GParamSpecULong *) spec;
2182           pspec = g_param_spec_ulong (name, nick, blurb,
2183                                       p->minimum, p->maximum, p->default_value,
2184                                       0);
2185         }
2186       else if (spec_type == G_TYPE_PARAM_INT64)
2187         {
2188           GParamSpecInt64 *p = (GParamSpecInt64 *) spec;
2189           pspec = g_param_spec_int64 (name, nick, blurb,
2190                                       p->minimum, p->maximum, p->default_value,
2191                                       0);
2192         }
2193       else if (spec_type == G_TYPE_PARAM_UINT64)
2194         {
2195           GParamSpecUInt64 *p = (GParamSpecUInt64 *) spec;
2196           pspec = g_param_spec_uint64 (name, nick, blurb,
2197                                        p->minimum, p->maximum, p->default_value,
2198                                        0);
2199         }
2200       else if (spec_type == G_TYPE_PARAM_FLOAT)
2201         {
2202           GParamSpecFloat *p = (GParamSpecFloat *) spec;
2203           pspec = g_param_spec_float (name, nick, blurb,
2204                                       p->minimum, p->maximum, p->default_value,
2205                                       0);
2206         }
2207       else if (spec_type == G_TYPE_PARAM_DOUBLE)
2208         {
2209           GParamSpecDouble *p = (GParamSpecDouble *) spec;
2210           pspec = g_param_spec_float (name, nick, blurb,
2211                                       p->minimum, p->maximum, p->default_value,
2212                                       0);
2213         }
2214     }
2215   return pspec;
2216 }
2217 
2218 static void
gwa_update_properties_from_type(GladeWidgetAdaptor * adaptor,GType type,GList ** properties,gboolean is_packing)2219 gwa_update_properties_from_type (GladeWidgetAdaptor *adaptor,
2220                                  GType               type,
2221                                  GList             **properties,
2222                                  gboolean            is_packing)
2223 {
2224   gpointer object_class = g_type_class_ref (type);
2225   GParamSpec **specs = NULL, *spec;
2226   guint i, n_specs = 0;
2227 
2228   /* only GtkContainer child propeties can be introspected */
2229   if (is_packing && !g_type_is_a (adaptor->priv->type, GTK_TYPE_CONTAINER))
2230     return;
2231 
2232   if (is_packing)
2233     specs = gtk_container_class_list_child_properties (object_class, &n_specs);
2234   else
2235     specs = g_object_class_list_properties (object_class, &n_specs);
2236 
2237   for (i = 0; i < n_specs; i++)
2238     {
2239       GladePropertyClass *property_class;
2240       GList *list;
2241 
2242       /* find the property in our list, if not found append a new property */
2243       for (list = *properties; list && list->data; list = list->next)
2244         {
2245           property_class = GLADE_PROPERTY_CLASS (list->data);
2246           if (glade_property_class_id (property_class) != NULL &&
2247               g_ascii_strcasecmp (specs[i]->name, glade_property_class_id (property_class)) == 0)
2248             break;
2249         }
2250 
2251       if (list == NULL && (specs[i]->flags & G_PARAM_WRITABLE) &&
2252           (spec = pspec_dup (specs[i])))
2253         {
2254           property_class = glade_property_class_new (adaptor, spec->name);
2255 
2256 	  glade_property_class_set_pspec (property_class, spec);
2257 
2258           /* Make sure we can tell properties apart by there
2259            * owning class.
2260            */
2261           spec->owner_type = adaptor->priv->type;
2262 
2263           /* Disable properties by default since the does not really implement them */
2264 	  glade_property_class_set_virtual (property_class, TRUE);
2265 	  glade_property_class_set_ignore (property_class, TRUE);
2266 
2267 	  glade_property_class_set_tooltip (property_class, g_param_spec_get_blurb (spec));
2268 	  glade_property_class_set_name (property_class, g_param_spec_get_nick (spec));
2269 
2270           if (spec->flags & G_PARAM_CONSTRUCT_ONLY)
2271 	    glade_property_class_set_construct_only (property_class, TRUE);
2272 
2273 	  glade_property_class_load_defaults_from_spec (property_class);
2274 	  glade_property_class_set_is_packing (property_class, is_packing);
2275 
2276           *properties = g_list_append (*properties, property_class);
2277         }
2278     }
2279 
2280   g_free (specs);
2281 }
2282 
2283 static void
gwa_action_update_from_node(GladeWidgetAdaptor * adaptor,gboolean is_packing,GladeXmlNode * node,const gchar * domain,gchar * group_path)2284 gwa_action_update_from_node (GladeWidgetAdaptor *adaptor,
2285                              gboolean            is_packing,
2286                              GladeXmlNode       *node,
2287                              const gchar        *domain,
2288                              gchar              *group_path)
2289 {
2290   GladeXmlNode *child;
2291   gchar *id, *label, *stock, *action_path;
2292   gboolean group, important;
2293 
2294   for (child = glade_xml_node_get_children (node);
2295        child; child = glade_xml_node_next (child))
2296     {
2297       if ((group =
2298            glade_xml_node_verify_silent (child, GLADE_TAG_ACTION)) == FALSE)
2299         continue;
2300 
2301       id = glade_xml_get_property_string_required
2302           (child, GLADE_TAG_ID, adaptor->priv->name);
2303       if (id == NULL)
2304         continue;
2305 
2306       if (group_path)
2307         action_path = g_strdup_printf ("%s/%s", group_path, id);
2308       else
2309         action_path = id;
2310 
2311       label = glade_xml_get_property_string (child, GLADE_TAG_NAME);
2312       stock = glade_xml_get_property_string (child, GLADE_TAG_STOCK);
2313       important =
2314           glade_xml_get_property_boolean (child, GLADE_TAG_IMPORTANT, FALSE);
2315 
2316       if (label)
2317         {
2318           gchar *translated = dgettext (domain, label);
2319           if (label != translated)
2320             {
2321               g_free (label);
2322               label = g_strdup (translated);
2323             }
2324         }
2325 
2326       if (is_packing)
2327         glade_widget_adaptor_pack_action_add (adaptor, action_path, label,
2328                                               stock, important);
2329       else
2330         glade_widget_adaptor_action_add (adaptor, action_path, label, stock,
2331                                          important);
2332 
2333       if (group)
2334         gwa_action_update_from_node (adaptor, is_packing, child, domain,
2335                                      action_path);
2336 
2337       g_free (id);
2338       g_free (label);
2339       g_free (stock);
2340       if (group_path)
2341         g_free (action_path);
2342     }
2343 }
2344 
2345 static void
gwa_set_signals_from_node(GladeWidgetAdaptor * adaptor,GladeXmlNode * node,const gchar * domain)2346 gwa_set_signals_from_node (GladeWidgetAdaptor *adaptor,
2347 			   GladeXmlNode       *node,
2348 			   const gchar        *domain)
2349 {
2350   GladeXmlNode     *child;
2351   GladeSignalClass *signal;
2352   GList            *list;
2353   gchar            *id;
2354 
2355   for (child = glade_xml_node_get_children (node);
2356        child; child = glade_xml_node_next (child))
2357     {
2358       if (!glade_xml_node_verify (child, GLADE_TAG_SIGNAL))
2359         continue;
2360 
2361       if (!(id = glade_xml_get_property_string_required (child, GLADE_TAG_ID, NULL)))
2362         continue;
2363 
2364       if ((list =
2365            g_list_find_custom (adaptor->priv->signals, id,
2366                                (GCompareFunc) gwa_signal_find_comp)) != NULL)
2367         {
2368           signal = list->data;
2369 
2370 	  glade_signal_class_update_from_node (signal, child, domain);
2371         }
2372       g_free (id);
2373     }
2374 }
2375 
2376 static GList *
gwa_internal_children_update_from_node(GList * internal_children,GladeXmlNode * node)2377 gwa_internal_children_update_from_node (GList        *internal_children,
2378                                         GladeXmlNode *node)
2379 {
2380   GList *retval = internal_children;
2381   GladeXmlNode *child, *children;
2382 
2383   for (child = node; child; child = glade_xml_node_next (child))
2384     {
2385       GladeInternalChild *data;
2386       gchar *name;
2387 
2388       if (!glade_xml_node_verify (child, GLADE_XML_TAG_WIDGET))
2389         continue;
2390 
2391       if (!(name = glade_xml_get_property_string_required (child, GLADE_TAG_NAME, NULL)))
2392         continue;
2393 
2394       if ((data = gwa_internal_child_find (retval, name)) == NULL)
2395         {
2396           gboolean anarchist = glade_xml_get_property_boolean (child, GLADE_TAG_ANARCHIST, FALSE);
2397           data = gwa_internal_children_new (name, anarchist);
2398           retval = g_list_prepend (retval, data);
2399         }
2400 
2401       if ((children = glade_xml_search_child (child, GLADE_XML_TAG_WIDGET)))
2402         data->children = gwa_internal_children_update_from_node (data->children, children);
2403 
2404       g_free (name);
2405     }
2406 
2407   return retval;
2408 }
2409 
2410 static gboolean
gwa_extend_with_node(GladeWidgetAdaptor * adaptor,GladeXmlNode * node,GModule * module,const gchar * domain)2411 gwa_extend_with_node (GladeWidgetAdaptor *adaptor,
2412                       GladeXmlNode       *node,
2413                       GModule            *module,
2414                       const gchar        *domain)
2415 {
2416   GladeXmlNode *child;
2417   gchar *child_type;
2418 
2419   /* Override the special-child-type here */
2420   if ((child_type =
2421        glade_xml_get_value_string (node, GLADE_TAG_SPECIAL_CHILD_TYPE)) != NULL)
2422     adaptor->priv->special_child_type =
2423         (g_free (adaptor->priv->special_child_type), child_type);
2424 
2425   if ((child = glade_xml_search_child (node, GLADE_TAG_PROPERTIES)) != NULL)
2426     gwa_update_properties_from_node
2427         (adaptor, child, module, &adaptor->priv->properties, domain, FALSE);
2428 
2429   if ((child =
2430        glade_xml_search_child (node, GLADE_TAG_PACKING_PROPERTIES)) != NULL)
2431     gwa_update_properties_from_node
2432         (adaptor, child, module, &adaptor->priv->packing_props, domain, TRUE);
2433 
2434   if ((child =
2435        glade_xml_search_child (node, GLADE_TAG_PACKING_DEFAULTS)) != NULL)
2436     gwa_set_packing_defaults_from_node (adaptor, child);
2437 
2438   if ((child = glade_xml_search_child (node, GLADE_TAG_SIGNALS)) != NULL)
2439     gwa_set_signals_from_node (adaptor, child, domain);
2440 
2441   if ((child = glade_xml_search_child (node, GLADE_TAG_ACTIONS)) != NULL)
2442     gwa_action_update_from_node (adaptor, FALSE, child, domain, NULL);
2443 
2444   if ((child =
2445        glade_xml_search_child (node, GLADE_TAG_PACKING_ACTIONS)) != NULL)
2446     gwa_action_update_from_node (adaptor, TRUE, child, domain, NULL);
2447 
2448   if ((child = glade_xml_search_child (node, GLADE_TAG_INTERNAL_CHILDREN)))
2449     adaptor->priv->internal_children =
2450       gwa_internal_children_update_from_node (adaptor->priv->internal_children,
2451                                               glade_xml_node_get_children (child));
2452 
2453   return TRUE;
2454 }
2455 
2456 /**
2457  * create_icon_name_for_object_class:
2458  * @class_name: The name of the widget class
2459  * @class_type: The #GType of the adaptor class
2460  * @icon_name:    The icon name as set from the catalog
2461  * @icon_prefix:  The icon prefix as set from the catalog
2462  * @generic_name: The generic name for the widget class
2463  *
2464  * Creates a suitable icon name for an object class, based on several parameters.
2465  *
2466  * Returns: An icon name, or NULL if the object class does not require one.
2467  */
2468 static gchar *
create_icon_name_for_object_class(const gchar * class_name,GType class_type,const gchar * icon_name,const gchar * icon_prefix,const gchar * generic_name)2469 create_icon_name_for_object_class (const gchar *class_name,
2470                                    GType        class_type,
2471                                    const gchar *icon_name,
2472                                    const gchar *icon_prefix,
2473                                    const gchar *generic_name)
2474 {
2475   gchar *name;
2476 
2477   /* only certain object classes need to have icons */
2478   if (G_TYPE_IS_INSTANTIATABLE (class_type) == FALSE ||
2479       G_TYPE_IS_ABSTRACT (class_type) != FALSE || generic_name == NULL)
2480     {
2481       return NULL;
2482     }
2483 
2484   /* if no icon name has been specified, we then fallback to a default icon name */
2485   if (!icon_name)
2486     name = g_strdup_printf ("widget-%s-%s", icon_prefix, generic_name);
2487   else
2488     name = g_strdup (icon_name);
2489 
2490   return name;
2491 }
2492 
2493 static void
gwa_displayable_values_check(GladeWidgetAdaptor * adaptor,gboolean packing)2494 gwa_displayable_values_check (GladeWidgetAdaptor *adaptor, gboolean packing)
2495 {
2496   GList *l, *p = (packing) ? adaptor->priv->packing_props : adaptor->priv->properties;
2497 
2498   for (l = p; l; l = g_list_next (l))
2499     {
2500       GladePropertyClass *klass = l->data;
2501       GParamSpec         *pspec = glade_property_class_get_pspec (klass);
2502 
2503       if (adaptor->priv->type == pspec->owner_type &&
2504 	  glade_property_class_is_visible (klass) &&
2505           (G_IS_PARAM_SPEC_ENUM (pspec) ||
2506            G_IS_PARAM_SPEC_FLAGS (pspec)) &&
2507           !glade_type_has_displayable_values (pspec->value_type) &&
2508           pspec->value_type != GLADE_TYPE_STOCK &&
2509           pspec->value_type != GLADE_TYPE_STOCK_IMAGE)
2510         {
2511           /* We do not need displayable values if the property is not visible */
2512 	  if (g_getenv (GLADE_ENV_TESTING) == NULL)
2513 	    g_message ("No displayable values for %sproperty %s::%s",
2514 		       (packing) ? "child " : "", adaptor->priv->name,
2515 		       glade_property_class_id (klass));
2516         }
2517     }
2518 }
2519 
2520 static GType
generate_type(const char * name,const char * parent_name)2521 generate_type (const char *name, const char *parent_name)
2522 {
2523   GType parent_type, retval;
2524   GTypeQuery query;
2525   GTypeInfo *type_info;
2526   char *new_name;
2527 
2528   g_return_val_if_fail (name != NULL, 0);
2529   g_return_val_if_fail (parent_name != NULL, 0);
2530 
2531   parent_type = glade_util_get_type_from_name (parent_name, FALSE);
2532   g_return_val_if_fail (parent_type != 0, 0);
2533 
2534   g_type_query (parent_type, &query);
2535   g_return_val_if_fail (query.type != 0, 0);
2536 
2537   /*
2538    * If the type already exist it means we want to use the parent type
2539    * instead of the real one at runtime.
2540    * This is currently used to instantiate GtkWindow as a GtkEventBox
2541    * at runtime.
2542    */
2543   if (glade_util_get_type_from_name (name, FALSE))
2544     new_name = g_strconcat ("GladeFake", name, NULL);
2545   else
2546     new_name = NULL;
2547 
2548   type_info = g_new0 (GTypeInfo, 1);
2549   type_info->class_size = query.class_size;
2550   type_info->instance_size = query.instance_size;
2551 
2552   retval = g_type_register_static (parent_type,
2553                                    (new_name) ? new_name : name, type_info, 0);
2554 
2555   g_free (new_name);
2556 
2557   return retval;
2558 }
2559 
2560 static gchar *
generate_deprecated_icon(const gchar * icon_name)2561 generate_deprecated_icon (const gchar *icon_name)
2562 {
2563   static GdkPixbuf *deprecated_pixbuf[2] = { NULL, NULL };
2564   GError        *error = NULL;
2565   GdkPixbuf     *orig_pixbuf[2];
2566   gchar         *deprecated;
2567 
2568   if (strncmp (icon_name, "deprecated-", strlen ("deprecated-")) == 0)
2569     return g_strdup (icon_name);
2570 
2571   /* Get deprecated graphics */
2572   if (!deprecated_pixbuf[0])
2573     {
2574       gchar *filename;
2575 
2576       filename = g_build_filename (glade_app_get_pixmaps_dir (), "deprecated-16x16.png", NULL);
2577 
2578       if ((deprecated_pixbuf[0] = gdk_pixbuf_new_from_file (filename, &error)) == NULL)
2579 	{
2580 	  g_warning ("Unable to render deprecated icon: %s", error->message);
2581 	  error = (g_error_free (error), NULL);
2582 	}
2583       g_free (filename);
2584 
2585       filename = g_build_filename (glade_app_get_pixmaps_dir (), "deprecated-22x22.png", NULL);
2586 
2587       if ((deprecated_pixbuf[1] = gdk_pixbuf_new_from_file (filename, &error)) == NULL)
2588 	{
2589 	  g_warning ("Unable to render deprecated icon: %s", error->message);
2590 	  error = (g_error_free (error), NULL);
2591 	}
2592       g_free (filename);
2593     }
2594 
2595   if (!deprecated_pixbuf[0] || !deprecated_pixbuf[1])
2596       return NULL;
2597 
2598   /* Load pixbuf's for the current icons */
2599   if ((orig_pixbuf[0] =
2600        gtk_icon_theme_load_icon (gtk_icon_theme_get_default (),
2601 				 icon_name, 16, 0, &error)) == NULL)
2602     {
2603       g_warning ("Unable to render icon %s at size 16: %s", icon_name, error->message);
2604       error = (g_error_free (error), NULL);
2605     }
2606   else
2607     {
2608       GdkPixbuf *tmp = gdk_pixbuf_copy (orig_pixbuf[0]);
2609       g_object_unref (orig_pixbuf[0]);
2610       orig_pixbuf[0] = tmp;
2611     }
2612 
2613   if ((orig_pixbuf[1] =
2614        gtk_icon_theme_load_icon (gtk_icon_theme_get_default (),
2615 				 icon_name, 22, 0, &error)) == NULL)
2616     {
2617       g_warning ("Unable to render icon %s at size 22: %s", icon_name, error->message);
2618       error = (g_error_free (error), NULL);
2619     }
2620   else
2621     {
2622       GdkPixbuf *tmp = gdk_pixbuf_copy (orig_pixbuf[1]);
2623       g_object_unref (orig_pixbuf[1]);
2624       orig_pixbuf[1] = tmp;
2625     }
2626 
2627   deprecated = g_strdup_printf ("deprecated-%s", icon_name);
2628 
2629   if (!gtk_icon_theme_has_icon (gtk_icon_theme_get_default (), deprecated))
2630     {
2631       if (orig_pixbuf[0])
2632 	gdk_pixbuf_composite (deprecated_pixbuf[0], orig_pixbuf[0],
2633 				0, 0, 16, 16, 0, 0, 1, 1, GDK_INTERP_NEAREST, 255);
2634 
2635       if (orig_pixbuf[1])
2636 	gdk_pixbuf_composite (deprecated_pixbuf[1], orig_pixbuf[1],
2637 				0, 0, 22, 22, 0, 0, 1, 1, GDK_INTERP_NEAREST, 255);
2638 
2639       gtk_icon_theme_add_builtin_icon (deprecated, 16, orig_pixbuf[0]);
2640       gtk_icon_theme_add_builtin_icon (deprecated, 22, orig_pixbuf[1]);
2641     }
2642 
2643   if (orig_pixbuf[0])
2644     g_object_unref (orig_pixbuf[0]);
2645 
2646   if (orig_pixbuf[1])
2647     g_object_unref (orig_pixbuf[1]);
2648 
2649   return deprecated;
2650 }
2651 
2652 /**
2653  * glade_widget_adaptor_from_catalog:
2654  * @catalog: A #GladeCatalog
2655  * @class_node: the #GladeXmlNode to load
2656  * @module: the plugin GModule.
2657  *
2658  * Dynamicly creates a subclass of #GladeWidgetAdaptor and subclasses
2659  * the closest parent adaptor (parent class adapters must be creates/registerd
2660  * prior to child classes, otherwise inheritance wont work) and parses in
2661  * the relevent catalog info.
2662  */
2663 GladeWidgetAdaptor *
glade_widget_adaptor_from_catalog(GladeCatalog * catalog,GladeXmlNode * class_node,GModule * module)2664 glade_widget_adaptor_from_catalog (GladeCatalog *catalog,
2665                                    GladeXmlNode *class_node,
2666                                    GModule      *module)
2667 {
2668   GladeWidgetAdaptor *adaptor = NULL;
2669   gchar *name, *generic_name, *icon_name, *adaptor_icon_name, *adaptor_name,
2670       *func_name;
2671   gchar *title, *translated_title, *parent_name;
2672   GType object_type, adaptor_type, parent_type;
2673   gchar *missing_icon = NULL;
2674   GWADerivedClassData data;
2675 
2676 
2677   if (!glade_xml_node_verify (class_node, GLADE_TAG_GLADE_WIDGET_CLASS))
2678     {
2679       g_warning ("Widget class node is not '%s'", GLADE_TAG_GLADE_WIDGET_CLASS);
2680       return NULL;
2681     }
2682 
2683   if ((name = glade_xml_get_property_string_required
2684        (class_node, GLADE_TAG_NAME, NULL)) == NULL)
2685     return NULL;
2686 
2687   /* Either get the instance type by:
2688    *
2689    * - Autosubclassing a specified parent type (a fake widget class)
2690    * - parsing the _get_type() function directly from the catalog
2691    * - deriving foo_bar_get_type() from the name FooBar and loading that.
2692    */
2693   if ((parent_name =
2694        glade_xml_get_property_string (class_node, GLADE_TAG_PARENT)) != NULL)
2695     {
2696       if (!glade_widget_adaptor_get_by_name (parent_name))
2697         {
2698           g_warning
2699               ("Trying to define class '%s' for parent class '%s', but parent class '%s' "
2700                "is not registered", name, parent_name, parent_name);
2701           g_free (name);
2702           g_free (parent_name);
2703           return NULL;
2704         }
2705       object_type = generate_type (name, parent_name);
2706       g_free (parent_name);
2707     }
2708   else if ((func_name =
2709             glade_xml_get_property_string (class_node,
2710                                            GLADE_TAG_GET_TYPE_FUNCTION)) != NULL)
2711     {
2712       object_type = glade_util_get_type_from_name (func_name, TRUE);
2713       g_free (func_name);
2714     }
2715   else
2716     {
2717       GType type_iter;
2718 
2719       object_type = glade_util_get_type_from_name (name, FALSE);
2720 
2721       for (type_iter = g_type_parent (object_type);
2722            type_iter; type_iter = g_type_parent (type_iter))
2723         {
2724           GladeWidgetAdaptor *a =
2725               glade_widget_adaptor_get_by_name (g_type_name (type_iter));
2726 
2727           if (a && a->priv->real_type != a->priv->type)
2728             {
2729               object_type = generate_type (name, g_type_name (a->priv->type));
2730               break;
2731             }
2732         }
2733     }
2734 
2735   if (object_type == 0)
2736     {
2737       g_warning ("Failed to load the GType for '%s'", name);
2738       g_free (name);
2739       return NULL;
2740     }
2741 
2742   if (glade_widget_adaptor_get_by_type (object_type))
2743     {
2744       g_warning ("Adaptor class for '%s' already defined",
2745                  g_type_name (object_type));
2746       g_free (name);
2747       return NULL;
2748     }
2749 
2750   if ((adaptor_name =
2751        glade_xml_get_property_string (class_node, GLADE_TAG_ADAPTOR)))
2752     adaptor_type = g_type_from_name (adaptor_name);
2753   else
2754     {
2755       /*
2756        * We use this struct pointer to pass data to
2757        * gwa_derived_class_init() because we must override constructor()
2758        * from the catalog before calling g_object_new() :P
2759        */
2760       data.node = class_node;
2761       data.module = module;
2762       adaptor_type = gwa_derive_adaptor_for_type (object_type, &data);
2763     }
2764 
2765   if (adaptor_type == 0)
2766     {
2767       g_warning ("Failed to get %s's adaptor %s", name,
2768                  (adaptor_name) ? adaptor_name : "");
2769       g_free (adaptor_name);
2770       g_free (name);
2771       return NULL;
2772     }
2773 
2774   generic_name =
2775       glade_xml_get_property_string (class_node, GLADE_TAG_GENERIC_NAME);
2776   icon_name = glade_xml_get_property_string (class_node, GLADE_TAG_ICON_NAME);
2777 
2778   /* get a suitable icon name for adaptor */
2779   adaptor_icon_name =
2780       create_icon_name_for_object_class (name,
2781                                          object_type,
2782                                          icon_name,
2783                                          glade_catalog_get_icon_prefix
2784                                          (catalog), generic_name);
2785 
2786 
2787   /* check if icon is available (a null icon-name is an abstract class) */
2788   if (adaptor_icon_name &&
2789       !gtk_icon_theme_has_icon (gtk_icon_theme_get_default (),
2790                                 adaptor_icon_name))
2791     {
2792       GladeWidgetAdaptor *parent =
2793           glade_widget_adaptor_get_parent_adaptor_by_type (object_type);
2794 
2795       /* Save the desired name */
2796       missing_icon = adaptor_icon_name;
2797 
2798       adaptor_icon_name = g_strdup ((parent && parent->priv->icon_name) ?
2799                                     parent->priv->icon_name : DEFAULT_ICON_NAME);
2800 
2801     }
2802 
2803   adaptor = g_object_new (adaptor_type,
2804                           "type", object_type,
2805                           "name", name,
2806                           "catalog", glade_catalog_get_name (catalog),
2807                           "generic-name", generic_name,
2808                           "icon-name", adaptor_icon_name, NULL);
2809 
2810   adaptor->priv->missing_icon = missing_icon;
2811 
2812   g_free (generic_name);
2813   g_free (icon_name);
2814   g_free (adaptor_icon_name);
2815 
2816 
2817   title = glade_xml_get_property_string_required (class_node,
2818                                                   GLADE_TAG_TITLE,
2819                                                   "This value is needed to "
2820                                                   "display object class names "
2821                                                   "in the UI");
2822   if (title == NULL)
2823     {
2824       g_warning ("Class '%s' declared without a '%s' attribute", name,
2825                  GLADE_TAG_TITLE);
2826       adaptor->priv->title = g_strdup (name);
2827     }
2828   else
2829     {
2830       /* translate */
2831       translated_title = dgettext (glade_catalog_get_domain (catalog), title);
2832       if (translated_title != title)
2833         {
2834           /* gettext owns translated_title */
2835           adaptor->priv->title = g_strdup (translated_title);
2836           g_free (title);
2837         }
2838       else
2839         {
2840           adaptor->priv->title = title;
2841         }
2842     }
2843 
2844   if (G_TYPE_IS_INSTANTIATABLE (adaptor->priv->type) &&
2845       G_TYPE_IS_ABSTRACT (adaptor->priv->type) == FALSE &&
2846       adaptor->priv->generic_name == NULL)
2847     {
2848       g_warning ("Instantiatable class '%s' built without a '%s'",
2849                  name, GLADE_TAG_GENERIC_NAME);
2850     }
2851 
2852   /* if adaptor->priv->type (the runtime used by glade) differs from adaptor->priv->name
2853    * (the name specified in the catalog) means we are using the type specified in the
2854    * the parent tag as the runtime and the class already exist.
2855    * So we need to add the properties and signals from the real class
2856    * even though they wont be aplied at runtime.
2857    */
2858   if (adaptor->priv->type != adaptor->priv->real_type)
2859     {
2860       adaptor->priv->signals = gwa_list_signals (adaptor, adaptor->priv->real_type);
2861 
2862       gwa_update_properties_from_type (adaptor, adaptor->priv->real_type,
2863                                        &adaptor->priv->properties, FALSE);
2864       gwa_update_properties_from_type (adaptor, adaptor->priv->real_type,
2865                                        &adaptor->priv->packing_props, TRUE);
2866     }
2867 
2868   /* Perform a stoopid fallback just incase */
2869   if (adaptor->priv->generic_name == NULL)
2870     adaptor->priv->generic_name = g_strdup ("widget");
2871 
2872   adaptor->priv->catalog = g_strdup (glade_catalog_get_name (catalog));
2873 
2874   if (glade_catalog_get_book (catalog))
2875     adaptor->priv->book = g_strdup (glade_catalog_get_book (catalog));
2876 
2877   gwa_extend_with_node (adaptor, class_node, module,
2878                         glade_catalog_get_domain (catalog));
2879 
2880   /* Finalize the icon and overlay it if it's deprecated */
2881   if (GWA_DEPRECATED (adaptor))
2882     {
2883       gchar *deprecated_icon = generate_deprecated_icon (adaptor->priv->icon_name);
2884 
2885       g_free (adaptor->priv->icon_name);
2886       adaptor->priv->icon_name = deprecated_icon;
2887     }
2888 
2889   /* Postpone creating the cursor until we have the right graphic for it */
2890   gwa_create_cursor (adaptor);
2891 
2892   /* Set default weight on properties */
2893   for (parent_type = adaptor->priv->type;
2894        parent_type != 0; parent_type = g_type_parent (parent_type))
2895     {
2896       glade_property_class_set_weights (&adaptor->priv->properties, parent_type);
2897       glade_property_class_set_weights (&adaptor->priv->packing_props, parent_type);
2898     }
2899 
2900   gwa_displayable_values_check (adaptor, FALSE);
2901   gwa_displayable_values_check (adaptor, TRUE);
2902 
2903   glade_widget_adaptor_register (adaptor);
2904 
2905   g_free (name);
2906 
2907   return adaptor;
2908 }
2909 
2910 /**
2911  * glade_widget_adaptor_create_internal:
2912  * @parent:            The parent #GladeWidget, or %NULL for children
2913  *                     outside of the hierarchy.
2914  * @internal_object:   the #GObject
2915  * @internal_name:     a string identifier for this internal widget.
2916  * @parent_name:       the generic name of the parent used for fancy child names.
2917  * @anarchist:         Whether or not this widget is a widget outside
2918  *                     of the parent's hierarchy (like a popup window)
2919  * @reason:            The #GladeCreateReason for which this internal widget
2920  *                     was created (usually just pass the reason from the post_create
2921  *                     function; note also this is used only by the plugin code so
2922  *                     pass something usefull here).
2923  *
2924  * A convenienve function to create a #GladeWidget of the prescribed type
2925  * for internal widgets.
2926  *
2927  * Returns: a freshly created #GladeWidget wrapper object for the
2928  *          @internal_object of name @internal_name
2929  */
2930 GladeWidget *
glade_widget_adaptor_create_internal(GladeWidget * parent,GObject * internal_object,const gchar * internal_name,const gchar * parent_name,gboolean anarchist,GladeCreateReason reason)2931 glade_widget_adaptor_create_internal (GladeWidget      *parent,
2932                                       GObject          *internal_object,
2933                                       const gchar      *internal_name,
2934                                       const gchar      *parent_name,
2935                                       gboolean          anarchist,
2936                                       GladeCreateReason reason)
2937 {
2938   GladeWidgetAdaptor *adaptor;
2939   GladeProject *project;
2940 
2941   g_return_val_if_fail (GLADE_IS_WIDGET (parent), NULL);
2942   project = glade_widget_get_project (parent);
2943 
2944   if ((adaptor = glade_widget_adaptor_get_by_name
2945        (G_OBJECT_TYPE_NAME (internal_object))) == NULL)
2946     {
2947       g_critical ("Unable to find widget class for type %s",
2948                   G_OBJECT_TYPE_NAME (internal_object));
2949       return NULL;
2950     }
2951 
2952   return glade_widget_adaptor_create_widget (adaptor, FALSE,
2953                                              "anarchist", anarchist,
2954                                              "parent", parent,
2955                                              "project", project,
2956                                              "internal", internal_name,
2957                                              "internal-name", parent_name,
2958                                              "reason", reason,
2959                                              "object", internal_object, NULL);
2960 }
2961 
2962 /**
2963  * glade_widget_adaptor_create_widget:
2964  * @adaptor: a #GladeWidgetAdaptor
2965  * @query:   whether to display query dialogs if
2966  *           applicable to the class
2967  * @...:     a %NULL terminated list of string/value pairs of #GladeWidget
2968  *           properties
2969  *
2970  *
2971  * This factory function returns a new #GladeWidget of the correct type/class
2972  * with the properties defined in @... and queries the user if nescisary.
2973  *
2974  * The resulting object will have all default properties applied to it
2975  * including the overrides specified in the catalog, unless the catalog
2976  * has specified 'ignore' for that property.
2977  *
2978  * Note that the widget class must be fed twice; once as the
2979  * leading arg... and also as the property for the #GladeWidget
2980  *
2981  * this macro returns the newly created #GladeWidget
2982  */
2983 GladeWidget *
glade_widget_adaptor_create_widget_real(gboolean query,const gchar * first_property,...)2984 glade_widget_adaptor_create_widget_real (gboolean     query,
2985                                          const gchar *first_property,
2986                                          ...)
2987 {
2988   GladeWidgetAdaptor *adaptor;
2989   GladeWidget *gwidget;
2990   va_list vl, vl_copy;
2991 
2992   g_return_val_if_fail (strcmp (first_property, "adaptor") == 0, NULL);
2993 
2994   va_start (vl, first_property);
2995   va_copy (vl_copy, vl);
2996 
2997   adaptor = va_arg (vl, GladeWidgetAdaptor *);
2998 
2999   va_end (vl);
3000 
3001   if (GLADE_IS_WIDGET_ADAPTOR (adaptor) == FALSE)
3002     {
3003       g_critical
3004           ("No adaptor found in glade_widget_adaptor_create_widget_real args");
3005       va_end (vl_copy);
3006       return NULL;
3007     }
3008 
3009   gwidget =
3010       GLADE_WIDGET_ADAPTOR_GET_CLASS (adaptor)->create_widget (adaptor,
3011                                                                first_property,
3012                                                                vl_copy);
3013 
3014   va_end (vl_copy);
3015 
3016   if (query && glade_widget_adaptor_query (adaptor))
3017     {
3018       /* If user pressed cancel on query popup. */
3019       if (!glade_editor_query_dialog (gwidget))
3020         {
3021           g_object_unref (G_OBJECT (gwidget));
3022           return NULL;
3023         }
3024     }
3025 
3026   return gwidget;
3027 }
3028 
3029 /**
3030  * glade_widget_adaptor_get_by_name:
3031  * @name: name of the widget class (for instance: GtkButton)
3032  *
3033  * Returns: an existing #GladeWidgetAdaptor with the name equaling @name,
3034  *          or %NULL if such a class doesn't exist
3035  **/
3036 GladeWidgetAdaptor *
glade_widget_adaptor_get_by_name(const gchar * name)3037 glade_widget_adaptor_get_by_name (const gchar *name)
3038 {
3039   GType type = g_type_from_name (name);
3040 
3041   if (adaptor_hash && type)
3042     return g_hash_table_lookup (adaptor_hash, GSIZE_TO_POINTER (type));
3043 
3044   return NULL;
3045 }
3046 
3047 
3048 /**
3049  * glade_widget_adaptor_get_by_type:
3050  * @type: the #GType of an object class
3051  *
3052  * Returns: an existing #GladeWidgetAdaptor with the type equaling @type,
3053  *          or %NULL if such a class doesn't exist
3054  **/
3055 GladeWidgetAdaptor *
glade_widget_adaptor_get_by_type(GType type)3056 glade_widget_adaptor_get_by_type (GType type)
3057 {
3058   if (adaptor_hash != NULL)
3059     return g_hash_table_lookup (adaptor_hash, GSIZE_TO_POINTER (type));
3060   else
3061     return NULL;
3062 }
3063 
3064 /**
3065  * glade_widget_adaptor_from_pspec:
3066  * @adaptor: a #GladeWidgetAdaptor
3067  * @pspec: a #GParamSpec
3068  *
3069  * Assumes @pspec is a property in an object class wrapped by @adaptor,
3070  * this function will search for the specific parent adaptor class which
3071  * originally introduced @pspec.
3072  *
3073  * Returns: the closest #GladeWidgetAdaptor in the ancestry to @adaptor
3074  *          which is responsable for introducing @pspec.
3075  **/
3076 GladeWidgetAdaptor *
glade_widget_adaptor_from_pspec(GladeWidgetAdaptor * adaptor,GParamSpec * spec)3077 glade_widget_adaptor_from_pspec (GladeWidgetAdaptor *adaptor,
3078                                  GParamSpec         *spec)
3079 {
3080   GladeWidgetAdaptor *spec_adaptor;
3081   GType spec_type = spec->owner_type;
3082 
3083   if (!spec_type)
3084     return adaptor;
3085 
3086   spec_adaptor = glade_widget_adaptor_get_by_type (spec->owner_type);
3087 
3088   g_return_val_if_fail (g_type_is_a (adaptor->priv->type, spec->owner_type), NULL);
3089 
3090   while (spec_type && !spec_adaptor && spec_type != adaptor->priv->type)
3091     {
3092       spec_type = g_type_parent (spec_type);
3093       spec_adaptor = glade_widget_adaptor_get_by_type (spec_type);
3094     }
3095 
3096   if (spec_adaptor)
3097     return spec_adaptor;
3098 
3099   return adaptor;
3100 }
3101 
3102 /**
3103  * glade_widget_adaptor_get_property_class:
3104  * @adaptor: a #GladeWidgetAdaptor
3105  * @name: a string
3106  *
3107  * Retrieves the #GladePropertyClass for @name in @adaptor
3108  *
3109  * Returns: A #GladePropertyClass object
3110  */
3111 GladePropertyClass *
glade_widget_adaptor_get_property_class(GladeWidgetAdaptor * adaptor,const gchar * name)3112 glade_widget_adaptor_get_property_class (GladeWidgetAdaptor *adaptor,
3113                                          const gchar        *name)
3114 {
3115   GList *list;
3116   GladePropertyClass *pclass;
3117 
3118   for (list = adaptor->priv->properties; list && list->data; list = list->next)
3119     {
3120       pclass = list->data;
3121       if (strcmp (glade_property_class_id (pclass), name) == 0)
3122         return pclass;
3123     }
3124   return NULL;
3125 }
3126 
3127 /**
3128  * glade_widget_adaptor_get_pack_property_class:
3129  * @adaptor: a #GladeWidgetAdaptor
3130  * @name: a string
3131  *
3132  * Retrieves the #GladePropertyClass for @name in
3133  * @adaptor's child properties
3134  *
3135  * Returns: A #GladePropertyClass object
3136  */
3137 GladePropertyClass *
glade_widget_adaptor_get_pack_property_class(GladeWidgetAdaptor * adaptor,const gchar * name)3138 glade_widget_adaptor_get_pack_property_class (GladeWidgetAdaptor *adaptor,
3139                                               const gchar        *name)
3140 {
3141   GList *list;
3142   GladePropertyClass *pclass;
3143 
3144   for (list = adaptor->priv->packing_props; list && list->data; list = list->next)
3145     {
3146       pclass = list->data;
3147       if (strcmp (glade_property_class_id (pclass), name) == 0)
3148         return pclass;
3149     }
3150   return NULL;
3151 }
3152 
3153 /**
3154  * glade_widget_class_default_params:
3155  * @adaptor: a #GladeWidgetAdaptor
3156  * @construct: whether to return construct params or not construct params
3157  * @n_params: return location if any defaults are specified for this class.
3158  *
3159  * Returns: A list of params for use in g_object_newv ()
3160  */
3161 GParameter *
glade_widget_adaptor_default_params(GladeWidgetAdaptor * adaptor,gboolean construct,guint * n_params)3162 glade_widget_adaptor_default_params (GladeWidgetAdaptor *adaptor,
3163                                      gboolean            construct,
3164                                      guint              *n_params)
3165 {
3166   GArray *params;
3167   GObjectClass *oclass;
3168   GParamSpec **pspec;
3169   GladePropertyClass *pclass;
3170   guint n_props, i;
3171 
3172   g_return_val_if_fail (GLADE_IS_WIDGET_ADAPTOR (adaptor), NULL);
3173   g_return_val_if_fail (n_params != NULL, NULL);
3174 
3175   /* As a slight optimization, we never unref the class
3176    */
3177   oclass = g_type_class_ref (adaptor->priv->type);
3178   pspec = g_object_class_list_properties (oclass, &n_props);
3179   params = g_array_new (FALSE, FALSE, sizeof (GParameter));
3180 
3181   for (i = 0; i < n_props; i++)
3182     {
3183       GParameter parameter = { 0, };
3184 
3185       pclass = glade_widget_adaptor_get_property_class
3186           (adaptor, pspec[i]->name);
3187 
3188       /* Ignore properties based on some criteria
3189        */
3190       if (pclass == NULL ||     /* Unaccounted for in the builder */
3191           glade_property_class_get_virtual (pclass) || /* should not be set before
3192 							  GladeWidget wrapper exists */
3193           glade_property_class_get_ignore (pclass))    /* Catalog explicitly ignores the object */
3194         continue;
3195 
3196       if (construct &&
3197           (pspec[i]->flags & (G_PARAM_CONSTRUCT | G_PARAM_CONSTRUCT_ONLY)) == 0)
3198         continue;
3199       else if (!construct &&
3200                (pspec[i]->flags &
3201                 (G_PARAM_CONSTRUCT | G_PARAM_CONSTRUCT_ONLY)) != 0)
3202         continue;
3203 
3204 
3205       if (g_value_type_compatible (G_VALUE_TYPE (glade_property_class_get_default (pclass)),
3206                                    pspec[i]->value_type) == FALSE)
3207         {
3208           g_critical ("Type mismatch on %s property of %s",
3209                       parameter.name, adaptor->priv->name);
3210           continue;
3211         }
3212 
3213       if (g_param_values_cmp (pspec[i],
3214 			      glade_property_class_get_default (pclass),
3215 			      glade_property_class_get_original_default (pclass)) == 0)
3216         continue;
3217 
3218       parameter.name = pspec[i]->name;  /* These are not copied/freed */
3219       g_value_init (&parameter.value, pspec[i]->value_type);
3220       g_value_copy (glade_property_class_get_default (pclass), &parameter.value);
3221 
3222       g_array_append_val (params, parameter);
3223     }
3224   g_free (pspec);
3225 
3226   *n_params = params->len;
3227   return (GParameter *) g_array_free (params, FALSE);
3228 }
3229 
3230 /**
3231  * glade_widget_adaptor_construct_object:
3232  * @adaptor: A #GladeWidgetAdaptor
3233  * @n_parameters: amount of construct parameters
3234  * @parameters: array of construct #GParameter args to create
3235  *              the new object with.
3236  *
3237  * This function is called to construct a GObject instance for
3238  * a #GladeWidget of the said @adaptor. (provided for language
3239  * bindings that may need to construct a wrapper object).
3240  *
3241  * Returns: A newly created #GObject
3242  */
3243 GObject *
glade_widget_adaptor_construct_object(GladeWidgetAdaptor * adaptor,guint n_parameters,GParameter * parameters)3244 glade_widget_adaptor_construct_object (GladeWidgetAdaptor *adaptor,
3245                                        guint               n_parameters,
3246                                        GParameter         *parameters)
3247 {
3248   g_return_val_if_fail (GLADE_IS_WIDGET_ADAPTOR (adaptor), NULL);
3249 
3250   return GLADE_WIDGET_ADAPTOR_GET_CLASS (adaptor)->construct_object (adaptor,
3251                                                                      n_parameters,
3252                                                                      parameters);
3253 }
3254 
3255 /**
3256  * glade_widget_adaptor_destroy_object:
3257  * @adaptor: A #GladeWidgetAdaptor
3258  * @object: The object to destroy
3259  *
3260  * This function is called to destroy a GObject instance.
3261  */
3262 void
glade_widget_adaptor_destroy_object(GladeWidgetAdaptor * adaptor,GObject * object)3263 glade_widget_adaptor_destroy_object (GladeWidgetAdaptor *adaptor,
3264 				     GObject *object)
3265 {
3266   g_return_if_fail (GLADE_IS_WIDGET_ADAPTOR (adaptor));
3267 
3268   GLADE_WIDGET_ADAPTOR_GET_CLASS (adaptor)->destroy_object (adaptor, object);
3269 }
3270 
3271 static void
gwa_internal_children_create(GladeWidgetAdaptor * adaptor,GObject * parent_object,GObject * object,GList * children,GladeCreateReason reason)3272 gwa_internal_children_create (GladeWidgetAdaptor *adaptor,
3273                               GObject            *parent_object,
3274                               GObject            *object,
3275                               GList              *children,
3276                               GladeCreateReason  reason)
3277 {
3278   gchar *parent_name = adaptor->priv->generic_name;
3279   GladeWidget *gobject = glade_widget_get_from_gobject (object);
3280   GList *l;
3281 
3282   for (l = children; l; l = g_list_next (l))
3283     {
3284       GladeInternalChild *internal = l->data;
3285       GObject *child;
3286 
3287       child = glade_widget_adaptor_get_internal_child (adaptor,
3288                                                        parent_object,
3289                                                        internal->name);
3290 
3291       if (child)
3292         {
3293           glade_widget_adaptor_create_internal (gobject,
3294                                                 child,
3295                                                 internal->name,
3296                                                 parent_name,
3297                                                 internal->anarchist,
3298                                                 reason);
3299 
3300           if (internal->children)
3301             gwa_internal_children_create (adaptor, parent_object, child, internal->children, reason);
3302         }
3303     }
3304 }
3305 
3306 /**
3307  * glade_widget_adaptor_post_create:
3308  * @adaptor:   A #GladeWidgetAdaptor
3309  * @object:    The #GObject
3310  * @reason:    The #GladeCreateReason that @object was created for
3311  *
3312  * An adaptor function to be called after the object is created
3313  */
3314 void
glade_widget_adaptor_post_create(GladeWidgetAdaptor * adaptor,GObject * object,GladeCreateReason reason)3315 glade_widget_adaptor_post_create (GladeWidgetAdaptor *adaptor,
3316                                   GObject            *object,
3317                                   GladeCreateReason   reason)
3318 {
3319   g_return_if_fail (GLADE_IS_WIDGET_ADAPTOR (adaptor));
3320   g_return_if_fail (G_IS_OBJECT (object));
3321   g_return_if_fail (g_type_is_a (G_OBJECT_TYPE (object), adaptor->priv->type));
3322 
3323   /* Create internal widgets */
3324   if (adaptor->priv->internal_children)
3325       gwa_internal_children_create (adaptor, object, object, adaptor->priv->internal_children, reason);
3326 
3327   /* Run post_create in 2 stages, one that chains up and all class adaptors
3328    * in the hierarchy get a peek, another that is used to setup placeholders
3329    * and things that differ from the child/parent implementations
3330    */
3331   if (GLADE_WIDGET_ADAPTOR_GET_CLASS (adaptor)->deep_post_create)
3332     GLADE_WIDGET_ADAPTOR_GET_CLASS (adaptor)->deep_post_create (adaptor, object,
3333                                                                 reason);
3334 
3335   if (GLADE_WIDGET_ADAPTOR_GET_CLASS (adaptor)->post_create)
3336     GLADE_WIDGET_ADAPTOR_GET_CLASS (adaptor)->post_create (adaptor, object,
3337                                                            reason);
3338   /* XXX Dont complain here if no implementation is found */
3339 }
3340 
3341 /**
3342  * glade_widget_adaptor_get_internal_child:
3343  * @adaptor:       A #GladeWidgetAdaptor
3344  * @object:        The #GObject
3345  * @internal_name: The string identifier of the internal object
3346  *
3347  * Retrieves the internal object @internal_name from @object
3348  *
3349  * Returns: The internal #GObject
3350  */
3351 GObject *
glade_widget_adaptor_get_internal_child(GladeWidgetAdaptor * adaptor,GObject * object,const gchar * internal_name)3352 glade_widget_adaptor_get_internal_child (GladeWidgetAdaptor *adaptor,
3353                                          GObject            *object,
3354                                          const gchar        *internal_name)
3355 {
3356   g_return_val_if_fail (GLADE_IS_WIDGET_ADAPTOR (adaptor), NULL);
3357   g_return_val_if_fail (G_IS_OBJECT (object), NULL);
3358   g_return_val_if_fail (internal_name != NULL, NULL);
3359   g_return_val_if_fail (g_type_is_a (G_OBJECT_TYPE (object), adaptor->priv->type),
3360                         NULL);
3361 
3362   if (GLADE_WIDGET_ADAPTOR_GET_CLASS (adaptor)->get_internal_child)
3363     return GLADE_WIDGET_ADAPTOR_GET_CLASS
3364         (adaptor)->get_internal_child (adaptor, object, internal_name);
3365   else
3366     g_critical ("No get_internal_child() support in adaptor %s", adaptor->priv->name);
3367 
3368   return NULL;
3369 }
3370 
3371 /**
3372  * glade_widget_adaptor_set_property:
3373  * @adaptor:       A #GladeWidgetAdaptor
3374  * @object:        The #GObject
3375  * @property_name: The property identifier
3376  * @value:         The #GValue
3377  *
3378  * This delagate function is used to apply the property value on
3379  * the runtime object.
3380  *
3381  */
3382 void
glade_widget_adaptor_set_property(GladeWidgetAdaptor * adaptor,GObject * object,const gchar * property_name,const GValue * value)3383 glade_widget_adaptor_set_property (GladeWidgetAdaptor *adaptor,
3384                                    GObject            *object,
3385                                    const gchar        *property_name,
3386                                    const GValue       *value)
3387 {
3388   g_return_if_fail (GLADE_IS_WIDGET_ADAPTOR (adaptor));
3389   g_return_if_fail (G_IS_OBJECT (object));
3390   g_return_if_fail (property_name != NULL && value != NULL);
3391   g_return_if_fail (g_type_is_a (G_OBJECT_TYPE (object), adaptor->priv->type));
3392 
3393   /* The base class provides an implementation */
3394   GLADE_WIDGET_ADAPTOR_GET_CLASS
3395       (adaptor)->set_property (adaptor, object, property_name, value);
3396 }
3397 
3398 
3399 /**
3400  * glade_widget_adaptor_get_property:
3401  * @adaptor:       A #GladeWidgetAdaptor
3402  * @object:        The #GObject
3403  * @property_name: The property identifier
3404  * @value:         The #GValue
3405  *
3406  * Gets @value of @property_name on @object.
3407  *
3408  */
3409 void
glade_widget_adaptor_get_property(GladeWidgetAdaptor * adaptor,GObject * object,const gchar * property_name,GValue * value)3410 glade_widget_adaptor_get_property (GladeWidgetAdaptor *adaptor,
3411                                    GObject            *object,
3412                                    const gchar        *property_name,
3413                                    GValue             *value)
3414 {
3415   g_return_if_fail (GLADE_IS_WIDGET_ADAPTOR (adaptor));
3416   g_return_if_fail (G_IS_OBJECT (object));
3417   g_return_if_fail (property_name != NULL && value != NULL);
3418   g_return_if_fail (g_type_is_a (G_OBJECT_TYPE (object), adaptor->priv->type));
3419 
3420   /* The base class provides an implementation */
3421   GLADE_WIDGET_ADAPTOR_GET_CLASS
3422       (adaptor)->get_property (adaptor, object, property_name, value);
3423 }
3424 
3425 
3426 /**
3427  * glade_widget_adaptor_verify_property:
3428  * @adaptor:       A #GladeWidgetAdaptor
3429  * @object:        The #GObject
3430  * @property_name: The property identifier
3431  * @value:         The #GValue
3432  *
3433  * This delagate function is always called whenever setting any
3434  * properties with the exception of load time, and copy/paste time
3435  * (basicly the two places where we recreate a hierarchy that we
3436  * already know "works") its basicly an optional backend provided
3437  * boundry checker for properties.
3438  *
3439  * Returns: whether or not its OK to set @value on @object, this function
3440  * will silently return TRUE if the class did not provide a verify function.
3441  */
3442 gboolean
glade_widget_adaptor_verify_property(GladeWidgetAdaptor * adaptor,GObject * object,const gchar * property_name,const GValue * value)3443 glade_widget_adaptor_verify_property (GladeWidgetAdaptor *adaptor,
3444                                       GObject            *object,
3445                                       const gchar        *property_name,
3446                                       const GValue       *value)
3447 {
3448   g_return_val_if_fail (GLADE_IS_WIDGET_ADAPTOR (adaptor), FALSE);
3449   g_return_val_if_fail (G_IS_OBJECT (object), FALSE);
3450   g_return_val_if_fail (property_name != NULL && value != NULL, FALSE);
3451   g_return_val_if_fail (g_type_is_a (G_OBJECT_TYPE (object), adaptor->priv->type),
3452                         FALSE);
3453 
3454   if (GLADE_WIDGET_ADAPTOR_GET_CLASS (adaptor)->verify_property)
3455     return GLADE_WIDGET_ADAPTOR_GET_CLASS
3456         (adaptor)->verify_property (adaptor, object, property_name, value);
3457 
3458   return TRUE;
3459 }
3460 
3461 /**
3462  * glade_widget_adaptor_add_verify:
3463  * @adaptor:   A #GladeWidgetAdaptor
3464  * @parent: A #GObject container
3465  * @child: A #GObject child
3466  * @user_feedback: whether a notification dialog should be
3467  * presented in the case that the child cannot not be added.
3468  *
3469  * Checks whether @child can be added to @parent.
3470  *
3471  * If @user_feedback is %TRUE and @child cannot be
3472  * added then this shows a notification dialog to the user
3473  * explaining why.
3474  *
3475  * Returns: whether @child can be added to @parent.
3476  */
3477 gboolean
glade_widget_adaptor_add_verify(GladeWidgetAdaptor * adaptor,GObject * container,GObject * child,gboolean user_feedback)3478 glade_widget_adaptor_add_verify (GladeWidgetAdaptor *adaptor,
3479 				 GObject            *container,
3480 				 GObject            *child,
3481 				 gboolean            user_feedback)
3482 {
3483   g_return_val_if_fail (GLADE_IS_WIDGET_ADAPTOR (adaptor), FALSE);
3484   g_return_val_if_fail (G_IS_OBJECT (container), FALSE);
3485   g_return_val_if_fail (G_IS_OBJECT (child), FALSE);
3486   g_return_val_if_fail (g_type_is_a (G_OBJECT_TYPE (container), adaptor->priv->type), FALSE);
3487 
3488   return GLADE_WIDGET_ADAPTOR_GET_CLASS (adaptor)->add_verify (adaptor, container, child, user_feedback);
3489 }
3490 
3491 /**
3492  * glade_widget_adaptor_add:
3493  * @adaptor:   A #GladeWidgetAdaptor
3494  * @container: The #GObject container
3495  * @child:     The #GObject child
3496  *
3497  * Adds @child to @container.
3498  */
3499 void
glade_widget_adaptor_add(GladeWidgetAdaptor * adaptor,GObject * container,GObject * child)3500 glade_widget_adaptor_add (GladeWidgetAdaptor *adaptor,
3501                           GObject            *container,
3502                           GObject            *child)
3503 {
3504   g_return_if_fail (GLADE_IS_WIDGET_ADAPTOR (adaptor));
3505   g_return_if_fail (G_IS_OBJECT (container));
3506   g_return_if_fail (G_IS_OBJECT (child));
3507   g_return_if_fail (g_type_is_a (G_OBJECT_TYPE (container), adaptor->priv->type));
3508 
3509   if (GLADE_WIDGET_ADAPTOR_GET_CLASS (adaptor)->add)
3510     GLADE_WIDGET_ADAPTOR_GET_CLASS (adaptor)->add (adaptor, container, child);
3511   else
3512     g_critical ("No add() support in adaptor %s", adaptor->priv->name);
3513 }
3514 
3515 
3516 /**
3517  * glade_widget_adaptor_remove:
3518  * @adaptor:   A #GladeWidgetAdaptor
3519  * @container: The #GObject container
3520  * @child:     The #GObject child
3521  *
3522  * Removes @child from @container.
3523  */
3524 void
glade_widget_adaptor_remove(GladeWidgetAdaptor * adaptor,GObject * container,GObject * child)3525 glade_widget_adaptor_remove (GladeWidgetAdaptor *adaptor,
3526                              GObject            *container,
3527                              GObject            *child)
3528 {
3529   g_return_if_fail (GLADE_IS_WIDGET_ADAPTOR (adaptor));
3530   g_return_if_fail (G_IS_OBJECT (container));
3531   g_return_if_fail (G_IS_OBJECT (child));
3532   g_return_if_fail (g_type_is_a (G_OBJECT_TYPE (container), adaptor->priv->type));
3533 
3534   if (GLADE_WIDGET_ADAPTOR_GET_CLASS (adaptor)->remove)
3535     GLADE_WIDGET_ADAPTOR_GET_CLASS (adaptor)->remove (adaptor, container,
3536                                                       child);
3537   else
3538     g_critical ("No remove() support in adaptor %s", adaptor->priv->name);
3539 }
3540 
3541 /**
3542  * glade_widget_adaptor_get_children:
3543  * @adaptor:   A #GladeWidgetAdaptor
3544  * @container: The #GObject container
3545  *
3546  * Lists the children of @container.
3547  *
3548  * Returns: A #GList of children
3549  */
3550 GList *
glade_widget_adaptor_get_children(GladeWidgetAdaptor * adaptor,GObject * container)3551 glade_widget_adaptor_get_children (GladeWidgetAdaptor *adaptor,
3552                                    GObject            *container)
3553 {
3554   g_return_val_if_fail (GLADE_IS_WIDGET_ADAPTOR (adaptor), NULL);
3555   g_return_val_if_fail (G_IS_OBJECT (container), NULL);
3556   g_return_val_if_fail (g_type_is_a (G_OBJECT_TYPE (container), adaptor->priv->type),
3557                         NULL);
3558 
3559   return GLADE_WIDGET_ADAPTOR_GET_CLASS (adaptor)->get_children (adaptor, container);
3560 }
3561 
3562 /**
3563  * glade_widget_adaptor_has_child:
3564  * @adaptor:   A #GladeWidgetAdaptor
3565  * @container: The #GObject container
3566  * @child:     The #GObject child
3567  *
3568  * Returns: whether @child is infact inside @container.
3569  */
3570 gboolean
glade_widget_adaptor_has_child(GladeWidgetAdaptor * adaptor,GObject * container,GObject * child)3571 glade_widget_adaptor_has_child (GladeWidgetAdaptor *adaptor,
3572                                 GObject            *container,
3573                                 GObject            *child)
3574 {
3575   GList *list, *children = NULL;
3576   gboolean found = FALSE;
3577 
3578   children = glade_widget_adaptor_get_children (adaptor, container);
3579 
3580   for (list = children; list && list->data; list = list->next)
3581     {
3582       if (list->data == child)
3583         {
3584           found = TRUE;
3585           break;
3586         }
3587     }
3588 
3589   g_list_free (children);
3590   return found;
3591 }
3592 
3593 /**
3594  * glade_widget_adaptor_child_set_property:
3595  * @adaptor:       A #GladeWidgetAdaptor
3596  * @container:     The #GObject container
3597  * @child:         The #GObject child
3598  * @property_name: The id of the property
3599  * @value:         The @GValue
3600  *
3601  * Sets @child's packing property identified by @property_name to @value.
3602  */
3603 void
glade_widget_adaptor_child_set_property(GladeWidgetAdaptor * adaptor,GObject * container,GObject * child,const gchar * property_name,const GValue * value)3604 glade_widget_adaptor_child_set_property (GladeWidgetAdaptor *adaptor,
3605                                          GObject            *container,
3606                                          GObject            *child,
3607                                          const gchar        *property_name,
3608                                          const GValue       *value)
3609 {
3610   g_return_if_fail (GLADE_IS_WIDGET_ADAPTOR (adaptor));
3611   g_return_if_fail (G_IS_OBJECT (container));
3612   g_return_if_fail (G_IS_OBJECT (child));
3613   g_return_if_fail (property_name != NULL && value != NULL);
3614   g_return_if_fail (g_type_is_a (G_OBJECT_TYPE (container), adaptor->priv->type));
3615 
3616   /* XXX Valgrind says that the above 'g_type_is_a' line allocates uninitialized stack memory
3617    * that is later used in glade_gtk_box_child_set_property, why ? */
3618 
3619   if (GLADE_WIDGET_ADAPTOR_GET_CLASS (adaptor)->child_set_property)
3620     GLADE_WIDGET_ADAPTOR_GET_CLASS
3621         (adaptor)->child_set_property (adaptor, container, child,
3622                                        property_name, value);
3623   else
3624     g_critical ("No child_set_property() support in adaptor %s", adaptor->priv->name);
3625 
3626 }
3627 
3628 /**
3629  * glade_widget_adaptor_child_get_property:
3630  * @adaptor:       A #GladeWidgetAdaptor
3631  * @container:     The #GObject container
3632  * @child:         The #GObject child
3633  * @property_name: The id of the property
3634  * @value:         The @GValue
3635  *
3636  * Gets @child's packing property identified by @property_name.
3637  */
3638 void
glade_widget_adaptor_child_get_property(GladeWidgetAdaptor * adaptor,GObject * container,GObject * child,const gchar * property_name,GValue * value)3639 glade_widget_adaptor_child_get_property (GladeWidgetAdaptor *adaptor,
3640                                          GObject            *container,
3641                                          GObject            *child,
3642                                          const gchar        *property_name,
3643                                          GValue             *value)
3644 {
3645   g_return_if_fail (GLADE_IS_WIDGET_ADAPTOR (adaptor));
3646   g_return_if_fail (G_IS_OBJECT (container));
3647   g_return_if_fail (G_IS_OBJECT (child));
3648   g_return_if_fail (property_name != NULL && value != NULL);
3649   g_return_if_fail (g_type_is_a (G_OBJECT_TYPE (container), adaptor->priv->type));
3650 
3651   if (GLADE_WIDGET_ADAPTOR_GET_CLASS (adaptor)->child_get_property)
3652     GLADE_WIDGET_ADAPTOR_GET_CLASS
3653         (adaptor)->child_get_property (adaptor, container, child,
3654                                        property_name, value);
3655   else
3656     g_critical ("No child_set_property() support in adaptor %s", adaptor->priv->name);
3657 }
3658 
3659 /**
3660  * glade_widget_adaptor_child_verify_property:
3661  * @adaptor:       A #GladeWidgetAdaptor
3662  * @container:     The #GObject container
3663  * @child:         The #GObject child
3664  * @property_name: The id of the property
3665  * @value:         The @GValue
3666  *
3667  * This delagate function is always called whenever setting any
3668  * properties with the exception of load time, and copy/paste time
3669  * (basicly the two places where we recreate a hierarchy that we
3670  * already know "works") its basicly an optional backend provided
3671  * boundry checker for properties.
3672  *
3673  * Returns: whether or not its OK to set @value on @object, this function
3674  * will silently return TRUE if the class did not provide a verify function.
3675  */
3676 gboolean
glade_widget_adaptor_child_verify_property(GladeWidgetAdaptor * adaptor,GObject * container,GObject * child,const gchar * property_name,const GValue * value)3677 glade_widget_adaptor_child_verify_property (GladeWidgetAdaptor *adaptor,
3678                                             GObject            *container,
3679                                             GObject            *child,
3680                                             const gchar        *property_name,
3681                                             const GValue       *value)
3682 {
3683   g_return_val_if_fail (GLADE_IS_WIDGET_ADAPTOR (adaptor), FALSE);
3684   g_return_val_if_fail (G_IS_OBJECT (container), FALSE);
3685   g_return_val_if_fail (G_IS_OBJECT (child), FALSE);
3686   g_return_val_if_fail (property_name != NULL && value != NULL, FALSE);
3687   g_return_val_if_fail (g_type_is_a (G_OBJECT_TYPE (container), adaptor->priv->type),
3688                         FALSE);
3689 
3690   if (GLADE_WIDGET_ADAPTOR_GET_CLASS (adaptor)->child_verify_property)
3691     return GLADE_WIDGET_ADAPTOR_GET_CLASS
3692         (adaptor)->child_verify_property (adaptor,
3693                                           container, child,
3694                                           property_name, value);
3695 
3696   return TRUE;
3697 }
3698 
3699 
3700 /**
3701  * glade_widget_adaptor_replace_child:
3702  * @adaptor: A #GladeWidgetAdaptor
3703  * @container: The #GObject container
3704  * @old_obj: The old #GObject child
3705  * @new_obj: The new #GObject child
3706  *
3707  * Replaces @old_obj with @new_obj in @container while positioning
3708  * @new_obj where @old_obj was and assigning it appropriate packing
3709  * property values.
3710  */
3711 void
glade_widget_adaptor_replace_child(GladeWidgetAdaptor * adaptor,GObject * container,GObject * old_obj,GObject * new_obj)3712 glade_widget_adaptor_replace_child (GladeWidgetAdaptor *adaptor,
3713                                     GObject            *container,
3714                                     GObject            *old_obj,
3715                                     GObject            *new_obj)
3716 {
3717   g_return_if_fail (GLADE_IS_WIDGET_ADAPTOR (adaptor));
3718   g_return_if_fail (G_IS_OBJECT (container));
3719   g_return_if_fail (G_IS_OBJECT (old_obj));
3720   g_return_if_fail (G_IS_OBJECT (new_obj));
3721   g_return_if_fail (g_type_is_a (G_OBJECT_TYPE (container), adaptor->priv->type));
3722 
3723   if (GLADE_WIDGET_ADAPTOR_GET_CLASS (adaptor)->replace_child)
3724     GLADE_WIDGET_ADAPTOR_GET_CLASS
3725         (adaptor)->replace_child (adaptor, container, old_obj, new_obj);
3726   else
3727     g_critical ("No replace_child() support in adaptor %s", adaptor->priv->name);
3728 }
3729 
3730 /**
3731  * glade_widget_adaptor_query:
3732  * @adaptor: A #GladeWidgetAdaptor
3733  *
3734  * Returns: whether the user needs to be queried for
3735  * certain properties upon creation of this class.
3736  */
3737 gboolean
glade_widget_adaptor_query(GladeWidgetAdaptor * adaptor)3738 glade_widget_adaptor_query (GladeWidgetAdaptor *adaptor)
3739 {
3740   GladePropertyClass *pclass;
3741   GList *l;
3742 
3743   g_return_val_if_fail (GLADE_IS_WIDGET_ADAPTOR (adaptor), FALSE);
3744 
3745   if (!adaptor->priv->query)
3746     return FALSE;
3747 
3748   for (l = adaptor->priv->properties; l; l = l->next)
3749     {
3750       pclass = l->data;
3751 
3752       if (glade_property_class_query (pclass))
3753         return TRUE;
3754     }
3755 
3756   return FALSE;
3757 }
3758 
3759 /**
3760  * glade_widget_adaptor_get_packing_default:
3761  * @child_adaptor:  A #GladeWidgetAdaptor
3762  * @container_adaptor: The #GladeWidgetAdaptor for the parent object
3763  * @id:    The string property identifier
3764  *
3765  * Gets the default value for @property_id on a widget governed by
3766  * @child_adaptor when parented in a widget governed by @parent_adaptor
3767  *
3768  * Returns: a string representing the default value for @property_id
3769  */
3770 G_CONST_RETURN gchar *
glade_widget_adaptor_get_packing_default(GladeWidgetAdaptor * child_adaptor,GladeWidgetAdaptor * container_adaptor,const gchar * id)3771 glade_widget_adaptor_get_packing_default (GladeWidgetAdaptor *child_adaptor,
3772                                           GladeWidgetAdaptor *container_adaptor,
3773                                           const gchar        *id)
3774 {
3775   GladeChildPacking *packing = NULL;
3776   GList *l;
3777 
3778   g_return_val_if_fail (GLADE_IS_WIDGET_ADAPTOR (child_adaptor), NULL);
3779   g_return_val_if_fail (GLADE_IS_WIDGET_ADAPTOR (container_adaptor), NULL);
3780 
3781   if ((packing =
3782        glade_widget_adaptor_get_child_packing (child_adaptor,
3783                                                container_adaptor->priv->name)) !=
3784       NULL)
3785     {
3786       for (l = packing->packing_defaults; l; l = l->next)
3787         {
3788           GladePackingDefault *def = l->data;
3789 
3790           if (strcmp (def->id, id) == 0)
3791             return def->value;
3792         }
3793     }
3794   return NULL;
3795 }
3796 
3797 /**
3798  * glade_widget_adaptor_is_container:
3799  * @adaptor: A #GladeWidgetAdaptor
3800  *
3801  * Checks whether or not this adaptor has support
3802  * to interface with child objects.
3803  *
3804  * Returns: whether or not @adaptor is a container
3805  */
3806 gboolean
glade_widget_adaptor_is_container(GladeWidgetAdaptor * adaptor)3807 glade_widget_adaptor_is_container (GladeWidgetAdaptor *adaptor)
3808 {
3809 
3810   g_return_val_if_fail (GLADE_IS_WIDGET_ADAPTOR (adaptor), FALSE);
3811 
3812   /* A GWA container must at least implement add/remove/get_children
3813    */
3814   return (GLADE_WIDGET_ADAPTOR_GET_CLASS (adaptor)->add &&
3815           GLADE_WIDGET_ADAPTOR_GET_CLASS (adaptor)->remove &&
3816           GLADE_WIDGET_ADAPTOR_GET_CLASS (adaptor)->get_children);
3817 }
3818 
3819 static const gchar *
gwa_action_path_get_id(const gchar * action_path)3820 gwa_action_path_get_id (const gchar *action_path)
3821 {
3822   const gchar *id;
3823 
3824   if ((id = g_strrstr (action_path, "/")) && id[1] != '\0')
3825     return &id[1];
3826   else
3827     return action_path;
3828 }
3829 
3830 static GWActionClass *
gwa_action_lookup(GList * actions,const gchar * action_id)3831 gwa_action_lookup (GList *actions, const gchar *action_id)
3832 {
3833   GList *l;
3834 
3835   for (l = actions; l; l = g_list_next (l))
3836     {
3837       GWActionClass *action = l->data;
3838       if (strcmp (action->id, action_id) == 0)
3839         return action;
3840     }
3841 
3842   return NULL;
3843 }
3844 
3845 static GWActionClass *
gwa_action_get_last_group(GList * actions,const gchar * action_path)3846 gwa_action_get_last_group (GList *actions, const gchar *action_path)
3847 {
3848   gchar **tokens = g_strsplit (action_path, "/", 0);
3849   GWActionClass *group = NULL;
3850   gint i;
3851 
3852   for (i = 0; tokens[i] && tokens[i + 1]; i++)
3853     {
3854       if ((group = gwa_action_lookup (actions, tokens[i])) == NULL)
3855         {
3856           g_strfreev (tokens);
3857           return NULL;
3858         }
3859       actions = group->actions;
3860     }
3861 
3862   g_strfreev (tokens);
3863   return group;
3864 }
3865 
3866 static gboolean
glade_widget_adaptor_action_add_real(GList ** list,const gchar * action_path,const gchar * label,const gchar * stock,gboolean important)3867 glade_widget_adaptor_action_add_real (GList       **list,
3868                                       const gchar  *action_path,
3869                                       const gchar  *label,
3870                                       const gchar  *stock,
3871 				      gboolean      important)
3872 {
3873   GWActionClass *action, *group;
3874   const gchar *id;
3875 
3876   id = gwa_action_path_get_id (action_path);
3877 
3878   if ((group = gwa_action_get_last_group (*list, action_path)))
3879     list = &group->actions;
3880 
3881   if (strcmp (label, "") == 0)
3882     label = NULL;
3883   if (stock && strcmp (stock, "") == 0)
3884     stock = NULL;
3885 
3886   if ((action = gwa_action_lookup (*list, id)) == NULL)
3887     {
3888       /* New Action */
3889       action = glade_widget_action_class_new (action_path);
3890 
3891       *list = g_list_append (*list, action);
3892     }
3893 
3894   glade_widget_action_class_set_label (action, label);
3895   glade_widget_action_class_set_stock (action, stock);
3896   glade_widget_action_class_set_important (action, important);
3897 
3898   return TRUE;
3899 }
3900 
3901 /**
3902  * glade_widget_adaptor_action_add:
3903  * @adaptor: A #GladeWidgetAdaptor
3904  * @action_path: The identifier of this action in the action tree
3905  * @label: A translated label to show in the UI for this action
3906  * @stock: If set, this stock item will be shown in the UI along side the label.
3907  * @important: if this action is important.
3908  *
3909  * Add an action to @adaptor.
3910  * If the action is present then it overrides label and stock
3911  *
3912  * Returns: whether or not the action was added/updated.
3913  */
3914 gboolean
glade_widget_adaptor_action_add(GladeWidgetAdaptor * adaptor,const gchar * action_path,const gchar * label,const gchar * stock,gboolean important)3915 glade_widget_adaptor_action_add (GladeWidgetAdaptor *adaptor,
3916                                  const gchar        *action_path,
3917                                  const gchar        *label,
3918                                  const gchar        *stock,
3919                                  gboolean            important)
3920 {
3921   g_return_val_if_fail (GLADE_IS_WIDGET_ADAPTOR (adaptor), FALSE);
3922   g_return_val_if_fail (action_path != NULL, FALSE);
3923 
3924   return glade_widget_adaptor_action_add_real (&adaptor->priv->actions,
3925                                                action_path,
3926                                                label, stock, important);
3927 }
3928 
3929 /**
3930  * glade_widget_adaptor_pack_action_add:
3931  * @adaptor: A #GladeWidgetAdaptor
3932  * @action_path: The identifier of this action in the action tree
3933  * @label: A translated label to show in the UI for this action
3934  * @stock: If set, this stock item will be shown in the UI along side the label.
3935  * @important: if this action is important.
3936  *
3937  * Add a packing action to @adaptor.
3938  * If the action is present then it overrides label and stock
3939  *
3940  * Returns: whether or not the action was added/updated.
3941  */
3942 gboolean
glade_widget_adaptor_pack_action_add(GladeWidgetAdaptor * adaptor,const gchar * action_path,const gchar * label,const gchar * stock,gboolean important)3943 glade_widget_adaptor_pack_action_add (GladeWidgetAdaptor *adaptor,
3944                                       const gchar        *action_path,
3945                                       const gchar        *label,
3946                                       const gchar        *stock,
3947                                       gboolean            important)
3948 {
3949   g_return_val_if_fail (GLADE_IS_WIDGET_ADAPTOR (adaptor), FALSE);
3950   g_return_val_if_fail (action_path != NULL, FALSE);
3951 
3952   return glade_widget_adaptor_action_add_real (&adaptor->priv->packing_actions,
3953                                                action_path,
3954                                                label, stock, important);
3955 }
3956 
3957 static gboolean
glade_widget_adaptor_action_remove_real(GList ** list,const gchar * action_path)3958 glade_widget_adaptor_action_remove_real (GList **list,
3959                                          const gchar *action_path)
3960 {
3961   GWActionClass *action, *group;
3962   const gchar *id;
3963 
3964   id = gwa_action_path_get_id (action_path);
3965 
3966   if ((group = gwa_action_get_last_group (*list, action_path)))
3967     list = &group->actions;
3968 
3969   if ((action = gwa_action_lookup (*list, id)) == NULL)
3970     return FALSE;
3971 
3972   *list = g_list_remove (*list, action);
3973 
3974   glade_widget_action_class_free (action);
3975 
3976   return TRUE;
3977 }
3978 
3979 /**
3980  * glade_widget_adaptor_action_remove:
3981  * @adaptor: A #GladeWidgetAdaptor
3982  * @action_path: The identifier of this action in the action tree
3983  *
3984  * Remove an @adaptor's action.
3985  *
3986  * Returns: whether or not the action was removed.
3987  */
3988 gboolean
glade_widget_adaptor_action_remove(GladeWidgetAdaptor * adaptor,const gchar * action_path)3989 glade_widget_adaptor_action_remove (GladeWidgetAdaptor *adaptor,
3990                                     const gchar        *action_path)
3991 {
3992   g_return_val_if_fail (GLADE_IS_WIDGET_ADAPTOR (adaptor), FALSE);
3993   g_return_val_if_fail (action_path != NULL, FALSE);
3994 
3995   return glade_widget_adaptor_action_remove_real (&adaptor->priv->actions,
3996                                                   action_path);
3997 }
3998 
3999 /**
4000  * glade_widget_adaptor_pack_action_remove:
4001  * @adaptor: A #GladeWidgetAdaptor
4002  * @action_path: The identifier of this action in the action tree
4003  *
4004  * Remove an @adaptor's packing action.
4005  *
4006  * Returns: whether or not the action was removed.
4007  */
4008 gboolean
glade_widget_adaptor_pack_action_remove(GladeWidgetAdaptor * adaptor,const gchar * action_path)4009 glade_widget_adaptor_pack_action_remove (GladeWidgetAdaptor *adaptor,
4010                                          const gchar        *action_path)
4011 {
4012   g_return_val_if_fail (GLADE_IS_WIDGET_ADAPTOR (adaptor), FALSE);
4013   g_return_val_if_fail (action_path != NULL, FALSE);
4014 
4015   return glade_widget_adaptor_action_remove_real (&adaptor->priv->packing_actions,
4016                                                   action_path);
4017 }
4018 
4019 /**
4020  * glade_widget_adaptor_actions_new:
4021  * @adaptor: A #GladeWidgetAdaptor
4022  *
4023  * Create a list of actions.
4024  *
4025  * Returns: a new list of GladeWidgetAction.
4026  */
4027 GList *
glade_widget_adaptor_actions_new(GladeWidgetAdaptor * adaptor)4028 glade_widget_adaptor_actions_new (GladeWidgetAdaptor *adaptor)
4029 {
4030   GList *l, *list = NULL;
4031 
4032   g_return_val_if_fail (GLADE_IS_WIDGET_ADAPTOR (adaptor), NULL);
4033 
4034   for (l = adaptor->priv->actions; l; l = g_list_next (l))
4035     {
4036       GWActionClass *action = l->data;
4037       GObject       *obj = g_object_new (GLADE_TYPE_WIDGET_ACTION,
4038 					 "class", action, NULL);
4039 
4040       list = g_list_prepend (list, GLADE_WIDGET_ACTION (obj));
4041     }
4042   return g_list_reverse (list);
4043 }
4044 
4045 /**
4046  * glade_widget_adaptor_pack_actions_new:
4047  * @adaptor: A #GladeWidgetAdaptor
4048  *
4049  * Create a list of packing actions.
4050  *
4051  * Returns: a new list of GladeWidgetAction.
4052  */
4053 GList *
glade_widget_adaptor_pack_actions_new(GladeWidgetAdaptor * adaptor)4054 glade_widget_adaptor_pack_actions_new (GladeWidgetAdaptor *adaptor)
4055 {
4056   GList *l, *list = NULL;
4057 
4058   g_return_val_if_fail (GLADE_IS_WIDGET_ADAPTOR (adaptor), NULL);
4059 
4060   for (l = adaptor->priv->packing_actions; l; l = g_list_next (l))
4061     {
4062       GWActionClass *action = l->data;
4063       GObject *obj = g_object_new (GLADE_TYPE_WIDGET_ACTION,
4064                                    "class", action, NULL);
4065 
4066       list = g_list_prepend (list, GLADE_WIDGET_ACTION (obj));
4067     }
4068   return g_list_reverse (list);
4069 }
4070 
4071 /**
4072  * glade_widget_adaptor_action_activate:
4073  * @adaptor:   A #GladeWidgetAdaptor
4074  * @object:    The #GObject
4075  * @action_path: The action identifier in the action tree
4076  *
4077  * An adaptor function to be called on widget actions.
4078  */
4079 void
glade_widget_adaptor_action_activate(GladeWidgetAdaptor * adaptor,GObject * object,const gchar * action_path)4080 glade_widget_adaptor_action_activate (GladeWidgetAdaptor *adaptor,
4081                                       GObject            *object,
4082                                       const gchar        *action_path)
4083 {
4084   g_return_if_fail (GLADE_IS_WIDGET_ADAPTOR (adaptor));
4085   g_return_if_fail (G_IS_OBJECT (object));
4086   g_return_if_fail (g_type_is_a (G_OBJECT_TYPE (object), adaptor->priv->type));
4087 
4088   GLADE_WIDGET_ADAPTOR_GET_CLASS (adaptor)->action_activate (adaptor, object,
4089                                                              action_path);
4090 }
4091 
4092 /**
4093  * glade_widget_adaptor_child_action_activate:
4094  * @adaptor:   A #GladeWidgetAdaptor
4095  * @object:    The #GObject
4096  * @action_path: The action identifier in the action tree
4097  *
4098  * An adaptor function to be called on widget actions.
4099  */
4100 void
glade_widget_adaptor_child_action_activate(GladeWidgetAdaptor * adaptor,GObject * container,GObject * object,const gchar * action_path)4101 glade_widget_adaptor_child_action_activate (GladeWidgetAdaptor *adaptor,
4102                                             GObject            *container,
4103                                             GObject            *object,
4104                                             const gchar        *action_path)
4105 {
4106   g_return_if_fail (GLADE_IS_WIDGET_ADAPTOR (adaptor));
4107   g_return_if_fail (G_IS_OBJECT (container));
4108   g_return_if_fail (G_IS_OBJECT (object));
4109   g_return_if_fail (g_type_is_a (G_OBJECT_TYPE (container), adaptor->priv->type));
4110 
4111   GLADE_WIDGET_ADAPTOR_GET_CLASS (adaptor)->child_action_activate (adaptor,
4112                                                                    container,
4113                                                                    object,
4114                                                                    action_path);
4115 }
4116 
4117 /**
4118  * glade_widget_adaptor_action_submenu:
4119  * @adaptor:   A #GladeWidgetAdaptor
4120  * @object:    The #GObject
4121  * @action_path: The action identifier in the action tree
4122  *
4123  * This delagate function is used to create dynamically customized
4124  * submenus. Called only for actions that dont have children.
4125  *
4126  * Returns: A newly created #GtkMenu or %NULL
4127  */
4128 GtkWidget *
glade_widget_adaptor_action_submenu(GladeWidgetAdaptor * adaptor,GObject * object,const gchar * action_path)4129 glade_widget_adaptor_action_submenu (GladeWidgetAdaptor *adaptor,
4130                                      GObject            *object,
4131                                      const gchar        *action_path)
4132 {
4133   g_return_val_if_fail (GLADE_IS_WIDGET_ADAPTOR (adaptor), NULL);
4134   g_return_val_if_fail (G_IS_OBJECT (object), NULL);
4135   g_return_val_if_fail (g_type_is_a (G_OBJECT_TYPE (object), adaptor->priv->type),
4136                         NULL);
4137 
4138   if (GLADE_WIDGET_ADAPTOR_GET_CLASS (adaptor)->action_submenu)
4139     return GLADE_WIDGET_ADAPTOR_GET_CLASS (adaptor)->action_submenu (adaptor,
4140                                                                      object,
4141                                                                      action_path);
4142 
4143   return NULL;
4144 }
4145 
4146 /**
4147  * glade_widget_adaptor_depends:
4148  * @adaptor: A #GladeWidgetAdaptor
4149  * @widget: A #GladeWidget of the adaptor
4150  * @another: another #GladeWidget
4151  *
4152  * Checks whether @widget depends on @another to be placed earlier in
4153  * the glade file.
4154  *
4155  * Returns: whether @widget depends on @another being parsed first in
4156  * the resulting glade file.
4157  *
4158  * Deprecated: 3.18
4159  */
4160 gboolean
glade_widget_adaptor_depends(GladeWidgetAdaptor * adaptor,GladeWidget * widget,GladeWidget * another)4161 glade_widget_adaptor_depends (GladeWidgetAdaptor *adaptor,
4162                               GladeWidget        *widget,
4163                               GladeWidget        *another)
4164 {
4165   return FALSE;
4166 }
4167 
4168 /**
4169  * glade_widget_adaptor_read_widget:
4170  * @adaptor: A #GladeWidgetAdaptor
4171  * @widget: The #GladeWidget
4172  * @node: The #GladeXmlNode
4173  *
4174  * This function is called to update @widget from @node
4175  * when loading xml files.
4176  */
4177 void
glade_widget_adaptor_read_widget(GladeWidgetAdaptor * adaptor,GladeWidget * widget,GladeXmlNode * node)4178 glade_widget_adaptor_read_widget (GladeWidgetAdaptor *adaptor,
4179                                   GladeWidget        *widget,
4180                                   GladeXmlNode       *node)
4181 {
4182   g_return_if_fail (GLADE_IS_WIDGET_ADAPTOR (adaptor));
4183   g_return_if_fail (GLADE_IS_WIDGET (widget));
4184   g_return_if_fail (node != NULL);
4185 
4186   GLADE_WIDGET_ADAPTOR_GET_CLASS (adaptor)->read_widget (adaptor, widget, node);
4187 }
4188 
4189 
4190 /**
4191  * glade_widget_adaptor_write_widget:
4192  * @adaptor: A #GladeWidgetAdaptor
4193  * @widget: The #GladeWidget
4194  * @context: The #GladeXmlContext
4195  * @node: The #GladeXmlNode
4196  *
4197  * This function is called to write @widget to @node
4198  * when writing xml files.
4199  */
4200 void
glade_widget_adaptor_write_widget(GladeWidgetAdaptor * adaptor,GladeWidget * widget,GladeXmlContext * context,GladeXmlNode * node)4201 glade_widget_adaptor_write_widget (GladeWidgetAdaptor *adaptor,
4202                                    GladeWidget        *widget,
4203                                    GladeXmlContext    *context,
4204                                    GladeXmlNode       *node)
4205 {
4206   g_return_if_fail (GLADE_IS_WIDGET_ADAPTOR (adaptor));
4207   g_return_if_fail (GLADE_IS_WIDGET (widget));
4208   g_return_if_fail (node != NULL);
4209 
4210   GLADE_WIDGET_ADAPTOR_GET_CLASS (adaptor)->write_widget (adaptor, widget,
4211                                                           context, node);
4212 }
4213 
4214 
4215 /**
4216  * glade_widget_adaptor_write_widget_after:
4217  * @adaptor: A #GladeWidgetAdaptor
4218  * @widget: The #GladeWidget
4219  * @context: The #GladeXmlContext
4220  * @node: The #GladeXmlNode
4221  *
4222  * This function is called to write @widget to @node
4223  * when writing xml files (after writing children)
4224  */
4225 void
glade_widget_adaptor_write_widget_after(GladeWidgetAdaptor * adaptor,GladeWidget * widget,GladeXmlContext * context,GladeXmlNode * node)4226 glade_widget_adaptor_write_widget_after (GladeWidgetAdaptor *adaptor,
4227 					 GladeWidget        *widget,
4228 					 GladeXmlContext    *context,
4229 					 GladeXmlNode       *node)
4230 {
4231   g_return_if_fail (GLADE_IS_WIDGET_ADAPTOR (adaptor));
4232   g_return_if_fail (GLADE_IS_WIDGET (widget));
4233   g_return_if_fail (node != NULL);
4234 
4235   GLADE_WIDGET_ADAPTOR_GET_CLASS (adaptor)->write_widget_after (adaptor, widget,
4236 								context, node);
4237 }
4238 
4239 
4240 /**
4241  * glade_widget_adaptor_read_child:
4242  * @adaptor: A #GladeWidgetAdaptor
4243  * @widget: The #GladeWidget
4244  * @node: The #GladeXmlNode
4245  *
4246  * This function is called to update load a child @widget
4247  * from @node when loading xml files (will recurse into
4248  * glade_widget_read())
4249  */
4250 void
glade_widget_adaptor_read_child(GladeWidgetAdaptor * adaptor,GladeWidget * widget,GladeXmlNode * node)4251 glade_widget_adaptor_read_child (GladeWidgetAdaptor *adaptor,
4252                                  GladeWidget        *widget,
4253                                  GladeXmlNode       *node)
4254 {
4255   g_return_if_fail (GLADE_IS_WIDGET_ADAPTOR (adaptor));
4256   g_return_if_fail (GLADE_IS_WIDGET (widget));
4257   g_return_if_fail (node != NULL);
4258 
4259   GLADE_WIDGET_ADAPTOR_GET_CLASS (adaptor)->read_child (adaptor, widget, node);
4260 }
4261 
4262 
4263 /**
4264  * glade_widget_adaptor_write_child:
4265  * @adaptor: A #GladeWidgetAdaptor
4266  * @widget: The #GladeWidget
4267  * @context: The #GladeXmlContext
4268  * @node: The #GladeXmlNode
4269  *
4270  * This function is called to write the child @widget to @node
4271  * when writing xml files (takes care of packing and recurses
4272  * into glade_widget_write())
4273  */
4274 void
glade_widget_adaptor_write_child(GladeWidgetAdaptor * adaptor,GladeWidget * widget,GladeXmlContext * context,GladeXmlNode * node)4275 glade_widget_adaptor_write_child (GladeWidgetAdaptor *adaptor,
4276                                   GladeWidget        *widget,
4277                                   GladeXmlContext    *context,
4278                                   GladeXmlNode       *node)
4279 {
4280   g_return_if_fail (GLADE_IS_WIDGET_ADAPTOR (adaptor));
4281   g_return_if_fail (GLADE_IS_WIDGET (widget));
4282   g_return_if_fail (node != NULL);
4283 
4284   GLADE_WIDGET_ADAPTOR_GET_CLASS (adaptor)->write_child (adaptor, widget,
4285                                                          context, node);
4286 }
4287 
4288 
4289 /**
4290  * glade_widget_adaptor_create_eprop:
4291  * @adaptor: A #GladeWidgetAdaptor
4292  * @klass: The #GladePropertyClass to be edited
4293  * @use_command: whether to use the GladeCommand interface
4294  * to commit property changes
4295  *
4296  * Creates a GladeEditorProperty to edit @klass
4297  *
4298  * Returns: A newly created #GladeEditorProperty
4299  */
4300 GladeEditorProperty *
glade_widget_adaptor_create_eprop(GladeWidgetAdaptor * adaptor,GladePropertyClass * klass,gboolean use_command)4301 glade_widget_adaptor_create_eprop (GladeWidgetAdaptor *adaptor,
4302                                    GladePropertyClass *klass,
4303                                    gboolean            use_command)
4304 {
4305   GladeEditorProperty *eprop;
4306   g_return_val_if_fail (GLADE_IS_WIDGET_ADAPTOR (adaptor), NULL);
4307   g_return_val_if_fail (GLADE_IS_PROPERTY_CLASS (klass), NULL);
4308 
4309   eprop = GLADE_WIDGET_ADAPTOR_GET_CLASS
4310       (adaptor)->create_eprop (adaptor, klass, use_command);
4311 
4312   /* XXX we really need to print a g_error() here, exept we are
4313    * now using this func to test for unsupported properties
4314    * at init time from glade-property-class */
4315 
4316   return eprop;
4317 }
4318 
4319 
4320 
4321 /**
4322  * glade_widget_adaptor_create_eprop_by_name:
4323  * @adaptor: A #GladeWidgetAdaptor
4324  * @property_id: the string if of the coresponding #GladePropertyClass to be edited
4325  * @packing: whether this reffers to a packing property
4326  * @use_command: whether to use the GladeCommand interface
4327  * to commit property changes
4328  *
4329  * Creates a #GladeEditorProperty to edit #GladePropertyClass @name in @adaptor
4330  *
4331  * Returns: A newly created #GladeEditorProperty
4332  */
4333 GladeEditorProperty *
glade_widget_adaptor_create_eprop_by_name(GladeWidgetAdaptor * adaptor,const gchar * property_id,gboolean packing,gboolean use_command)4334 glade_widget_adaptor_create_eprop_by_name (GladeWidgetAdaptor *adaptor,
4335                                            const gchar        *property_id,
4336                                            gboolean            packing,
4337                                            gboolean            use_command)
4338 {
4339   GladePropertyClass *klass;
4340   g_return_val_if_fail (GLADE_IS_WIDGET_ADAPTOR (adaptor), NULL);
4341   g_return_val_if_fail (property_id && property_id[0], NULL);
4342 
4343   if (packing)
4344     klass = glade_widget_adaptor_get_pack_property_class (adaptor, property_id);
4345   else
4346     klass = glade_widget_adaptor_get_property_class (adaptor, property_id);
4347 
4348   g_return_val_if_fail (klass != NULL, NULL);
4349 
4350   return GLADE_WIDGET_ADAPTOR_GET_CLASS
4351       (adaptor)->create_eprop (adaptor, klass, use_command);
4352 }
4353 
4354 
4355 /**
4356  * glade_widget_adaptor_string_from_value:
4357  * @adaptor: A #GladeWidgetAdaptor
4358  * @klass: The #GladePropertyClass
4359  * @value: The #GValue to convert to a string
4360  *
4361  * For normal properties this is used to serialize
4362  * property values, for custom properties its still
4363  * needed to update the UI for undo/redo items etc.
4364  *
4365  * Returns: A newly allocated string representation of @value
4366  */
4367 gchar *
glade_widget_adaptor_string_from_value(GladeWidgetAdaptor * adaptor,GladePropertyClass * klass,const GValue * value)4368 glade_widget_adaptor_string_from_value (GladeWidgetAdaptor *adaptor,
4369                                         GladePropertyClass *klass,
4370                                         const GValue       *value)
4371 {
4372   g_return_val_if_fail (GLADE_IS_WIDGET_ADAPTOR (adaptor), NULL);
4373   g_return_val_if_fail (GLADE_IS_PROPERTY_CLASS (klass), NULL);
4374   g_return_val_if_fail (value != NULL, NULL);
4375 
4376   return GLADE_WIDGET_ADAPTOR_GET_CLASS (adaptor)->string_from_value (adaptor,
4377                                                                       klass,
4378                                                                       value);
4379 }
4380 
4381 
4382 /**
4383  * glade_widget_adaptor_get_signal_class:
4384  * @adaptor: A #GladeWidgetAdaptor
4385  * @name: the name of the signal class.
4386  *
4387  * Looks up signal class @name on @adaptor.
4388  *
4389  * Returns: a #GladeSignalClass or %NULL
4390  */
4391 GladeSignalClass *
glade_widget_adaptor_get_signal_class(GladeWidgetAdaptor * adaptor,const gchar * name)4392 glade_widget_adaptor_get_signal_class (GladeWidgetAdaptor *adaptor,
4393                                        const gchar        *name)
4394 {
4395   GList *list;
4396   GladeSignalClass *signal;
4397 
4398   g_return_val_if_fail (GLADE_IS_WIDGET_ADAPTOR (adaptor), NULL);
4399   g_return_val_if_fail (name != NULL, NULL);
4400 
4401   for (list = adaptor->priv->signals; list; list = list->next)
4402     {
4403       signal = list->data;
4404       if (!strcmp (glade_signal_class_get_name (signal), name))
4405         return signal;
4406     }
4407 
4408   return NULL;
4409 }
4410 
4411 
4412 /**
4413  * glade_widget_adaptor_create_editable:
4414  * @adaptor: A #GladeWidgetAdaptor
4415  * @type: The #GladeEditorPageType
4416  *
4417  * This is used to allow the backend to override the way an
4418  * editor page is layed out (note that editor widgets are created
4419  * on demand and not at startup).
4420  *
4421  * Returns: A new #GladeEditable widget
4422  */
4423 GladeEditable *
glade_widget_adaptor_create_editable(GladeWidgetAdaptor * adaptor,GladeEditorPageType type)4424 glade_widget_adaptor_create_editable (GladeWidgetAdaptor *adaptor,
4425                                       GladeEditorPageType type)
4426 {
4427   g_return_val_if_fail (GLADE_IS_WIDGET_ADAPTOR (adaptor), NULL);
4428 
4429   return GLADE_WIDGET_ADAPTOR_GET_CLASS
4430       (adaptor)->create_editable (adaptor, type);
4431 }
4432