glade-widget-adaptor.c 148 KB
Newer Older
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23
/*
 * Copyright (C) 2001 Ximian, Inc.
 *
 * This program is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as
 * published by the Free Software Foundation; either version 2 of the
 * License, or (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program; if not, write to the Free Software
 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
 *
 * Authors:
 *   Tristan Van Berkom <tvb@gnome.org>
 */

#include <config.h>

24 25 26 27
/**
 * SECTION:glade-widget-adaptor
 * @Short_Description: Adaptor base class to add runtime support for each widget class.
 * 
28 29 30 31 32
 * The #GladeWidgetAdaptor object is a proxy for widget class support in Glade.
 * it is automatically generated from the xml and allows you to override its
 * methods in the plugin library for fine grained support on how you load/save
 * widgets and handle thier properties in the runtime and more.
 * 
33 34
 */

35 36 37 38
#include "glade.h"
#include "glade-widget-adaptor.h"
#include "glade-xml-utils.h"
#include "glade-signal.h"
39 40
#include "glade-marshallers.h"
#include "glade-accumulators.h"
41
#include "glade-displayable-values.h"
42
#include "glade-editor-table.h"
43
#include "glade-cursor.h"
44
#include "glade-private.h"
45

46 47 48 49
/* For g_file_exists */
#include <sys/types.h>
#include <string.h>

50
#include <glib.h>
51 52 53 54
#include <glib/gi18n-lib.h>
#include <gmodule.h>
#include <ctype.h>

Vincent Geddes's avatar
Vincent Geddes committed
55
#define DEFAULT_ICON_NAME "widget-gtk-frame"
56

57 58
struct _GladeWidgetAdaptorPrivate
{
59 60 61 62 63
  GType        type;                /* GType of the widget */
  GType        real_type;

  gchar       *name;                /* Name of the widget, for example GtkButton */
  gchar       *generic_name;        /* Used to generate names of new widgets, for
64 65 66
                                     * example "button" so that we generate button1,
                                     * button2, buttonX ..
                                     */
67 68 69 70
  gchar       *icon_name;           /* icon name to use for widget class */
  gchar       *missing_icon;        /* the name of the missing icon if it was not found */

  gchar       *title;               /* Translated class name used in the UI */
71
  GList       *properties;          /* List of GladePropertyDef objects.
72 73 74 75 76 77
                                     * [see glade-property.h] this list contains
                                     * properties about the widget that we are going
                                     * to modify. Like "title", "label", "rows" .
                                     * Each property creates an input in the propety
                                     * editor.
                                     */
78
  GList       *packing_props;       /* List of GladePropertyDef objects that describe
79 80 81 82
                                     * properties for child objects packing definition -
                                     * note there may be more than one type of child supported
                                     * by a widget and thus they may have different sets
                                     * of properties for each type - this association is
83
                                     * managed on the GladePropertyDef proper.
84
                                     */
85
  GList       *signals;              /* List of GladeSignalDef objects */
86
  GList       *child_packings;       /* Default packing property values */
87 88
  GList       *actions;              /* A list of GladeWidgetActionDef */
  GList       *packing_actions;      /* A list of GladeWidgetActionDef for child objects */
89
  GList       *internal_children;    /* A list of GladeInternalChild */
90
  gchar       *catalog;              /* The name of the widget catalog this class
91 92
                                      * was declared by.
                                      */
93
  gchar       *book;                 /* DevHelp search namespace for this widget class
94
                                      */
95 96 97 98

  GdkCursor   *cursor;                /* a cursor for inserting widgets */

  gchar       *special_child_type;    /* Special case code for children that
99 100 101
                                       * are special children (like notebook tab 
                                       * widgets for example).
                                       */
102
  gboolean     query;                 /* Do we have to query the user, see glade_widget_adaptor_query() */
103 104
};

105 106 107 108
struct _GladeChildPacking
{
  gchar *parent_name;
  GList *packing_defaults;
109 110
};

111

112 113 114 115
struct _GladePackingDefault
{
  gchar *id;
  gchar *value;
116 117
};

118 119 120 121 122 123
struct _GladeInternalChild
{
  gchar *name;
  gboolean anarchist;
  GList *children;
};
124

125 126 127 128 129 130 131 132 133 134 135
enum
{
  PROP_0,
  PROP_NAME,
  PROP_TYPE,
  PROP_TITLE,
  PROP_GENERIC_NAME,
  PROP_ICON_NAME,
  PROP_CATALOG,
  PROP_BOOK,
  PROP_SPECIAL_TYPE,
136 137
  PROP_CURSOR,
  PROP_QUERY
138 139
};

140 141
typedef struct _GladeChildPacking GladeChildPacking;
typedef struct _GladePackingDefault GladePackingDefault;
142
typedef struct _GladeInternalChild GladeInternalChild;
143

144
static GHashTable *adaptor_hash = NULL;
145

146 147 148 149
/* This object used to be registered as GladeGObjectAdaptor but there is
 * no reason for it since the autogenerated class for GtWidget is GladeGtkWidgetAdaptor
 * TODO: rename GladeWidgetAdaptor to GladeGObjectAdator or GladeObjectAdator
 */
150
G_DEFINE_TYPE_WITH_PRIVATE (GladeWidgetAdaptor, glade_widget_adaptor, G_TYPE_OBJECT);
151

152 153 154 155 156
/*******************************************************************************
                              Helper functions
 *******************************************************************************/

static void
157
gwa_create_cursor (GladeWidgetAdaptor *adaptor)
158
{
159 160 161 162 163 164
  GdkPixbuf *tmp_pixbuf, *widget_pixbuf;
  const GdkPixbuf *add_pixbuf;
  GdkDisplay *display;
  GError *error = NULL;

  /* only certain widget classes need to have cursors */
165 166 167
  if (G_TYPE_IS_INSTANTIATABLE (adaptor->priv->type) == FALSE ||
      G_TYPE_IS_ABSTRACT (adaptor->priv->type) != FALSE ||
      adaptor->priv->generic_name == NULL)
168
    return;
169

170 171 172
  /* cannot continue if 'add widget' cursor pixbuf has not been loaded for any reason */
  if ((add_pixbuf = glade_cursor_get_add_widget_pixbuf ()) == NULL)
    return;
173

174
  display = gdk_display_get_default ();
175

176 177 178
  /* create a temporary pixbuf clear to transparent black */
  tmp_pixbuf = gdk_pixbuf_new (GDK_COLORSPACE_RGB, TRUE, 8, 32, 32);
  gdk_pixbuf_fill (tmp_pixbuf, 0x00000000);
179

180
  if (gtk_icon_theme_has_icon
181
      (gtk_icon_theme_get_default (), adaptor->priv->icon_name))
182 183
    {
      widget_pixbuf = gtk_icon_theme_load_icon (gtk_icon_theme_get_default (),
184
                                                adaptor->priv->icon_name,
185 186 187 188 189
                                                22, 0, &error);

      if (error)
        {
          g_warning ("Could not load image data for named icon '%s': %s",
190
                     adaptor->priv->icon_name, error->message);
191 192 193
          g_error_free (error);
          return;
        }
194

195 196 197 198 199
    }
  else
    {
      return;
    }
200

201 202 203
  /* composite pixbufs */
  gdk_pixbuf_composite (widget_pixbuf, tmp_pixbuf,
                        8, 8, 22, 22, 8, 8, 1, 1, GDK_INTERP_NEAREST, 255);
204

205 206
  gdk_pixbuf_composite (add_pixbuf, tmp_pixbuf,
                        0, 0, 12, 12, 0, 0, 1, 1, GDK_INTERP_NEAREST, 255);
207 208


209 210
  adaptor->priv->cursor =
      gdk_cursor_new_from_pixbuf (display, tmp_pixbuf, 6, 6);
211

212 213
  g_object_unref (tmp_pixbuf);
  g_object_unref (widget_pixbuf);
214 215
}

216
static gboolean
217 218
glade_widget_adaptor_hash_find (gpointer key,
                                gpointer value, 
219
                                gpointer user_data)
220
{
221 222 223
  GladeWidgetAdaptor *adaptor = value;
  GType *type = user_data;

224
  if (g_type_is_a (adaptor->priv->type, *type))
225
    {
226
      *type = adaptor->priv->type;
227 228 229 230
      return TRUE;
    }

  return FALSE;
231 232 233 234 235
}

static void
glade_abort_if_derived_adaptors_exist (GType type)
{
236 237 238 239 240 241 242 243 244
  if (adaptor_hash)
    {
      GType retval = type;

      g_hash_table_find (adaptor_hash, glade_widget_adaptor_hash_find, &retval);
      if (retval != type)
        g_error (_("A derived adaptor (%s) of %s already exist!"),
                 g_type_name (retval), g_type_name (type));
    }
245
}
246

247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269
static GladeInternalChild *
gwa_internal_child_find (GList *list, const gchar *name)
{
  GList *l;

  for (l = list; l; l = g_list_next (l))
    {
      GladeInternalChild *data = l->data;

      if (strcmp (data->name, name) == 0)
        return data;
      
      if (data->children)
        {
          GladeInternalChild *child;
          if ((child = gwa_internal_child_find (data->children, name)))
            return child;
        }
    }
  
  return NULL;
}

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
{
278 279
  GladeWidgetAdaptor *parent_adaptor = NULL;
  GType iter_type;
280

281 282 283 284 285 286 287
  for (iter_type = g_type_parent (adaptor_type);
       iter_type > 0; iter_type = g_type_parent (iter_type))
    {
      if ((parent_adaptor =
           glade_widget_adaptor_get_by_type (iter_type)) != NULL)
        return parent_adaptor;
    }
288

289
  return NULL;
290 291
}

292 293 294 295 296
/**
 * glade_widget_adaptor_get_parent_adaptor:
 * @adaptor: a #GladeWidgetAdaptor
 *
 * Returns: (transfer none): the parent #GladeWidgetAdaptor according to @adaptor type
297 298
 */
GladeWidgetAdaptor *
299
glade_widget_adaptor_get_parent_adaptor (GladeWidgetAdaptor *adaptor)
300
{
301
  g_return_val_if_fail (GLADE_IS_WIDGET_ADAPTOR (adaptor), NULL);
302

303
  return glade_widget_adaptor_get_parent_adaptor_by_type (adaptor->priv->type);
304
}
305

306 307 308 309 310 311 312
gboolean
glade_widget_adaptor_has_internal_children (GladeWidgetAdaptor *adaptor)
{
  g_return_val_if_fail (GLADE_IS_WIDGET_ADAPTOR (adaptor), FALSE);
  return adaptor->priv->internal_children != NULL;
}

313
static gint
314
gwa_signal_comp (gpointer a, gpointer b)
315
{
316
  GladeSignalDef *signal_a = a, *signal_b = b;
317

318 319
  return strcmp (glade_signal_def_get_name (signal_b), 
                 glade_signal_def_get_name (signal_a));
320 321
}

322
static gint
323
gwa_signal_find_comp (gpointer a, gpointer b)
324
{
325
  GladeSignalDef *signal = a;
326
  gchar *name = b;
327
  return strcmp (name, glade_signal_def_get_name (signal));
328 329
}

330
static void
331
gwa_add_signals (GladeWidgetAdaptor *adaptor, GList **signals, GType type)
332
{
333
  guint               count, *sig_ids, num_signals;
334
  GladeWidgetAdaptor *type_adaptor;
335
  GladeSignalDef     *signal;
336
  GList              *list = NULL;
337 338 339

  type_adaptor = glade_widget_adaptor_get_by_type (type);

340
  sig_ids = g_signal_list_ids (type, &num_signals);
341

342 343
  for (count = 0; count < num_signals; count++)
    {
344
      signal = glade_signal_def_new (type_adaptor ? 
345 346
                                       type_adaptor : adaptor,
                                       type, sig_ids[count]);
347

348
      list = g_list_prepend (list, signal);
349
    }
350 351 352 353
  g_free (sig_ids);

  list = g_list_sort (list, (GCompareFunc)gwa_signal_comp);
  *signals = g_list_concat (list, *signals);
354 355 356
}

static GList *
357
gwa_list_signals (GladeWidgetAdaptor *adaptor, GType real_type)
358 359 360 361 362 363 364 365 366 367 368 369 370 371 372
{
  GList *signals = NULL;
  GType type, parent, *i, *p;

  g_return_val_if_fail (real_type != 0, NULL);

  for (type = real_type; g_type_is_a (type, G_TYPE_OBJECT); type = parent)
    {
      parent = g_type_parent (type);

      /* Add class signals */
      gwa_add_signals (adaptor, &signals, type);

      /* Add class interfaces signals */
      for (i = p = g_type_interfaces (type, NULL); *i; i++)
373
        if (!g_type_is_a (parent, *i))
374 375 376 377 378 379 380 381 382
          gwa_add_signals (adaptor, &signals, *i);

      g_free (p);
    }

  return g_list_reverse (signals);
}

static GList *
383
gwa_clone_parent_properties (GladeWidgetAdaptor *adaptor, gboolean is_packing)
384 385 386 387 388 389
{
  GladeWidgetAdaptor *parent_adaptor;
  GList *properties = NULL, *list, *proplist;

  if ((parent_adaptor = gwa_get_parent_adaptor (adaptor)) != NULL)
    {
390 391
      gboolean reset_version;

392
      proplist = is_packing ?
393
          parent_adaptor->priv->packing_props : parent_adaptor->priv->properties;
394

395
      /* Reset versioning in derived catalogs just once */
396
      reset_version = strcmp (adaptor->priv->catalog, parent_adaptor->priv->catalog) != 0;
397

398 399
      for (list = proplist; list; list = list->next)
        {
400 401 402
          GladePropertyDef *pdef = glade_property_def_clone (list->data);
          if (reset_version)
            _glade_property_def_reset_version (pdef);
403

404
          glade_property_def_set_adaptor (pdef, adaptor);
405

406
          properties = g_list_prepend (properties, pdef);
407 408 409 410
        }
    }

  return g_list_reverse (properties);
411 412 413
}

static void
414
gwa_setup_introspected_props_from_pspecs (GladeWidgetAdaptor *adaptor,
415 416 417
                                          GParamSpec        **specs,
                                          gint                n_specs,
                                          gboolean            is_packing)
418 419
{
  GladeWidgetAdaptor *parent_adaptor = gwa_get_parent_adaptor (adaptor);
420
  GladePropertyDef *property_def;
421 422 423 424 425 426 427 428
  gint i;
  GList *list = NULL;

  for (i = 0; i < n_specs; i++)
    {
      if (parent_adaptor == NULL ||
          /* Dont create it if it already exists */
          (!is_packing &&
429 430
           !glade_widget_adaptor_get_property_def (parent_adaptor,
                                                   specs[i]->name)) ||
431
          (is_packing &&
432 433
           !glade_widget_adaptor_get_pack_property_def (parent_adaptor,
                                                        specs[i]->name)))
434
        {
435 436 437
          if ((property_def =
               glade_property_def_new_from_spec (adaptor, specs[i])) != NULL)
            list = g_list_prepend (list, property_def);
438 439 440 441
        }
    }

  if (is_packing)
442 443
    adaptor->priv->packing_props =
        g_list_concat (adaptor->priv->packing_props, g_list_reverse (list));
444
  else
445 446
    adaptor->priv->properties =
        g_list_concat (adaptor->priv->properties, g_list_reverse (list));
447 448 449
}

static void
450
gwa_setup_properties (GladeWidgetAdaptor *adaptor,
451 452
                      GObjectClass       *object_class,
                      gboolean            is_packing)
453 454 455 456 457 458
{
  GParamSpec **specs = NULL;
  guint n_specs = 0;
  GList *l;

  /* only GtkContainer child propeties can be introspected */
459
  if (is_packing && !g_type_is_a (adaptor->priv->type, GTK_TYPE_CONTAINER))
460 461 462 463
    return;

  /* First clone the parents properties */
  if (is_packing)
464
    adaptor->priv->packing_props = gwa_clone_parent_properties (adaptor, is_packing);
465
  else
466
    adaptor->priv->properties = gwa_clone_parent_properties (adaptor, is_packing);
467 468 469 470 471 472 473 474 475 476 477 478 479 480 481 482

  /* Now automaticly introspect new properties added in this class,
   * allow the class writer to decide what to override in the resulting
   * list of properties.
   */
  if (is_packing)
    specs = gtk_container_class_list_child_properties (object_class, &n_specs);
  else
    specs = g_object_class_list_properties (object_class, &n_specs);
  gwa_setup_introspected_props_from_pspecs (adaptor, specs, n_specs,
                                            is_packing);
  g_free (specs);

  if (is_packing)
    {
      /* We have to mark packing properties from GladeWidgetAdaptor
483
       * because GladePropertyDef doesnt have a valid parent GType
484 485 486 487 488
       * to introspect it.
       *
       * (which could be used to call gtk_container_class_find_child_property()
       * and properly introspect whether or not its a packing property).
       */
489
      for (l = adaptor->priv->packing_props; l; l = l->next)
490
        {
491
          GladePropertyDef *property_def = l->data;
492

493
          glade_property_def_set_is_packing (property_def, TRUE);
494 495
        }
    }
496 497 498
}

static GList *
499
gwa_inherit_child_packing (GladeWidgetAdaptor *adaptor)
500
{
501 502
  GladeWidgetAdaptor *parent_adaptor;
  GList *child_packings = NULL, *packing_list, *default_list;
503

504 505
  if ((parent_adaptor = gwa_get_parent_adaptor (adaptor)) != NULL)
    {
506
      for (packing_list = parent_adaptor->priv->child_packings;
507 508 509 510
           packing_list; packing_list = packing_list->next)
        {
          GladeChildPacking *packing = packing_list->data;
          GladeChildPacking *packing_dup = g_new0 (GladeChildPacking, 1);
511

512
          packing_dup->parent_name = g_strdup (packing->parent_name);
513

514 515 516 517 518
          for (default_list = packing->packing_defaults;
               default_list; default_list = default_list->next)
            {
              GladePackingDefault *def = default_list->data;
              GladePackingDefault *def_dup = g_new0 (GladePackingDefault, 1);
519

520 521
              def_dup->id = g_strdup (def->id);
              def_dup->value = g_strdup (def->value);
522

523 524 525
              packing_dup->packing_defaults =
                  g_list_prepend (packing_dup->packing_defaults, def_dup);
            }
526

527 528 529 530
          child_packings = g_list_prepend (child_packings, packing_dup);
        }
    }
  return child_packings;
531 532
}

533
static void
534
gwa_inherit_signals (GladeWidgetAdaptor *adaptor)
535 536 537
{
  GladeWidgetAdaptor *parent_adaptor;
  GList *list, *node;
538
  GladeSignalDef *signal, *parent_signal;
539 540 541

  if ((parent_adaptor = gwa_get_parent_adaptor (adaptor)) != NULL)
    {
542
      for (list = adaptor->priv->signals; list; list = list->next)
543 544 545
        {
          signal = list->data;

546
          if ((node = g_list_find_custom (parent_adaptor->priv->signals, 
547
                                          glade_signal_def_get_name (signal),
548
                                          (GCompareFunc) gwa_signal_find_comp)) != NULL)
549 550 551
            {
              parent_signal = node->data;

552
              /* XXX FIXME: This is questionable, why should derived catalogs
553 554 555 556
               * reset the derived signal versions ???
               *
               * Reset versioning in derived catalogs just once
               */
557 558
              if (strcmp (adaptor->priv->catalog,
                          parent_adaptor->priv->catalog))
559
                glade_signal_def_set_since (signal, 0, 0);
560
              else
561 562 563
                glade_signal_def_set_since (signal, 
                                            glade_signal_def_since_major (parent_signal),
                                            glade_signal_def_since_minor (parent_signal));
564

565
              glade_signal_def_set_deprecated (signal, glade_signal_def_deprecated (parent_signal));
566 567 568
            }
        }
    }
569 570
}

571 572 573 574 575 576 577 578 579 580 581 582 583 584 585 586 587 588 589 590 591 592 593 594 595 596 597 598 599 600
static GladeInternalChild *
gwa_internal_children_new (gchar *name, gboolean anarchist)
{
  GladeInternalChild *data = g_slice_new0 (GladeInternalChild);

  data->name = g_strdup (name);
  data->anarchist = anarchist;

  return data;
}

static GList *
gwa_internal_children_clone (GList *children)
{
  GList *l, *retval = NULL;
  
  for (l = children; l; l = g_list_next (l))
    {
      GladeInternalChild *data, *child = l->data;

      data = gwa_internal_children_new (child->name, child->anarchist);
      retval = g_list_prepend (retval, data);

      if (child->children)
        data->children = gwa_internal_children_clone (child->children);
    }

  return g_list_reverse (retval);
}

601
static GObject *
602 603 604
glade_widget_adaptor_constructor (GType                  type,
                                  guint                  n_construct_properties,
                                  GObjectConstructParam *construct_properties)
605 606 607 608 609 610 611
{
  GladeWidgetAdaptor *adaptor, *parent_adaptor;
  GObject *ret_obj;
  GObjectClass *object_class;

  glade_abort_if_derived_adaptors_exist (type);

612
  ret_obj = G_OBJECT_CLASS (glade_widget_adaptor_parent_class)->constructor
613 614 615 616 617
      (type, n_construct_properties, construct_properties);

  adaptor = GLADE_WIDGET_ADAPTOR (ret_obj);
  parent_adaptor = gwa_get_parent_adaptor (adaptor);

618
  if (adaptor->priv->type == G_TYPE_NONE)
619
    g_warning ("Adaptor created without a type");
620
  if (adaptor->priv->name == NULL)
621 622 623
    g_warning ("Adaptor created without a name");

  /* Build decorations */
624
  if (!adaptor->priv->icon_name)
625
    adaptor->priv->icon_name = g_strdup ("image-missing");
626 627

  /* Let it leek */
628
  if ((object_class = g_type_class_ref (adaptor->priv->type)))
629 630
    {
      /* Build signals & properties */
631
      adaptor->priv->signals = gwa_list_signals (adaptor, adaptor->priv->type);
632 633 634 635 636 637 638

      gwa_inherit_signals (adaptor);
      gwa_setup_properties (adaptor, object_class, FALSE);
      gwa_setup_properties (adaptor, object_class, TRUE);
    }

  /* Inherit packing defaults here */
639
  adaptor->priv->child_packings = gwa_inherit_child_packing (adaptor);
640 641 642 643 644 645 646 647 648 649

  /* Inherit special-child-type */
  if (parent_adaptor)
    adaptor->priv->special_child_type =
        parent_adaptor->priv->special_child_type ?
        g_strdup (parent_adaptor->priv->special_child_type) : NULL;


  /* Reset version numbering if we're in a new catalog just once */
  if (parent_adaptor &&
650
      strcmp (adaptor->priv->catalog, parent_adaptor->priv->catalog))
651 652 653 654 655 656 657 658 659 660
    {
      GLADE_WIDGET_ADAPTOR_GET_CLASS (adaptor)->version_since_major =
          GLADE_WIDGET_ADAPTOR_GET_CLASS (adaptor)->version_since_minor = 0;
    }

  /* Copy parent actions */
  if (parent_adaptor)
    {
      GList *l;

661
      if (parent_adaptor->priv->actions)
662
        {
663
          for (l = parent_adaptor->priv->actions; l; l = g_list_next (l))
664
            {
665
              GladeWidgetActionDef *child = glade_widget_action_def_clone (l->data);
666
              adaptor->priv->actions = g_list_prepend (adaptor->priv->actions, child);
667
            }
668
          adaptor->priv->actions = g_list_reverse (adaptor->priv->actions);
669 670
        }

671
      if (parent_adaptor->priv->packing_actions)
672
        {
673
          for (l = parent_adaptor->priv->packing_actions; l; l = g_list_next (l))
674
            {
675
              GladeWidgetActionDef *child = glade_widget_action_def_clone (l->data);
676 677
              adaptor->priv->packing_actions =
                  g_list_prepend (adaptor->priv->packing_actions, child);
678
            }
679
          adaptor->priv->packing_actions = g_list_reverse (adaptor->priv->packing_actions);
680 681 682
        }
    }

683 684 685 686
  /* Copy parent internal children */
  if (parent_adaptor && parent_adaptor->priv->internal_children)
    adaptor->priv->internal_children = gwa_internal_children_clone (parent_adaptor->priv->internal_children);

687
  return ret_obj;
688 689 690
}

static void
691
gwa_packing_default_free (GladePackingDefault *def)
692
{
693 694 695
  g_clear_pointer (&def->id, g_free);
  g_clear_pointer (&def->value, g_free);
  g_free (def);
696 697 698
}

static void
699
gwa_child_packing_free (GladeChildPacking *packing)
700
{
701
  g_clear_pointer (&packing->parent_name, g_free);
702

703 704 705 706
  g_list_free_full (packing->packing_defaults,
                    (GDestroyNotify) gwa_packing_default_free);
  packing->packing_defaults = NULL;
  g_free (packing);
707 708
}

709 710 711
static void
gwa_glade_internal_child_free (GladeInternalChild *child)
{
712
  g_clear_pointer (&child->name, g_free);
713 714
  if (child->children)
    {
715 716 717
      g_list_free_full (child->children,
                        (GDestroyNotify) gwa_glade_internal_child_free);
      child->children = NULL;
718 719
    }

720
  g_slice_free (GladeInternalChild, child);
721 722
}

723
static void
724
glade_widget_adaptor_finalize (GObject *object)
725 726
{
  GladeWidgetAdaptor *adaptor = GLADE_WIDGET_ADAPTOR (object);
727

728
  /* Free properties and signals */
729
  g_list_free_full (adaptor->priv->properties,
730
                    (GDestroyNotify) glade_property_def_free);
731
  adaptor->priv->properties = NULL;
732

733
  g_list_free_full (adaptor->priv->packing_props,
734
                    (GDestroyNotify) glade_property_def_free);
735
  adaptor->priv->packing_props = NULL;
736

737
  g_list_free_full (adaptor->priv->signals,
738
                    (GDestroyNotify) glade_signal_def_free);
739
  adaptor->priv->signals = NULL;
740 741

  /* Free child packings */
742 743 744 745 746 747 748 749 750 751 752 753 754 755 756
  g_list_free_full (adaptor->priv->child_packings,
                    (GDestroyNotify) gwa_child_packing_free);
  adaptor->priv->child_packings = NULL;

  g_clear_pointer (&adaptor->priv->book, g_free);
  g_clear_pointer (&adaptor->priv->catalog, g_free);
  g_clear_pointer (&adaptor->priv->special_child_type, g_free);

  g_clear_object (&adaptor->priv->cursor);

  g_clear_pointer (&adaptor->priv->name, g_free);
  g_clear_pointer (&adaptor->priv->generic_name, g_free);
  g_clear_pointer (&adaptor->priv->title, g_free);
  g_clear_pointer (&adaptor->priv->icon_name, g_free);
  g_clear_pointer (&adaptor->priv->missing_icon, g_free);
757 758 759

  if (adaptor->priv->actions)
    {
760
      g_list_free_full (adaptor->priv->actions,
761
                        (GDestroyNotify) glade_widget_action_def_free);
762
      adaptor->priv->actions = NULL;
763 764
    }

765
  if (adaptor->priv->packing_actions)
766
    {
767
      g_list_free_full (adaptor->priv->packing_actions,
768
                        (GDestroyNotify) glade_widget_action_def_free);
769
      adaptor->priv->packing_actions = NULL;
770 771
    }

772 773 774 775 776 777
  if (adaptor->priv->internal_children)
    {
      g_list_free_full (adaptor->priv->internal_children,
                        (GDestroyNotify) gwa_glade_internal_child_free);
      adaptor->priv->internal_children = NULL;
    }
778

779
  G_OBJECT_CLASS (glade_widget_adaptor_parent_class)->finalize (object);
780 781 782
}

static void
783 784
glade_widget_adaptor_real_set_property (GObject      *object,
                                        guint         prop_id,
785
                                        const GValue *value,
786
                                        GParamSpec   *pspec)
787 788 789 790 791 792 793 794 795
{
  GladeWidgetAdaptor *adaptor;

  adaptor = GLADE_WIDGET_ADAPTOR (object);

  switch (prop_id)
    {
      case PROP_NAME:
        /* assume once (construct-only) */
796 797
        adaptor->priv->name = g_value_dup_string (value);
        adaptor->priv->real_type = g_type_from_name (adaptor->priv->name);
798 799 800
        break;
      case PROP_ICON_NAME:
        /* assume once (construct-only) */
801
        adaptor->priv->icon_name = g_value_dup_string (value);
802 803
        break;
      case PROP_TYPE:
804
        adaptor->priv->type = g_value_get_gtype (value);
805 806
        break;
      case PROP_TITLE:
807
        g_clear_pointer (&adaptor->priv->title, g_free);
808
        adaptor->priv->title = g_value_dup_string (value);
809 810
        break;
      case PROP_GENERIC_NAME:
811
        g_clear_pointer (&adaptor->priv->generic_name, g_free);
812
        adaptor->priv->generic_name = g_value_dup_string (value);
813 814 815
        break;
      case PROP_CATALOG:
        /* assume once (construct-only) */
816
        g_clear_pointer (&adaptor->priv->catalog, g_free);
817 818 819 820
        adaptor->priv->catalog = g_value_dup_string (value);
        break;
      case PROP_BOOK:
        /* assume once (construct-only) */
821
        g_clear_pointer (&adaptor->priv->book, g_free);
822 823 824
        adaptor->priv->book = g_value_dup_string (value);
        break;
      case PROP_SPECIAL_TYPE:
825
        /* assume once (construct-only) */ 
826
        g_clear_pointer (&adaptor->priv->special_child_type, g_free);
827
        adaptor->priv->special_child_type = g_value_dup_string (value);
828
        break;
829 830 831
      case PROP_QUERY:
        adaptor->priv->query = g_value_get_boolean (value);
        break;
832 833 834 835
      default:
        G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
        break;
    }
836 837 838
}

static void
839 840 841
glade_widget_adaptor_real_get_property (GObject    *object,
                                        guint       prop_id,
                                        GValue     *value,
842
                                        GParamSpec *pspec)
843 844 845 846 847 848 849 850 851
{

  GladeWidgetAdaptor *adaptor;

  adaptor = GLADE_WIDGET_ADAPTOR (object);

  switch (prop_id)
    {
      case PROP_NAME:
852
        g_value_set_string (value, adaptor->priv->name);
853 854
        break;
      case PROP_TYPE:
855
        g_value_set_gtype (value, adaptor->priv->type);
856 857
        break;
      case PROP_TITLE:
858
        g_value_set_string (value, adaptor->priv->title);
859 860
        break;
      case PROP_GENERIC_NAME:
861
        g_value_set_string (value, adaptor->priv->generic_name);
862 863
        break;
      case PROP_ICON_NAME:
864
        g_value_set_string (value, adaptor->priv->icon_name);
865 866 867 868 869 870 871 872 873 874 875 876 877
        break;
      case PROP_CATALOG:
        g_value_set_string (value, adaptor->priv->catalog);
        break;
      case PROP_BOOK:
        g_value_set_string (value, adaptor->priv->book);
        break;
      case PROP_SPECIAL_TYPE:
        g_value_set_string (value, adaptor->priv->special_child_type);
        break;
      case PROP_CURSOR:
        g_value_set_pointer (value, adaptor->priv->cursor);
        break;
878 879 880
      case PROP_QUERY:
        g_value_set_boolean (value, adaptor->priv->query);
        break;
881 882 883 884
      default:
        G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
        break;
    }
885 886
}

887 888 889
/*******************************************************************************
                  GladeWidgetAdaptor base class implementations
 *******************************************************************************/
890
static GladeWidget *
891
glade_widget_adaptor_object_create_widget (GladeWidgetAdaptor *adaptor,
892 893
                                           const gchar        *first_property_name,
                                           va_list             var_args)
894
{
895 896
  return GLADE_WIDGET (g_object_new_valist (GLADE_TYPE_WIDGET,
                                            first_property_name, var_args));
897 898
}

899
static GObject *
900
glade_widget_adaptor_object_construct_object (GladeWidgetAdaptor *adaptor,
901 902
                                              guint               n_parameters,
                                              GParameter         *parameters)
903
{
904
  return g_object_newv (adaptor->priv->type, n_parameters, parameters);
905 906
}

907 908
static void
glade_widget_adaptor_object_destroy_object (GladeWidgetAdaptor *adaptor,
909
                                            GObject            *object)
910 911 912 913
{
  /* Do nothing, just have a method here incase classes chain up */
}

914 915 916

static GObject *
glade_widget_adaptor_object_get_internal_child (GladeWidgetAdaptor *adaptor,
917 918
                                                GObject            *object,
                                                const gchar        *name)
919 920 921 922 923 924 925 926 927 928 929
{
  static GtkBuilder *builder = NULL;
  
  g_return_val_if_fail (GTK_IS_BUILDABLE (object), NULL);

  /* Dummy object just in case the interface use it for something */
  if (builder == NULL) builder = gtk_builder_new ();
  
  return gtk_buildable_get_internal_child (GTK_BUILDABLE (object), builder, name);
}

930 931
static gboolean
glade_widget_adaptor_object_add_verify (GladeWidgetAdaptor *adaptor,
932 933 934
                                        GObject            *parent,
                                        GObject            *child,
                                        gboolean            user_feedback)
935 936 937
{
  if (user_feedback)
    glade_util_ui_message (glade_app_get_window (),
938 939 940
                           GLADE_UI_INFO, NULL,
                           _("%s does not support adding any children."), 
                           adaptor->priv->title);
941 942 943

  return FALSE;
}
944

945
static void
946
glade_widget_adaptor_object_set_property (GladeWidgetAdaptor *adaptor,
947 948 949
                                          GObject            *object,
                                          const gchar        *property_name,
                                          const GValue       *value)
950
{
951
  g_object_set_property (object, property_name, value);
952 953 954
}

static void
955
glade_widget_adaptor_object_get_property (GladeWidgetAdaptor *adaptor,
956 957 958
                                          GObject            *object,
                                          const gchar        *property_name,
                                          GValue             *value)
959
{
960
  g_object_get_property (object, property_name, value);
961 962
}

963
static void
964
glade_widget_adaptor_object_action_activate (GladeWidgetAdaptor *adaptor,
965 966
                                             GObject            *object,
                                             const gchar        *action_id)
967
{
968
  g_message ("No action_activate() support in adaptor %s for action '%s'",
969
             adaptor->priv->name, action_id);
970
}
971

972
static void
973
glade_widget_adaptor_object_child_action_activate (GladeWidgetAdaptor *adaptor,
974 975 976
                                                   GObject            *container,
                                                   GObject            *object,
                                                   const gchar        *action_id)
977
{
978
  g_message ("No child_action_activate() support in adaptor %s for action '%s'",
979
             adaptor->priv->name, action_id);
980 981
}

982
static void
983
glade_widget_adaptor_object_read_widget (GladeWidgetAdaptor *adaptor,
984 985
                                         GladeWidget        *widget,
                                         GladeXmlNode       *node)
986 987 988 989 990 991 992 993 994 995 996 997 998 999 1000 1001 1002 1003 1004 1005 1006 1007 1008 1009
{
  GladeXmlNode *iter_node;
  GladeSignal *signal;
  GladeProperty *property;
  gchar *name, *prop_name;
  GList *read_properties = NULL, *l;

  /* Read in the properties */
  for (iter_node = glade_xml_node_get_children (node);
       iter_node; iter_node = glade_xml_node_next (iter_node))
    {
      if (!glade_xml_node_verify_silent (iter_node, GLADE_XML_TAG_PROPERTY))
        continue;

      /* Get prop name from node and lookup property ... */
      if (!(name = glade_xml_get_property_string_required
            (iter_node, GLADE_XML_TAG_NAME, NULL)))
        continue;

      prop_name = glade_util_read_prop_name (name);

      /* Some properties may be special child type of custom, just leave them for the adaptor */
      if ((property = glade_widget_get_property (widget, prop_name)) != NULL)
        {
1010
          glade_property_read (property, glade_widget_get_project (widget), iter_node);
1011 1012 1013 1014 1015 1016 1017 1018
          read_properties = g_list_prepend (read_properties, property);
        }

      g_free (prop_name);
      g_free (name);
    }

  /* Sync the remaining values not read in from the Glade file.. */
1019
  for (l = glade_widget_get_properties (widget); l; l = l->next)
1020 1021 1022 1023 1024 1025 1026 1027 1028 1029 1030 1031 1032 1033 1034
    {
      property = l->data;

      if (!g_list_find (read_properties, property))
        glade_property_sync (property);
    }
  g_list_free (read_properties);

  /* Read in the signals */
  for (iter_node = glade_xml_node_get_children (node);
       iter_node; iter_node = glade_xml_node_next (iter_node))
    {
      if (!glade_xml_node_verify_silent (iter_node, GLADE_XML_TAG_SIGNAL))
        continue;

1035
      if (!(signal = glade_signal_read (iter_node, adaptor)))
1036 1037
        continue;

1038 1039
      /* The widget doesnt use the signal handler directly but rather
       * creates it's own copy */
1040
      glade_widget_add_signal_handler (widget, signal);
1041
      g_object_unref (signal);
1042 1043 1044 1045 1046 1047 1048 1049 1050
    }

  /* Read in children */
  for (iter_node = glade_xml_node_get_children (node);
       iter_node; iter_node = glade_xml_node_next (iter_node))
    {
      if (glade_xml_node_verify_silent (iter_node, GLADE_XML_TAG_CHILD))
        glade_widget_read_child (widget, iter_node);

1051
      if (glade_project_load_cancelled (glade_widget_get_project (widget)))
1052 1053
        return;
    }
1054 1055 1056
}

static void
1057
glade_widget_adaptor_object_write_widget (GladeWidgetAdaptor *adaptor,
1058 1059 1060
                                          GladeWidget        *widget,
                                          GladeXmlContext    *context,
                                          GladeXmlNode       *node)
1061
{
1062
  GList *props;
1063

1064
  /* Write the properties */
1065
  for (props = glade_widget_get_properties (widget); props; props = props->next)
1066
    {
1067 1068
      GladeProperty    *property = props->data;
      GladePropertyDef *def = glade_property_get_def (property);
1069

1070
      if (glade_property_def_save (def) && 
1071
          glade_property_get_enabled (property))
1072 1073
        glade_property_write (GLADE_PROPERTY (props->data), context, node);
    }
1074 1075
}

1076 1077
static void
glade_widget_adaptor_object_write_widget_after (GladeWidgetAdaptor *adaptor,
1078 1079 1080
                                                GladeWidget        *widget,
                                                GladeXmlContext    *context,
                                                GladeXmlNode       *node)
1081 1082 1083 1084
{

}

1085
static void
1086
glade_widget_adaptor_object_read_child (GladeWidgetAdaptor *adaptor,
1087 1088
                                        GladeWidget        *widget,
                                        GladeXmlNode       *node)
1089 1090 1091 1092 1093 1094 1095 1096 1097 1098 1099 1100 1101 1102 1103 1104 1105
{
  GladeXmlNode *widget_node, *packing_node, *iter_node;
  GladeWidget *child_widget;
  gchar *internal_name;
  gchar *name, *prop_name;
  GladeProperty *property;

  if (!glade_xml_node_verify (node, GLADE_XML_TAG_CHILD))
    return;

  internal_name =
      glade_xml_get_property_string (node, GLADE_XML_TAG_INTERNAL_CHILD);

  if ((widget_node =
       glade_xml_search_child (node, GLADE_XML_TAG_WIDGET)) != NULL)
    {
      child_widget =
1106 1107
        glade_widget_read (glade_widget_get_project (widget),
                           widget, widget_node, internal_name);
1108 1109 1110 1111 1112 1113

      if (child_widget)
        {
          if (!internal_name)
            {
              glade_widget_set_child_type_from_node
1114
                (widget, glade_widget_get_object (child_widget), node);
1115 1116 1117 1118 1119 1120 1121 1122 1123 1124 1125 1126 1127 1128 1129 1130 1131 1132 1133 1134 1135 1136 1137 1138 1139 1140 1141
              glade_widget_add_child (widget, child_widget, FALSE);
            }

          if ((packing_node =
               glade_xml_search_child (node, GLADE_XML_TAG_PACKING)) != NULL)
            {

              /* Read in the properties */
              for (iter_node = glade_xml_node_get_children (packing_node);
                   iter_node; iter_node = glade_xml_node_next (iter_node))
                {
                  if (!glade_xml_node_verify_silent
                      (iter_node, GLADE_XML_TAG_PROPERTY))
                    continue;

                  /* Get prop name from node and lookup property ... */
                  if (!(name = glade_xml_get_property_string_required
                        (iter_node, GLADE_XML_TAG_NAME, NULL)))
                    continue;

                  prop_name = glade_util_read_prop_name (name);

                  /* Some properties may be special child type of custom, 
                   * just leave them for the adaptor */
                  if ((property =
                       glade_widget_get_pack_property (child_widget,
                                                       prop_name)) != NULL)
1142
                    glade_property_read (property, 
1143
                                         glade_widget_get_project (child_widget),
1144 1145 1146 1147 1148 1149 1150 1151 1152 1153 1154 1155 1156
                                         iter_node);

                  g_free (prop_name);
                  g_free (name);
                }
            }
        }

    }
  else
    {
      GObject *palaceholder = G_OBJECT (glade_placeholder_new ());
      glade_widget_set_child_type_from_node (widget, palaceholder, node);
1157
      glade_widget_adaptor_add (adaptor, glade_widget_get_object (widget), palaceholder);
1158 1159
    }
  g_free (internal_name);
1160 1161 1162
}

static void
1163
glade_widget_adaptor_object_write_child (GladeWidgetAdaptor *adaptor,
1164 1165 1166
                                         GladeWidget        *widget,
                                         GladeXmlContext    *context,
                                         GladeXmlNode       *node)
1167 1168 1169 1170 1171 1172 1173 1174
{
  GladeXmlNode *child_node, *packing_node;
  GList *props;

  child_node = glade_xml_node_new (context, GLADE_XML_TAG_CHILD);
  glade_xml_node_append_child (node, child_node);

  /* Set internal child */
1175
  if (glade_widget_get_internal (widget))
1176 1177
    glade_xml_node_set_property_string (child_node,
                                        GLADE_XML_TAG_INTERNAL_CHILD,
1178
                                        glade_widget_get_internal (widget));
1179 1180 1181 1182 1183 1184 1185 1186

  /* Write out the widget */
  glade_widget_write (widget, context, child_node);

  /* Write out packing properties and special-child-type */
  packing_node = glade_xml_node_new (context, GLADE_XML_TAG_PACKING);
  glade_xml_node_append_child (child_node, packing_node);

1187
  for (props = glade_widget_get_packing_properties (widget); props; props = props->next)
1188
    {
1189 1190
      GladeProperty    *property = props->data;
      GladePropertyDef *def = glade_property_get_def (property);
1191

1192
      if (glade_property_def_save (def) && 
1193
          glade_property_get_enabled (property))
1194 1195 1196 1197
        glade_property_write (GLADE_PROPERTY (props->data),
                              context, packing_node);
    }

1198 1199
  glade_widget_write_special_child_prop (glade_widget_get_parent (widget),
                                         glade_widget_get_object (widget), 
1200
                                         context, child_node);
1201 1202 1203 1204 1205 1206 1207 1208 1209 1210 1211 1212 1213

  /* Default packing properties and such are not saved,
   * so lets check afterwords if there was anything saved
   * and then just remove the node.
   */
  if (!glade_xml_node_get_children (packing_node))
    {
      glade_xml_node_remove (packing_node);
      glade_xml_node_delete (packing_node);
    }
}

static GType
1214
glade_widget_adaptor_get_eprop_type (GParamSpec *pspec)
1215 1216 1217 1218 1219 1220 1221 1222 1223
{
  GType type = 0;

  if (G_IS_PARAM_SPEC_ENUM (pspec))
    type = GLADE_TYPE_EPROP_ENUM;
  else if (G_IS_PARAM_SPEC_FLAGS (pspec))
    type = GLADE_TYPE_EPROP_FLAGS;
  else if (G_IS_PARAM_SPEC_VALUE_ARRAY (pspec))
    {
1224 1225
      /* Require deprecated code */
      G_GNUC_BEGIN_IGNORE_DEPRECATIONS;
1226 1227
      if (pspec->value_type == G_TYPE_VALUE_ARRAY)
        type = GLADE_TYPE_EPROP_TEXT;
1228
      G_GNUC_BEGIN_IGNORE_DEPRECATIONS;
1229 1230 1231
    }
  else if (G_IS_PARAM_SPEC_BOXED (pspec))
    {
1232
      if (pspec->value_type == GDK_TYPE_COLOR ||
1233
          pspec->value_type == GDK_TYPE_RGBA)
1234 1235 1236 1237
        type = GLADE_TYPE_EPROP_COLOR;
      else if (pspec->value_type == G_TYPE_STRV)
        type = GLADE_TYPE_EPROP_TEXT;
    }
1238 1239
  else if (G_IS_PARAM_SPEC_STRING (pspec) ||
           G_IS_PARAM_SPEC_VARIANT (pspec))
1240 1241 1242 1243 1244 1245 1246 1247 1248 1249 1250 1251 1252 1253 1254
    type = GLADE_TYPE_EPROP_TEXT;
  else if (G_IS_PARAM_SPEC_BOOLEAN (pspec))
    type = GLADE_TYPE_EPROP_BOOL;
  else if (G_IS_PARAM_SPEC_FLOAT (pspec) ||
           G_IS_PARAM_SPEC_DOUBLE (pspec) ||
           G_IS_PARAM_SPEC_INT (pspec) ||
           G_IS_PARAM_SPEC_UINT (pspec) ||
           G_IS_PARAM_SPEC_LONG (pspec) ||
           G_IS_PARAM_SPEC_ULONG (pspec) ||
           G_IS_PARAM_SPEC_INT64 (pspec) || G_IS_PARAM_SPEC_UINT64 (pspec))
    type = GLADE_TYPE_EPROP_NUMERIC;
  else if (G_IS_PARAM_SPEC_UNICHAR (pspec))
    type = GLADE_TYPE_EPROP_UNICHAR;
  else if (G_IS_PARAM_SPEC_OBJECT (pspec))
    {
1255 1256
      if (pspec->value_type == GDK_TYPE_PIXBUF ||
          pspec->value_type == G_TYPE_FILE)
1257 1258 1259 1260 1261 1262 1263 1264
        type = GLADE_TYPE_EPROP_TEXT;
      else
        type = GLADE_TYPE_EPROP_OBJECT;
    }
  else if (GLADE_IS_PARAM_SPEC_OBJECTS (pspec))
    type = GLADE_TYPE_EPROP_OBJECTS;

  return type;
1265 1266 1267
}

static GladeEditorProperty *
1268
glade_widget_adaptor_object_create_eprop (GladeWidgetAdaptor *adaptor,
1269
                                          GladePropertyDef   *def,
1270
                                          gboolean            use_command)
1271
{
1272
  GladeEditorProperty *eprop;
1273 1274 1275 </