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 (¶meter.value, pspec[i]->value_type);
3220 g_value_copy (glade_property_class_get_default (pclass), ¶meter.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