/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */ /* * 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 */ #include /** * SECTION:glade-widget-adaptor * @Short_Description: Adaptor base class to add runtime support for each widget class. * * TODO: Add long description. */ #include "glade.h" #include "glade-widget-adaptor.h" #include "glade-xml-utils.h" #include "glade-property-class.h" #include "glade-signal.h" #include "glade-marshallers.h" #include "glade-accumulators.h" /* For g_file_exists */ #include #include #include #include #include #include #define DEFAULT_ICON_NAME "widget-gtk-frame" #define GLADE_WIDGET_ADAPTOR_GET_PRIVATE(o) \ (G_TYPE_INSTANCE_GET_PRIVATE ((o), GLADE_TYPE_WIDGET_ADAPTOR, GladeWidgetAdaptorPrivate)) struct _GladeWidgetAdaptorPrivate { gchar *catalog; /* The name of the widget catalog this class * was declared by. */ gchar *book; /* DevHelp search namespace for this widget class */ GdkCursor *cursor; /* a cursor for inserting widgets */ gchar *special_child_type; /* Special case code for children that * are special children (like notebook tab * widgets for example). */ }; struct _GladeChildPacking { gchar *parent_name; GList *packing_defaults; }; enum { PROP_0, PROP_NAME, PROP_TYPE, PROP_TITLE, PROP_GENERIC_NAME, PROP_ICON_NAME, PROP_CATALOG, PROP_BOOK, PROP_SPECIAL_TYPE, PROP_CURSOR }; typedef struct _GladeChildPacking GladeChildPacking; static GObjectClass *parent_class = NULL; static GHashTable *adaptor_hash = NULL; /******************************************************************************* Helper functions *******************************************************************************/ static GladeWidgetAdaptor * gwa_get_parent_adaptor (GladeWidgetAdaptor *adaptor) { GladeWidgetAdaptor *parent_adaptor = NULL; GType iter_type; 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; } return NULL; } /* This function assignes "weight" to each property in its natural order staring from 1. If parent is 0 weight will be set for every GladePropertyClass in the list. This function will not override weight if it is already set (weight >= 0.0) */ static void gwa_properties_set_weight (GList **properties, GType parent) { gint normal = 0, common = 0, packing = 0; GList *l; for (l = *properties; l && l->data; l = g_list_next (l)) { GladePropertyClass *klass = l->data; GPCType type = klass->type; if (klass->visible && (parent) ? parent == klass->pspec->owner_type : TRUE && (type == GPC_NORMAL || type == GPC_ACCEL_PROPERTY)) { /* Use a different counter for each tab (common, packing and normal) */ if (klass->common) common++; else if (klass->packing) packing++; else normal++; /* Skip if it is already set */ if (klass->weight >= 0.0) continue; /* Special-casing weight of properties for seperate tabs */ if (klass->common) klass->weight = common; else if (klass->packing) klass->weight = packing; else klass->weight = normal; } } } static void gwa_create_cursor (GladeWidgetAdaptor *adaptor) { GdkPixbuf *tmp_pixbuf, *widget_pixbuf; const GdkPixbuf *add_pixbuf; GdkDisplay *display; GError *error = NULL; /* only certain widget classes need to have cursors */ if (G_TYPE_IS_INSTANTIATABLE (adaptor->type) == FALSE || G_TYPE_IS_ABSTRACT (adaptor->type) != FALSE || adaptor->generic_name == NULL) return; /* 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; display = gdk_display_get_default (); /* 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); if (gtk_icon_theme_has_icon (gtk_icon_theme_get_default (), adaptor->icon_name)) { widget_pixbuf = gtk_icon_theme_load_icon (gtk_icon_theme_get_default (), adaptor->icon_name, 22, 0, &error); if (error) { g_warning ("Could not load image data for named icon '%s': %s", adaptor->icon_name, error->message); g_error_free (error); return; } } else { return; } /* composite pixbufs */ gdk_pixbuf_composite (widget_pixbuf, tmp_pixbuf, 8, 8, 22, 22, 8, 8, 1, 1, GDK_INTERP_NEAREST, 255); gdk_pixbuf_composite (add_pixbuf, tmp_pixbuf, 0, 0, 12, 12, 0, 0, 1, 1, GDK_INTERP_NEAREST, 255); adaptor->priv->cursor = gdk_cursor_new_from_pixbuf (display, tmp_pixbuf, 6, 6); g_object_unref (tmp_pixbuf); g_object_unref (widget_pixbuf); } static gboolean gwa_gtype_equal (gconstpointer v1, gconstpointer v2) { return *((const GType*) v1) == *((const GType*) v2); } static guint gwa_gtype_hash (gconstpointer v) { return *(const GType*) v; } static gboolean glade_widget_adaptor_hash_find (gpointer key, gpointer value, gpointer user_data) { GladeWidgetAdaptor *adaptor = value; GType *type = user_data; if (g_type_is_a (adaptor->type, *type)) { *type = adaptor->type; return TRUE; } return FALSE; } static void glade_abort_if_derived_adaptors_exist (GType type) { 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)); } } /******************************************************************************* Base Object Implementation detail *******************************************************************************/ static gint gwa_signal_comp (gconstpointer a, gconstpointer b) { const GladeSignalClass *signal_a = a, *signal_b = b; return strcmp (signal_b->query.signal_name, signal_a->query.signal_name); } static void gwa_add_signals (GList **signals, GType type) { guint count, *sig_ids, num_signals; GladeSignalClass *cur; GList *list = NULL; if (G_TYPE_IS_INSTANTIATABLE (type) || G_TYPE_IS_INTERFACE (type)) { sig_ids = g_signal_list_ids (type, &num_signals); for (count = 0; count < num_signals; count++) { cur = g_new0 (GladeSignalClass, 1); g_signal_query (sig_ids[count], &(cur->query)); /* Since glib gave us this signal id... it should * exist no matter what. */ g_assert (cur->query.signal_id != 0); cur->name = (cur->query.signal_name); cur->type = (gchar *) g_type_name (type); list = g_list_prepend (list, cur); } g_free (sig_ids); list = g_list_sort (list, gwa_signal_comp); *signals = g_list_concat (list, *signals); } } static GList * gwa_list_signals (GladeWidgetAdaptor *adaptor) { GList *signals = NULL; GType type, parent, *i, *p; g_return_val_if_fail (adaptor->type != 0, NULL); for (type = adaptor->type; g_type_is_a (type, G_TYPE_OBJECT); type = parent) { parent = g_type_parent (type); /* Add class signals */ gwa_add_signals (&signals, type); /* Add class interfaces signals */ for (i = p = g_type_interfaces (type, NULL); *i; i++) if (!glade_util_class_implements_interface (parent, *i)) gwa_add_signals (&signals, *i); g_free (p); } return g_list_reverse (signals); } static GList * gwa_clone_parent_properties (GladeWidgetAdaptor *adaptor, gboolean is_packing) { GladeWidgetAdaptor *parent_adaptor; GList *properties = NULL, *list, *proplist; if ((parent_adaptor = gwa_get_parent_adaptor (adaptor)) != NULL) { proplist = is_packing ? parent_adaptor->packing_props : parent_adaptor->properties; for (list = proplist; list; list = list->next) { GladePropertyClass *pclass = glade_property_class_clone (list->data); pclass->handle = adaptor; properties = g_list_prepend (properties, pclass); } } return g_list_reverse (properties); } static void gwa_setup_introspected_props_from_pspecs (GladeWidgetAdaptor *adaptor, GParamSpec **specs, gint n_specs, gboolean is_packing) { GladeWidgetAdaptor *parent_adaptor = gwa_get_parent_adaptor (adaptor); GladePropertyClass *property_class; GType class_type; gint i; GList *list = NULL; for (i = 0; i < n_specs; i++) { gboolean found; /* Only create properties that dont exist on the adaptor yet */ for (found = FALSE, class_type = adaptor->type; ((!parent_adaptor && class_type != 0) || ( parent_adaptor && class_type != parent_adaptor->type)); class_type = g_type_parent (class_type)) if (specs[i]->owner_type == class_type || (G_TYPE_IS_INTERFACE (specs[i]->owner_type) && glade_util_class_implements_interface (class_type, specs[i]->owner_type))) { found = TRUE; break; } if (found && (property_class = glade_property_class_new_from_spec (adaptor, specs[i])) != NULL) list = g_list_prepend (list, property_class); } if (is_packing) adaptor->packing_props = g_list_concat (adaptor->packing_props, g_list_reverse (list)); else adaptor->properties = g_list_concat (adaptor->properties, g_list_reverse (list)); } /* XXX Atk relations and accel props disregarded - they should * be implemented from the gtk+ catalog instead I think. */ static void gwa_setup_properties (GladeWidgetAdaptor *adaptor, GObjectClass *object_class, gboolean is_packing) { GParamSpec **specs = NULL; guint n_specs = 0; GList *l; /* only GtkContainer child propeties can be introspected */ if (is_packing && !g_type_is_a (adaptor->type, GTK_TYPE_CONTAINER)) return; /* First clone the parents properties */ if (is_packing) adaptor->packing_props = gwa_clone_parent_properties (adaptor, is_packing); else adaptor->properties = gwa_clone_parent_properties (adaptor, is_packing); /* 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 * because GladePropertyClass doesnt have a valid parent GType * 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). */ for (l = adaptor->packing_props; l; l = l->next) { GladePropertyClass *property_class = l->data; property_class->packing = TRUE; } } } static GList * gwa_inherit_child_packing (GladeWidgetAdaptor *adaptor) { GladeWidgetAdaptor *parent_adaptor; GList *child_packings = NULL, *packing_list, *default_list; if ((parent_adaptor = gwa_get_parent_adaptor (adaptor)) != NULL) { for (packing_list = parent_adaptor->child_packings; packing_list; packing_list = packing_list->next) { GladeChildPacking *packing = packing_list->data; GladeChildPacking *packing_dup = g_new0 (GladeChildPacking, 1); packing_dup->parent_name = g_strdup (packing->parent_name); 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); def_dup->id = g_strdup (def->id); def_dup->value = g_strdup (def->value); packing_dup->packing_defaults = g_list_prepend (packing_dup->packing_defaults, def_dup); } child_packings = g_list_prepend (child_packings, packing_dup); } } return child_packings; } static GObject * glade_widget_adaptor_constructor (GType type, guint n_construct_properties, GObjectConstructParam *construct_properties) { GladeWidgetAdaptor *adaptor, *parent_adaptor; GObject *ret_obj; GObjectClass *object_class; glade_abort_if_derived_adaptors_exist (type); ret_obj = G_OBJECT_CLASS (parent_class)->constructor (type, n_construct_properties, construct_properties); adaptor = GLADE_WIDGET_ADAPTOR (ret_obj); parent_adaptor = gwa_get_parent_adaptor (adaptor); if (adaptor->type == G_TYPE_NONE) g_warning ("Adaptor created without a type"); if (adaptor->name == NULL) g_warning ("Adaptor created without a name"); /* Build decorations */ if (!adaptor->icon_name) { adaptor->icon_name = g_strdup ("gtk-missing-image"); } gwa_create_cursor (adaptor); /* Let it leek */ if ((object_class = g_type_class_ref (adaptor->type))) { /* Build signals & properties */ adaptor->signals = gwa_list_signals (adaptor); gwa_setup_properties (adaptor, object_class, FALSE); gwa_setup_properties (adaptor, object_class, TRUE); } else g_critical ("Failed to get class for type %s\n", g_type_name (adaptor->type)); /* Inherit packing defaults here */ adaptor->child_packings = gwa_inherit_child_packing (adaptor); /* 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; /* Copy parent actions */ if (parent_adaptor) { GList *l; if (parent_adaptor->actions) { for (l = parent_adaptor->actions; l; l = g_list_next (l)) { GWActionClass *child = glade_widget_action_class_clone (l->data); adaptor->actions = g_list_prepend (adaptor->actions, child); } adaptor->actions = g_list_reverse (adaptor->actions); } if (parent_adaptor->packing_actions) { for (l = parent_adaptor->packing_actions; l; l = g_list_next (l)) { GWActionClass *child = glade_widget_action_class_clone (l->data); adaptor->packing_actions = g_list_prepend (adaptor->packing_actions, child); } adaptor->packing_actions = g_list_reverse (adaptor->packing_actions); } } return ret_obj; } static void gwa_packing_default_free (GladePackingDefault *def) { g_free (def->id); g_free (def->value); } static void gwa_child_packing_free (GladeChildPacking *packing) { g_free (packing->parent_name); g_list_foreach (packing->packing_defaults, (GFunc) gwa_packing_default_free, NULL); g_list_free (packing->packing_defaults); } static void glade_widget_adaptor_finalize (GObject *object) { GladeWidgetAdaptor *adaptor = GLADE_WIDGET_ADAPTOR (object); /* Free properties and signals */ g_list_foreach (adaptor->properties, (GFunc) glade_property_class_free, NULL); g_list_free (adaptor->properties); g_list_foreach (adaptor->packing_props, (GFunc) glade_property_class_free, NULL); g_list_free (adaptor->packing_props); g_list_foreach (adaptor->signals, (GFunc) glade_signal_free, NULL); g_list_free (adaptor->signals); /* Free child packings */ g_list_foreach (adaptor->child_packings, (GFunc) gwa_child_packing_free, NULL); g_list_free (adaptor->child_packings); if (adaptor->priv->book) g_free (adaptor->priv->book); if (adaptor->priv->catalog) g_free (adaptor->priv->catalog); if (adaptor->priv->special_child_type) g_free (adaptor->priv->special_child_type); if (adaptor->priv->cursor != NULL) gdk_cursor_unref (adaptor->priv->cursor); if (adaptor->name) g_free (adaptor->name); if (adaptor->generic_name) g_free (adaptor->generic_name); if (adaptor->title) g_free (adaptor->title); if (adaptor->icon_name) g_free (adaptor->icon_name); if (adaptor->actions) { g_list_foreach (adaptor->actions, (GFunc) glade_widget_action_class_free, NULL); g_list_free (adaptor->actions); } if (adaptor->packing_actions) { g_list_foreach (adaptor->packing_actions, (GFunc) glade_widget_action_class_free, NULL); g_list_free (adaptor->packing_actions); } g_free (adaptor->priv); G_OBJECT_CLASS (parent_class)->finalize (object); } static void glade_widget_adaptor_real_set_property (GObject *object, guint prop_id, const GValue *value, GParamSpec *pspec) { GladeWidgetAdaptor *adaptor; adaptor = GLADE_WIDGET_ADAPTOR (object); switch (prop_id) { case PROP_NAME: /* assume once (construct-only) */ adaptor->name = g_value_dup_string (value); break; case PROP_ICON_NAME: /* assume once (construct-only) */ adaptor->icon_name = g_value_dup_string (value); break; case PROP_TYPE: adaptor->type = g_value_get_gtype (value); break; case PROP_TITLE: if (adaptor->title) g_free (adaptor->title); adaptor->title = g_value_dup_string (value); break; case PROP_GENERIC_NAME: if (adaptor->generic_name) g_free (adaptor->generic_name); adaptor->generic_name = g_value_dup_string (value); break; case PROP_CATALOG: /* assume once (construct-only) */ adaptor->priv->catalog = g_value_dup_string (value); break; case PROP_BOOK: /* assume once (construct-only) */ adaptor->priv->book = g_value_dup_string (value); break; case PROP_SPECIAL_TYPE: /* assume once (construct-only) */ adaptor->priv->special_child_type = g_value_dup_string (value); break; default: G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); break; } } static void glade_widget_adaptor_real_get_property (GObject *object, guint prop_id, GValue *value, GParamSpec *pspec) { GladeWidgetAdaptor *adaptor; adaptor = GLADE_WIDGET_ADAPTOR (object); switch (prop_id) { case PROP_NAME: g_value_set_string (value, adaptor->name); break; case PROP_TYPE: g_value_set_gtype (value, adaptor->type); break; case PROP_TITLE: g_value_set_string (value, adaptor->title); break; case PROP_GENERIC_NAME: g_value_set_string (value, adaptor->generic_name); break; case PROP_ICON_NAME: g_value_set_string (value, adaptor->icon_name); 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; default: G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); break; } } /******************************************************************************* GladeWidgetAdaptor base class implementations *******************************************************************************/ static void glade_widget_adaptor_object_set_property (GladeWidgetAdaptor *adaptor, GObject *object, const gchar *property_name, const GValue *value) { g_object_set_property (object, property_name, value); } static void glade_widget_adaptor_object_get_property (GladeWidgetAdaptor *adaptor, GObject *object, const gchar *property_name, GValue *value) { g_object_get_property (object, property_name, value); } static void glade_widget_adaptor_object_action_activate (GladeWidgetAdaptor *adaptor, GObject *object, const gchar *action_id) { g_message ("No action_activate() support in adaptor %s for action '%s'", adaptor->name, action_id); } static void glade_widget_adaptor_object_child_action_activate (GladeWidgetAdaptor *adaptor, GObject *container, GObject *object, const gchar *action_id) { g_message ("No child_action_activate() support in adaptor %s for action '%s'", adaptor->name, action_id); } /******************************************************************************* GladeWidgetAdaptor type registration and class initializer *******************************************************************************/ static void glade_widget_adaptor_init (GladeWidgetAdaptor *adaptor) { adaptor->priv = GLADE_WIDGET_ADAPTOR_GET_PRIVATE (adaptor); } static void glade_widget_adaptor_class_init (GladeWidgetAdaptorClass *adaptor_class) { GObjectClass *object_class; g_return_if_fail (adaptor_class != NULL); parent_class = g_type_class_peek_parent (adaptor_class); object_class = G_OBJECT_CLASS (adaptor_class); /* GObjectClass */ object_class->constructor = glade_widget_adaptor_constructor; object_class->finalize = glade_widget_adaptor_finalize; object_class->set_property = glade_widget_adaptor_real_set_property; object_class->get_property = glade_widget_adaptor_real_get_property; /* Class methods */ adaptor_class->deep_post_create = NULL; adaptor_class->post_create = NULL; adaptor_class->get_internal_child = NULL; adaptor_class->verify_property = NULL; adaptor_class->set_property = glade_widget_adaptor_object_set_property; adaptor_class->get_property = glade_widget_adaptor_object_get_property; adaptor_class->add = NULL; adaptor_class->remove = NULL; adaptor_class->replace_child = NULL; adaptor_class->get_children = NULL; adaptor_class->child_set_property = NULL; adaptor_class->child_get_property = NULL; adaptor_class->action_activate = glade_widget_adaptor_object_action_activate; adaptor_class->child_action_activate= glade_widget_adaptor_object_child_action_activate; /* Base defaults here */ adaptor_class->fixed = FALSE; adaptor_class->toplevel = FALSE; adaptor_class->use_placeholders = FALSE; adaptor_class->default_width = -1; adaptor_class->default_height = -1; /* Properties */ g_object_class_install_property (object_class, PROP_NAME, g_param_spec_string ("name", _("Name"), _("Name of the class"), NULL, G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY)); g_object_class_install_property (object_class, PROP_TYPE, g_param_spec_gtype ("type", _("Type"), _("GType of the class"), G_TYPE_NONE, G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY)); g_object_class_install_property (object_class, PROP_TITLE, g_param_spec_string ("title", _("Title"), _("Translated title for the class used in the glade UI"), NULL, G_PARAM_READWRITE)); g_object_class_install_property (object_class, PROP_GENERIC_NAME, g_param_spec_string ("generic-name", _("Generic Name"), _("Used to generate names of new widgets"), NULL, G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY)); g_object_class_install_property (object_class, PROP_ICON_NAME, g_param_spec_string ("icon-name", _("Icon Name"), _("The icon name"), DEFAULT_ICON_NAME, G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY)); g_object_class_install_property (object_class, PROP_CATALOG, g_param_spec_string ("catalog", _("Catalog"), _("The name of the widget catalog this class was declared by"), NULL, G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY)); g_object_class_install_property (object_class, PROP_BOOK, g_param_spec_string ("book", _("Book"), _("DevHelp search namespace for this widget class"), NULL, G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY)); g_object_class_install_property (object_class, PROP_SPECIAL_TYPE, g_param_spec_string ("special-child-type", _("Special Child Type"), _("Holds the name of the packing property to depict " "special children for this container class"), NULL, G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY)); g_object_class_install_property (object_class, PROP_CURSOR, g_param_spec_pointer ("cursor", _("Cursor"), _("A cursor for inserting widgets in the UI"), G_PARAM_READABLE)); g_type_class_add_private (adaptor_class, sizeof (GladeWidgetAdaptorPrivate)); } GType glade_widget_adaptor_get_type (void) { static GType adaptor_type = 0; if (!adaptor_type) { static const GTypeInfo adaptor_info = { sizeof (GladeWidgetAdaptorClass), (GBaseInitFunc) NULL, (GBaseFinalizeFunc) NULL, (GClassInitFunc) glade_widget_adaptor_class_init, (GClassFinalizeFunc) NULL, NULL, /* class_data */ sizeof (GladeWidgetAdaptor), 0, /* n_preallocs */ (GInstanceInitFunc) glade_widget_adaptor_init, }; adaptor_type = g_type_register_static (G_TYPE_OBJECT, "GladeGObjectAdaptor", &adaptor_info, 0); } return adaptor_type; } GType glade_create_reason_get_type (void) { static GType etype = 0; if (etype == 0) { static const GEnumValue values[] = { { GLADE_CREATE_USER, "GLADE_CREATE_USER", "create-user" }, { GLADE_CREATE_COPY, "GLADE_CREATE_COPY", "create-copy" }, { GLADE_CREATE_LOAD, "GLADE_CREATE_LOAD", "create-load" }, { GLADE_CREATE_REBUILD, "GLADE_CREATE_REBUILD", "create-rebuild" }, { 0, NULL, NULL } }; etype = g_enum_register_static ("GladeCreateReason", values); } return etype; } /******************************************************************************* Synthetic Object Derivation *******************************************************************************/ typedef struct { GladeXmlNode *node; GModule *module; } GWADerivedClassData; static void gwa_derived_init (GladeWidgetAdaptor *adaptor, gpointer g_class) { } static void gwa_extend_with_node_load_sym (GladeWidgetAdaptorClass *klass, GladeXmlNode *node, GModule *module) { GObjectClass *object_class = G_OBJECT_CLASS (klass); gpointer symbol; /* * We use a temporary variable to avoid a bogus gcc warning. * the thing it that g_module_symbol() should use a function pointer * instead of a gpointer! */ if (glade_xml_load_sym_from_node (node, module, GLADE_TAG_CONSTRUCTOR_FUNCTION, &symbol)) object_class->constructor = symbol; if (glade_xml_load_sym_from_node (node, module, GLADE_TAG_DEEP_POST_CREATE_FUNCTION, &symbol)) klass->deep_post_create = symbol; if (glade_xml_load_sym_from_node (node, module, GLADE_TAG_POST_CREATE_FUNCTION, &symbol)) klass->post_create = symbol; if (glade_xml_load_sym_from_node (node, module, GLADE_TAG_GET_INTERNAL_CHILD_FUNCTION, &symbol)) klass->get_internal_child = symbol; if (glade_xml_load_sym_from_node (node, module, GLADE_TAG_SET_FUNCTION, &symbol)) klass->set_property = symbol; if (glade_xml_load_sym_from_node (node, module, GLADE_TAG_GET_FUNCTION, &symbol)) klass->get_property = symbol; if (glade_xml_load_sym_from_node (node, module, GLADE_TAG_VERIFY_FUNCTION, &symbol)) klass->verify_property = symbol; if (glade_xml_load_sym_from_node (node, module, GLADE_TAG_ADD_CHILD_FUNCTION, &symbol)) klass->add = symbol; if (glade_xml_load_sym_from_node (node, module, GLADE_TAG_REMOVE_CHILD_FUNCTION, &symbol)) klass->remove = symbol; if (glade_xml_load_sym_from_node (node, module, GLADE_TAG_GET_CHILDREN_FUNCTION, &symbol)) klass->get_children = symbol; if (glade_xml_load_sym_from_node (node, module, GLADE_TAG_CHILD_SET_PROP_FUNCTION, &symbol)) klass->child_set_property = symbol; if (glade_xml_load_sym_from_node (node, module, GLADE_TAG_CHILD_GET_PROP_FUNCTION, &symbol)) klass->child_get_property = symbol; if (glade_xml_load_sym_from_node (node, module, GLADE_TAG_CHILD_VERIFY_FUNCTION, &symbol)) klass->child_verify_property = symbol; if (glade_xml_load_sym_from_node (node, module, GLADE_TAG_REPLACE_CHILD_FUNCTION, &symbol)) klass->replace_child = symbol; if (glade_xml_load_sym_from_node (node, module, GLADE_TAG_ACTION_ACTIVATE_FUNCTION, &symbol)) klass->action_activate = symbol; if (glade_xml_load_sym_from_node (node, module, GLADE_TAG_CHILD_ACTION_ACTIVATE_FUNCTION, &symbol)) klass->child_action_activate = symbol; } static void gwa_derived_class_init (GladeWidgetAdaptorClass *adaptor_class, GWADerivedClassData *data) { GladeXmlNode *node = data->node; GModule *module = data->module; /* Load catalog symbols from module */ if (module) gwa_extend_with_node_load_sym (adaptor_class, node, module); adaptor_class->fixed = glade_xml_get_property_boolean (node, GLADE_TAG_FIXED, adaptor_class->fixed); /* Check if this class is toplevel */ adaptor_class->toplevel = glade_xml_get_property_boolean (node, GLADE_TAG_TOPLEVEL, adaptor_class->toplevel); /* Check if this class uses placeholders for child widgets */ adaptor_class->use_placeholders = glade_xml_get_property_boolean (node, GLADE_TAG_USE_PLACEHOLDERS, adaptor_class->use_placeholders); /* Check default size when used as a toplevel in the GladeDesignView */ adaptor_class->default_width = glade_xml_get_property_int (node, GLADE_TAG_DEFAULT_WIDTH, adaptor_class->default_width); adaptor_class->default_height = glade_xml_get_property_int (node, GLADE_TAG_DEFAULT_HEIGHT, adaptor_class->default_height); } static GType gwa_derive_adaptor_for_type (GType object_type, GWADerivedClassData *data) { GladeWidgetAdaptor *adaptor; GType iter_type, derived_type; GType parent_type = GLADE_TYPE_WIDGET_ADAPTOR; gchar *type_name; GTypeInfo adaptor_info = { sizeof (GladeWidgetAdaptorClass), (GBaseInitFunc) NULL, (GBaseFinalizeFunc) NULL, (GClassInitFunc) gwa_derived_class_init, (GClassFinalizeFunc) NULL, data, /* class_data */ sizeof (GladeWidgetAdaptor), 0, /* n_preallocs */ (GInstanceInitFunc) gwa_derived_init, }; for (iter_type = g_type_parent (object_type); iter_type > 0; iter_type = g_type_parent (iter_type)) { if ((adaptor = glade_widget_adaptor_get_by_type (iter_type)) != NULL) { parent_type = G_TYPE_FROM_INSTANCE (adaptor); break; } } /* Note that we must pass ownership of the type_name string * to the type system */ type_name = g_strdup_printf ("Glade%sAdaptor", g_type_name (object_type)); derived_type = g_type_register_static (parent_type, type_name, &adaptor_info, 0); return derived_type; } /******************************************************************************* API *******************************************************************************/ /** * glade_widget_adaptor_register: * @adaptor: A #GladeWidgetAdaptor * * Registers @adaptor into the Glade core (every supported * object type must have a registered adaptor). */ void glade_widget_adaptor_register (GladeWidgetAdaptor *adaptor) { g_return_if_fail (GLADE_IS_WIDGET_ADAPTOR (adaptor)); if (glade_widget_adaptor_get_by_name (adaptor->name)) { g_warning ("Adaptor class for '%s' already registered", adaptor->name); return; } if (!adaptor_hash) adaptor_hash = g_hash_table_new_full (gwa_gtype_hash, gwa_gtype_equal, g_free, g_object_unref); g_hash_table_insert (adaptor_hash, g_memdup (&adaptor->type, sizeof (GType)), adaptor); } static GladePackingDefault * gwa_default_from_child_packing (GladeChildPacking *packing, const gchar *id) { GList *list; for (list = packing->packing_defaults; list; list = list->next) { GladePackingDefault *def = list->data; if (id && !strcmp (id, def->id)) return def; } return NULL; } static GladeChildPacking * glade_widget_adaptor_get_child_packing (GladeWidgetAdaptor *child_adaptor, const gchar *parent_name) { GList *l; for (l = child_adaptor->child_packings; l; l = l->next) { GladeChildPacking *packing; packing = (GladeChildPacking *) l->data; if (!strcmp (packing->parent_name, parent_name)) return packing; } return NULL; } static void gwa_set_packing_defaults_from_node (GladeWidgetAdaptor *adaptor, GladeXmlNode *node) { GladeXmlNode *child; for (child = glade_xml_node_get_children (node); child; child = glade_xml_node_next (child)) { gchar *name; GladeXmlNode *prop_node; GladeChildPacking *packing; if (!glade_xml_node_verify (child, GLADE_TAG_PARENT_CLASS)) continue; if ((name = glade_xml_get_property_string_required (child, GLADE_TAG_NAME, adaptor->name)) == NULL) continue; /* If a GladeChildPacking exists for this parent, use it - * otherwise prepend a new one */ if ((packing = glade_widget_adaptor_get_child_packing (adaptor, name)) == NULL) { packing = g_new0 (GladeChildPacking, 1); packing->parent_name = name; adaptor->child_packings = g_list_prepend (adaptor->child_packings, packing); } for (prop_node = glade_xml_node_get_children (child); prop_node; prop_node = glade_xml_node_next (prop_node)) { GladePackingDefault *def; gchar *id; gchar *value; if ((id = glade_xml_get_property_string_required (prop_node, GLADE_TAG_ID, adaptor->name)) == NULL) continue; if ((value = glade_xml_get_property_string_required (prop_node, GLADE_TAG_DEFAULT, adaptor->name)) == NULL) { g_free (id); continue; } if ((def = gwa_default_from_child_packing (packing, id)) == NULL) { def = g_new0 (GladePackingDefault, 1); def->id = id; def->value = value; packing->packing_defaults = g_list_prepend (packing->packing_defaults, def); } else { g_free (id); g_free (def->value); def->value = value; } adaptor->child_packings = g_list_prepend (adaptor->child_packings, packing); } } } static void gwa_update_properties_from_node (GladeWidgetAdaptor *adaptor, GladeXmlNode *node, GModule *module, GList **properties, const gchar *domain, gboolean is_packing) { GladeXmlNode *child; for (child = glade_xml_node_get_children (node); child; child = glade_xml_node_next (child)) { gchar *id; GList *list; GladePropertyClass *property_class; gboolean updated; if (!glade_xml_node_verify (child, GLADE_TAG_PROPERTY)) continue; id = glade_xml_get_property_string_required (child, GLADE_TAG_ID, adaptor->name); if (!id) continue; /* property names from catalogs also need to have the '-' form */ glade_util_replace (id, '_', '-'); /* find the property in our list, if not found append a new property */ for (list = *properties; list && list->data; list = list->next) { property_class = GLADE_PROPERTY_CLASS (list->data); if (property_class->id != NULL && g_ascii_strcasecmp (id, property_class->id) == 0) break; } if (list) { property_class = GLADE_PROPERTY_CLASS (list->data); } else { property_class = glade_property_class_new (adaptor); property_class->id = g_strdup (id); /* When creating new virtual packing properties, * make sure we mark them as such here. */ if (is_packing) property_class->packing = TRUE; *properties = g_list_append (*properties, property_class); list = g_list_last (*properties); } if ((updated = glade_property_class_update_from_node (child, module, adaptor->type, &property_class, domain)) == FALSE) { g_warning ("failed to update %s property of %s from xml", id, adaptor->name); g_free (id); continue; } /* the property has Disabled=TRUE ... */ if (!property_class) *properties = g_list_delete_link (*properties, list); g_free (id); } } static void gwa_action_update_from_node (GladeWidgetAdaptor *adaptor, gboolean is_packing, GladeXmlNode *node, const gchar *domain, gchar *group_path) { GladeXmlNode *child; gchar *id, *label, *stock, *action_path; gboolean group, important; for (child = glade_xml_node_get_children (node); child; child = glade_xml_node_next (child)) { if ((group = glade_xml_node_verify_silent (child, GLADE_TAG_ACTION)) == FALSE) continue; id = glade_xml_get_property_string_required (child, GLADE_TAG_ID, adaptor->name); if (id == NULL) continue; if (group_path) action_path = g_strdup_printf ("%s/%s", group_path, id); else action_path = id; label = glade_xml_get_property_string (child, GLADE_TAG_NAME); stock = glade_xml_get_property_string (child, GLADE_TAG_STOCK); important = glade_xml_get_property_boolean (child, GLADE_TAG_IMPORTANT, FALSE); if (label) { gchar *translated = dgettext (domain, label); if (label != translated) { g_free (label); label = g_strdup (translated); } } if (is_packing) glade_widget_adaptor_pack_action_add (adaptor, action_path, label, stock, important); else glade_widget_adaptor_action_add (adaptor, action_path, label, stock, important); if (group) gwa_action_update_from_node (adaptor, is_packing, child, domain, action_path); g_free (id); g_free (label); g_free (stock); if (group_path) g_free (action_path); } } static gboolean gwa_extend_with_node (GladeWidgetAdaptor *adaptor, GladeXmlNode *node, GModule *module, const gchar *domain) { GladeXmlNode *child; gchar *child_type; /* Override the special-child-type here */ if ((child_type = glade_xml_get_value_string (node, GLADE_TAG_SPECIAL_CHILD_TYPE)) != NULL) adaptor->priv->special_child_type = (g_free (adaptor->priv->special_child_type), child_type); /* if we found a tag on the xml file, we add the properties * that we read from the xml file to the class. */ if ((child = glade_xml_search_child (node, GLADE_TAG_PROPERTIES)) != NULL) gwa_update_properties_from_node (adaptor, child, module, &adaptor->properties, domain, FALSE); if ((child = glade_xml_search_child (node, GLADE_TAG_PACKING_PROPERTIES)) != NULL) gwa_update_properties_from_node (adaptor, child, module, &adaptor->packing_props, domain, TRUE); if ((child = glade_xml_search_child (node, GLADE_TAG_PACKING_DEFAULTS)) != NULL) gwa_set_packing_defaults_from_node (adaptor, child); /* Update actions from child node */ if ((child = glade_xml_search_child (node, GLADE_TAG_ACTIONS)) != NULL) gwa_action_update_from_node (adaptor, FALSE, child, domain, NULL); /* Update packing actions from child node */ if ((child = glade_xml_search_child (node, GLADE_TAG_PACKING_ACTIONS)) != NULL) gwa_action_update_from_node (adaptor, TRUE, child, domain, NULL); return TRUE; } /** * create_icon_name_for_adaptor: * @adaptor_name: The name of the widget class * @adaptor_type: The #GType of the adaptor class * @icon_name: The icon name as set from the catalog * @icon_prefix: The icon prefix as set from the catalog * @generic_name: The generic name for the widget class * * Creates a suitable icon name for an adaptor, based on several parameters. * * Returns: An icon name, or NULL if the adaptor does not require one. */ static gchar * create_icon_name_for_adaptor (const gchar *adaptor_name, GType adaptor_type, const gchar *icon_name, const gchar *icon_prefix, const gchar *generic_name) { gchar *name; /* only certain widget adaptors need to have icons */ if (G_TYPE_IS_INSTANTIATABLE (adaptor_type) == FALSE || G_TYPE_IS_ABSTRACT (adaptor_type) != FALSE || generic_name == NULL) { return NULL; } /* if no icon name has been specified, we then fallback to a default icon name */ if (!icon_name) name = g_strdup_printf ("widget-%s-%s", icon_prefix, generic_name); else name = g_strdup (icon_name); /* check if icon is available */ if (!gtk_icon_theme_has_icon (gtk_icon_theme_get_default (), name)) { g_warning ("No icon named '%s' was found for widget class '%s'.", name, adaptor_name); g_free (name); name = g_strdup (DEFAULT_ICON_NAME); } return name; } static void gwa_displayable_values_check (GladeWidgetAdaptor *adaptor, gboolean packing) { GList *l, *p = (packing) ? adaptor->packing_props : adaptor->properties; for (l = p; l; l = g_list_next (l)) { GladePropertyClass *klass = l->data; if (adaptor->type == klass->pspec->owner_type && (G_IS_PARAM_SPEC_ENUM (klass->pspec) || G_IS_PARAM_SPEC_FLAGS (klass->pspec)) && !klass->displayable_values && klass->visible && klass->pspec->value_type != GLADE_TYPE_STOCK && klass->pspec->value_type != GLADE_TYPE_STOCK_IMAGE) { /* We do not need displayable values if the property is not visible */ g_message ("No displayable values for %sproperty %s::%s", (packing) ? "child " : "", adaptor->name, klass->id); } } } static GType generate_type (const char *name, const char *parent_name) { GType parent_type; GTypeQuery query; GTypeInfo *type_info; g_return_val_if_fail (name != NULL, 0); g_return_val_if_fail (parent_name != NULL, 0); parent_type = glade_util_get_type_from_name (parent_name, FALSE); g_return_val_if_fail (parent_type != 0, 0); g_type_query (parent_type, &query); g_return_val_if_fail (query.type != 0, 0); type_info = g_new0 (GTypeInfo, 1); type_info->class_size = query.class_size; type_info->instance_size = query.instance_size; return g_type_register_static (parent_type, name, type_info, 0); } /** * glade_widget_adaptor_from_catalog: * @class_node: A #GladeXmlNode * @catname: the name of the owning catalog * @icon_prefix: * @module: the plugin GModule. * @domain: the domain to translate strings from this plugin from * @book: the devhelp search domain for the owning catalog. * * Dynamicly creates a subclass of #GladeWidgetAdaptor and subclasses * the closest parent adaptor (parent class adapters must be creates/registerd * prior to child classes, otherwise inheritance wont work) and parses in * the relevent catalog info. */ GladeWidgetAdaptor * glade_widget_adaptor_from_catalog (GladeXmlNode *class_node, const gchar *catname, const gchar *icon_prefix, GModule *module, const gchar *domain, const gchar *book) { GladeWidgetAdaptor *adaptor = NULL; gchar *name, *generic_name, *icon_name, *adaptor_icon_name, *adaptor_name, *func_name; gchar *title, *translated_title, *parent_name; GType object_type, adaptor_type, parent_type; GWADerivedClassData data; if (!glade_xml_node_verify (class_node, GLADE_TAG_GLADE_WIDGET_CLASS)) { g_warning ("Widget class node is not '%s'", GLADE_TAG_GLADE_WIDGET_CLASS); return NULL; } if ((name = glade_xml_get_property_string_required (class_node, GLADE_TAG_NAME, NULL)) == NULL) return NULL; /* Either get the instance type by: * * - Autosubclassing a specified parent type (a fake widget class) * - parsing the _get_type() function directly from the catalog * - deriving foo_bar_get_type() from the name FooBar and loading that. */ if ((parent_name = glade_xml_get_property_string (class_node, GLADE_TAG_PARENT)) != NULL) { if (!glade_widget_adaptor_get_by_name (parent_name)) { g_warning ("Trying to define class '%s' for parent class '%s', but parent class '%s' " "is not registered", name, parent_name, parent_name); g_free (name); g_free (parent_name); return NULL; } object_type = generate_type (name, parent_name); g_free (parent_name); } else if ((func_name = glade_xml_get_property_string (class_node, GLADE_TAG_GET_TYPE_FUNCTION)) != NULL) object_type = glade_util_get_type_from_name (func_name, TRUE); else object_type = glade_util_get_type_from_name (name, FALSE); if (object_type == 0) { g_warning ("Failed to load the GType for '%s'", name); g_free (name); return NULL; } if (glade_widget_adaptor_get_by_type (object_type)) { g_warning ("Adaptor class for '%s' already defined", g_type_name (object_type)); g_free (name); return NULL; } if ((adaptor_name = glade_xml_get_property_string (class_node, GLADE_TAG_ADAPTOR))) adaptor_type = g_type_from_name (adaptor_name); else { /* * We use this struct pointer to pass data to * gwa_derived_class_init() because we must override constructor() * from the catalog before calling g_object_new() :P */ data.node = class_node; data.module = module; adaptor_type = gwa_derive_adaptor_for_type (object_type, &data); } if (adaptor_type == 0) { g_warning ("Failed to get %s's adaptor %s", name, (adaptor_name) ? adaptor_name : ""); g_free (adaptor_name); g_free (name); return NULL; } generic_name = glade_xml_get_property_string (class_node, GLADE_TAG_GENERIC_NAME); icon_name = glade_xml_get_property_string (class_node, GLADE_TAG_ICON_NAME); /* get a suitable icon name for adaptor */ adaptor_icon_name = create_icon_name_for_adaptor (name, adaptor_type, icon_name, icon_prefix, generic_name); adaptor = g_object_new (adaptor_type, "type", object_type, "name", name, "generic-name", generic_name, "icon-name", adaptor_icon_name, NULL); g_free (generic_name); g_free (icon_name); g_free (adaptor_icon_name); title = glade_xml_get_property_string_required (class_node, GLADE_TAG_TITLE, "This value is needed to " "display object class names " "in the UI"); if (title == NULL) { g_warning ("Class '%s' declared without a '%s' attribute", name, GLADE_TAG_TITLE); adaptor->title = g_strdup (name); } else { /* translate */ translated_title = dgettext (domain, title); if (translated_title != title) { /* gettext owns translated_title */ adaptor->title = g_strdup (translated_title); g_free (title); } else { adaptor->title = title; } } if (G_TYPE_IS_INSTANTIATABLE (adaptor->type) && G_TYPE_IS_ABSTRACT (adaptor->type) == FALSE && adaptor->generic_name == NULL) { g_warning ("Instantiatable class '%s' built without a '%s'", name, GLADE_TAG_GENERIC_NAME); } /* Perform a stoopid fallback just incase */ if (adaptor->generic_name == NULL) adaptor->generic_name = g_strdup ("widget"); /* Dont mention gtk+ as a required lib in the generated glade file */ if (strcmp (catname, "gtk+")) adaptor->priv->catalog = g_strdup (catname); if (book) adaptor->priv->book = g_strdup (book); gwa_extend_with_node (adaptor, class_node, module, domain); /* Set default weight on properties */ for (parent_type = adaptor->type; parent_type != 0; parent_type = g_type_parent (parent_type)) { gwa_properties_set_weight (&adaptor->properties, parent_type); gwa_properties_set_weight (&adaptor->packing_props, parent_type); } gwa_displayable_values_check (adaptor, FALSE); gwa_displayable_values_check (adaptor, TRUE); glade_widget_adaptor_register (adaptor); return adaptor; } /** * glade_widget_adaptor_create_internal: * @parent: The parent #GladeWidget, or %NULL for children * outside of the hierarchy. * @internal_object: the #GObject * @internal_name: a string identifier for this internal widget. * @anarchist: Whether or not this widget is a widget outside * of the parent's hierarchy (like a popup window) * @reason: The #GladeCreateReason for which this internal widget * was created (usually just pass the reason from the post_create * function; note also this is used only by the plugin code so * pass something usefull here). * * A convenienve function to create a #GladeWidget of the prescribed type * for internal widgets. * * Returns: a freshly created #GladeWidget wrapper object for the * @internal_object of name @internal_name */ GladeWidget * glade_widget_adaptor_create_internal (GladeWidget *parent, GObject *internal_object, const gchar *internal_name, const gchar *parent_name, gboolean anarchist, GladeCreateReason reason) { GladeWidgetAdaptor *adaptor; GladeProject *project; g_return_val_if_fail (GLADE_IS_WIDGET (parent), NULL); project = glade_widget_get_project (parent); if ((adaptor = glade_widget_adaptor_get_by_name (G_OBJECT_TYPE_NAME (internal_object))) == NULL) { g_critical ("Unable to find widget class for type %s", G_OBJECT_TYPE_NAME (internal_object)); return NULL; } return glade_widget_adaptor_create_widget (adaptor, FALSE, "anarchist", anarchist, "parent", parent, "project", project, "internal", internal_name, "internal-name", parent_name, "reason", reason, "object", internal_object, NULL); } /** * glade_widget_adaptor_create_widget: * @adaptor: a #GladeWidgetAdaptor * @query: whether to display query dialogs if * applicable to the class * @...: a %NULL terminated list of string/value pairs of #GladeWidget * properties * * * This factory function returns a new #GladeWidget of the correct type/class * with the properties defined in @... and queries the user if nescisary. * * The resulting object will have all default properties applied to it * including the overrides specified in the catalog, unless the catalog * has specified 'ignore' for that property. * * Note that the widget class must be fed twice; once as the * leading arg... and also as the property for the #GladeWidget * * this macro returns the newly created #GladeWidget */ GladeWidget * glade_widget_adaptor_create_widget_real (gboolean query, const gchar *first_property, ...) { GladeWidgetAdaptor *adaptor; GType gwidget_type; GladeWidget *gwidget; va_list vl, vl_copy; g_return_val_if_fail (strcmp (first_property, "adaptor") == 0, NULL); va_start (vl, first_property); va_copy (vl_copy, vl); adaptor = va_arg (vl, GladeWidgetAdaptor *); va_end (vl); if (GLADE_IS_WIDGET_ADAPTOR (adaptor) == FALSE) { g_critical ("No adaptor found in glade_widget_adaptor_create_widget_real args"); va_end (vl_copy); return NULL; } if (GWA_IS_FIXED (adaptor)) gwidget_type = GLADE_TYPE_FIXED; else gwidget_type = GLADE_TYPE_WIDGET; gwidget = (GladeWidget *)g_object_new_valist (gwidget_type, first_property, vl_copy); va_end (vl_copy); if (query && glade_widget_adaptor_query (adaptor)) { GladeEditor *editor = glade_app_get_editor (); /* If user pressed cancel on query popup. */ if (!glade_editor_query_dialog (editor, gwidget)) { g_object_unref (G_OBJECT (gwidget)); return NULL; } } return gwidget; } typedef struct { const gchar *name; GladeWidgetAdaptor *adaptor; } GladeAdaptorSearchPair; static void search_adaptor_by_name (GType *type, GladeWidgetAdaptor *adaptor, GladeAdaptorSearchPair *pair) { if (!strcmp (adaptor->name, pair->name)) pair->adaptor = adaptor; } /** * glade_widget_adaptor_get_by_name: * @name: name of the widget class (for instance: GtkButton) * * Returns: an existing #GladeWidgetAdaptor with the name equaling @name, * or %NULL if such a class doesn't exist **/ GladeWidgetAdaptor * glade_widget_adaptor_get_by_name (const gchar *name) { GladeAdaptorSearchPair pair = { name, NULL }; if (adaptor_hash != NULL) { g_hash_table_foreach (adaptor_hash, (GHFunc)search_adaptor_by_name, &pair); } return pair.adaptor; } /** * glade_widget_adaptor_get_by_type: * @type: the #GType of an object class * * Returns: an existing #GladeWidgetAdaptor with the type equaling @type, * or %NULL if such a class doesn't exist **/ GladeWidgetAdaptor * glade_widget_adaptor_get_by_type (GType type) { if (adaptor_hash != NULL) return g_hash_table_lookup (adaptor_hash, &type); else return NULL; } /** * glade_widget_adaptor_get_property_class: * @adaptor: a #GladeWidgetAdaptor * @name: a string * * Retrieves the #GladePropertyClass for @name in @adaptor * * Returns: A #GladePropertyClass object */ GladePropertyClass * glade_widget_adaptor_get_property_class (GladeWidgetAdaptor *adaptor, const gchar *name) { GList *list; GladePropertyClass *pclass; for (list = adaptor->properties; list && list->data; list = list->next) { pclass = list->data; if (strcmp (pclass->id, name) == 0) return pclass; } return NULL; } /** * glade_widget_adaptor_get_pack_property_class: * @adaptor: a #GladeWidgetAdaptor * @name: a string * * Retrieves the #GladePropertyClass for @name in * @adaptor's child properties * * Returns: A #GladePropertyClass object */ GladePropertyClass * glade_widget_adaptor_get_pack_property_class (GladeWidgetAdaptor *adaptor, const gchar *name) { GList *list; GladePropertyClass *pclass; for (list = adaptor->packing_props; list && list->data; list = list->next) { pclass = list->data; if (strcmp (pclass->id, name) == 0) return pclass; } return NULL; } /** * glade_widget_class_default_params: * @adaptor: a #GladeWidgetAdaptor * @construct: whether to return construct params or not construct params * @n_params: return location if any defaults are specified for this class. * * Returns: A list of params for use in g_object_newv () */ GParameter * glade_widget_adaptor_default_params (GladeWidgetAdaptor *adaptor, gboolean construct, guint *n_params) { GArray *params; GObjectClass *oclass; GParamSpec **pspec; GladePropertyClass *pclass; guint n_props, i; g_return_val_if_fail (GLADE_IS_WIDGET_ADAPTOR (adaptor), NULL); g_return_val_if_fail (n_params != NULL, NULL); /* As a slight optimization, we never unref the class */ oclass = g_type_class_ref (adaptor->type); pspec = g_object_class_list_properties (oclass, &n_props); params = g_array_new (FALSE, FALSE, sizeof (GParameter)); for (i = 0; i < n_props; i++) { GParameter parameter = { 0, }; pclass = glade_widget_adaptor_get_property_class (adaptor, pspec[i]->name); /* Ignore properties based on some criteria */ if (pclass == NULL || /* Unaccounted for in the builder */ pclass->virt || /* should not be set before GladeWidget wrapper exists */ pclass->ignore) /* Catalog explicitly ignores the object */ continue; if (construct && (pspec[i]->flags & (G_PARAM_CONSTRUCT|G_PARAM_CONSTRUCT_ONLY)) == 0) continue; else if (!construct && (pspec[i]->flags & (G_PARAM_CONSTRUCT|G_PARAM_CONSTRUCT_ONLY)) != 0) continue; if (g_value_type_compatible (G_VALUE_TYPE (pclass->def), pspec[i]->value_type) == FALSE) { g_critical ("Type mismatch on %s property of %s", parameter.name, adaptor->name); continue; } if (g_param_values_cmp (pspec[i], pclass->def, pclass->orig_def) == 0) continue; parameter.name = pspec[i]->name; /* These are not copied/freed */ g_value_init (¶meter.value, pspec[i]->value_type); g_value_copy (pclass->def, ¶meter.value); g_array_append_val (params, parameter); } g_free (pspec); *n_params = params->len; return (GParameter *)g_array_free (params, FALSE); } /** * glade_widget_adaptor_post_create: * @adaptor: A #GladeWidgetAdaptor * @object: The #GObject * @reason: The #GladeCreateReason that @object was created for * * An adaptor function to be called after the object is created */ void glade_widget_adaptor_post_create (GladeWidgetAdaptor *adaptor, GObject *object, GladeCreateReason reason) { g_return_if_fail (GLADE_IS_WIDGET_ADAPTOR (adaptor)); g_return_if_fail (G_IS_OBJECT (object)); g_return_if_fail (g_type_is_a (G_OBJECT_TYPE (object), adaptor->type)); /* Run post_create in 2 stages, one that chains up and all class adaptors * in the hierarchy get a peek, another that is used to setup placeholders * and things that differ from the child/parent implementations */ if (GLADE_WIDGET_ADAPTOR_GET_CLASS (adaptor)->deep_post_create) GLADE_WIDGET_ADAPTOR_GET_CLASS (adaptor)->deep_post_create (adaptor, object, reason); if (GLADE_WIDGET_ADAPTOR_GET_CLASS (adaptor)->post_create) GLADE_WIDGET_ADAPTOR_GET_CLASS (adaptor)->post_create (adaptor, object, reason); /* XXX Dont complain here if no implementation is found */ } /** * glade_widget_adaptor_get_internal_child: * @adaptor: A #GladeWidgetAdaptor * @object: The #GObject * @internal_name: The string identifier of the internal object * * Retrieves the internal object @internal_name from @object * * Returns: The internal #GObject */ GObject * glade_widget_adaptor_get_internal_child (GladeWidgetAdaptor *adaptor, GObject *object, const gchar *internal_name) { g_return_val_if_fail (GLADE_IS_WIDGET_ADAPTOR (adaptor), NULL); g_return_val_if_fail (G_IS_OBJECT (object), NULL); g_return_val_if_fail (internal_name != NULL, NULL); g_return_val_if_fail (g_type_is_a (G_OBJECT_TYPE (object), adaptor->type), NULL); if (GLADE_WIDGET_ADAPTOR_GET_CLASS (adaptor)->get_internal_child) return GLADE_WIDGET_ADAPTOR_GET_CLASS (adaptor)->get_internal_child (adaptor, object, internal_name); else g_critical ("No get_internal_child() support in adaptor %s", adaptor->name); return NULL; } /** * glade_widget_adaptor_set_property: * @adaptor: A #GladeWidgetAdaptor * @object: The #GObject * @property_name: The property identifier * @value: The #GValue * * This delagate function is used to apply the property value on * the runtime object. * */ void glade_widget_adaptor_set_property (GladeWidgetAdaptor *adaptor, GObject *object, const gchar *property_name, const GValue *value) { g_return_if_fail (GLADE_IS_WIDGET_ADAPTOR (adaptor)); g_return_if_fail (G_IS_OBJECT (object)); g_return_if_fail (property_name != NULL && value != NULL); g_return_if_fail (g_type_is_a (G_OBJECT_TYPE (object), adaptor->type)); /* The base class provides an implementation */ GLADE_WIDGET_ADAPTOR_GET_CLASS (adaptor)->set_property (adaptor, object, property_name, value); } /** * glade_widget_adaptor_get_property: * @adaptor: A #GladeWidgetAdaptor * @object: The #GObject * @property_name: The property identifier * @value: The #GValue * * Gets @value of @property_name on @object. * */ void glade_widget_adaptor_get_property (GladeWidgetAdaptor *adaptor, GObject *object, const gchar *property_name, GValue *value) { g_return_if_fail (GLADE_IS_WIDGET_ADAPTOR (adaptor)); g_return_if_fail (G_IS_OBJECT (object)); g_return_if_fail (property_name != NULL && value != NULL); g_return_if_fail (g_type_is_a (G_OBJECT_TYPE (object), adaptor->type)); /* The base class provides an implementation */ GLADE_WIDGET_ADAPTOR_GET_CLASS (adaptor)->get_property (adaptor, object, property_name, value); } /** * glade_widget_adaptor_verify_property: * @adaptor: A #GladeWidgetAdaptor * @object: The #GObject * @property_name: The property identifier * @value: The #GValue * * This delagate function is always called whenever setting any * properties with the exception of load time, and copy/paste time * (basicly the two places where we recreate a hierarchy that we * already know "works") its basicly an optional backend provided * boundry checker for properties. * * Returns: whether or not its OK to set @value on @object, this function * will silently return TRUE if the class did not provide a verify function. */ gboolean glade_widget_adaptor_verify_property (GladeWidgetAdaptor *adaptor, GObject *object, const gchar *property_name, const GValue *value) { g_return_val_if_fail (GLADE_IS_WIDGET_ADAPTOR (adaptor), FALSE); g_return_val_if_fail (G_IS_OBJECT (object), FALSE); g_return_val_if_fail (property_name != NULL && value != NULL, FALSE); g_return_val_if_fail (g_type_is_a (G_OBJECT_TYPE (object), adaptor->type), FALSE); if (GLADE_WIDGET_ADAPTOR_GET_CLASS (adaptor)->verify_property) return GLADE_WIDGET_ADAPTOR_GET_CLASS (adaptor)->verify_property (adaptor, object, property_name, value); return TRUE; } /** * glade_widget_adaptor_add: * @adaptor: A #GladeWidgetAdaptor * @container: The #GObject container * @child: The #GObject child * * Adds @child to @container. */ void glade_widget_adaptor_add (GladeWidgetAdaptor *adaptor, GObject *container, GObject *child) { g_return_if_fail (GLADE_IS_WIDGET_ADAPTOR (adaptor)); g_return_if_fail (G_IS_OBJECT (container)); g_return_if_fail (G_IS_OBJECT (child)); g_return_if_fail (g_type_is_a (G_OBJECT_TYPE (container), adaptor->type)); if (GLADE_WIDGET_ADAPTOR_GET_CLASS (adaptor)->add) GLADE_WIDGET_ADAPTOR_GET_CLASS (adaptor)->add (adaptor, container, child); else g_critical ("No add() support in adaptor %s", adaptor->name); } /** * glade_widget_adaptor_remove: * @adaptor: A #GladeWidgetAdaptor * @container: The #GObject container * @child: The #GObject child * * Removes @child from @container. */ void glade_widget_adaptor_remove (GladeWidgetAdaptor *adaptor, GObject *container, GObject *child) { g_return_if_fail (GLADE_IS_WIDGET_ADAPTOR (adaptor)); g_return_if_fail (G_IS_OBJECT (container)); g_return_if_fail (G_IS_OBJECT (child)); g_return_if_fail (g_type_is_a (G_OBJECT_TYPE (container), adaptor->type)); if (GLADE_WIDGET_ADAPTOR_GET_CLASS (adaptor)->remove) GLADE_WIDGET_ADAPTOR_GET_CLASS (adaptor)->remove (adaptor, container, child); else g_critical ("No remove() support in adaptor %s", adaptor->name); } /** * glade_widget_adaptor_get_children: * @adaptor: A #GladeWidgetAdaptor * @container: The #GObject container * * Lists the children of @container. * * Returns: A #GList of children */ GList * glade_widget_adaptor_get_children (GladeWidgetAdaptor *adaptor, GObject *container) { g_return_val_if_fail (GLADE_IS_WIDGET_ADAPTOR (adaptor), NULL); g_return_val_if_fail (G_IS_OBJECT (container), NULL); g_return_val_if_fail (g_type_is_a (G_OBJECT_TYPE (container), adaptor->type), NULL); if (GLADE_WIDGET_ADAPTOR_GET_CLASS (adaptor)->get_children) return GLADE_WIDGET_ADAPTOR_GET_CLASS (adaptor)->get_children (adaptor, container); /* Dont complain here if no implementation is found */ return NULL; } /** * glade_widget_adaptor_has_child: * @adaptor: A #GladeWidgetAdaptor * @container: The #GObject container * @child: The #GObject child * * Returns whether @child is infact inside @container. */ gboolean glade_widget_adaptor_has_child (GladeWidgetAdaptor *adaptor, GObject *container, GObject *child) { GList *list, *children = NULL; gboolean found = FALSE; children = glade_widget_adaptor_get_children (adaptor, container); for (list = children; list && list->data; list = list->next) { if (list->data == child) { found = TRUE; break; } } g_list_free (children); return found; } /** * glade_widget_adaptor_child_set_property: * @adaptor: A #GladeWidgetAdaptor * @container: The #GObject container * @child: The #GObject child * @property_name: The id of the property * @value: The @GValue * * Sets @child's packing property identified by @property_name to @value. */ void glade_widget_adaptor_child_set_property (GladeWidgetAdaptor *adaptor, GObject *container, GObject *child, const gchar *property_name, const GValue *value) { g_return_if_fail (GLADE_IS_WIDGET_ADAPTOR (adaptor)); g_return_if_fail (G_IS_OBJECT (container)); g_return_if_fail (G_IS_OBJECT (child)); g_return_if_fail (property_name != NULL && value != NULL); g_return_if_fail (g_type_is_a (G_OBJECT_TYPE (container), adaptor->type)); if (GLADE_WIDGET_ADAPTOR_GET_CLASS (adaptor)->child_set_property) GLADE_WIDGET_ADAPTOR_GET_CLASS (adaptor)->child_set_property (adaptor, container, child, property_name, value); else g_critical ("No child_set_property() support in adaptor %s", adaptor->name); } /** * glade_widget_adaptor_child_get_property: * @adaptor: A #GladeWidgetAdaptor * @container: The #GObject container * @child: The #GObject child * @property_name: The id of the property * @value: The @GValue * * Gets @child's packing property identified by @property_name. */ void glade_widget_adaptor_child_get_property (GladeWidgetAdaptor *adaptor, GObject *container, GObject *child, const gchar *property_name, GValue *value) { g_return_if_fail (GLADE_IS_WIDGET_ADAPTOR (adaptor)); g_return_if_fail (G_IS_OBJECT (container)); g_return_if_fail (G_IS_OBJECT (child)); g_return_if_fail (property_name != NULL && value != NULL); g_return_if_fail (g_type_is_a (G_OBJECT_TYPE (container), adaptor->type)); if (GLADE_WIDGET_ADAPTOR_GET_CLASS (adaptor)->child_get_property) GLADE_WIDGET_ADAPTOR_GET_CLASS (adaptor)->child_get_property (adaptor, container, child, property_name, value); else g_critical ("No child_set_property() support in adaptor %s", adaptor->name); } /** * glade_widget_adaptor_child_verify_property: * @adaptor: A #GladeWidgetAdaptor * @container: The #GObject container * @child: The #GObject child * @property_name: The id of the property * @value: The @GValue * * This delagate function is always called whenever setting any * properties with the exception of load time, and copy/paste time * (basicly the two places where we recreate a hierarchy that we * already know "works") its basicly an optional backend provided * boundry checker for properties. * * Returns: whether or not its OK to set @value on @object, this function * will silently return TRUE if the class did not provide a verify function. */ gboolean glade_widget_adaptor_child_verify_property (GladeWidgetAdaptor *adaptor, GObject *container, GObject *child, const gchar *property_name, const GValue *value) { g_return_val_if_fail (GLADE_IS_WIDGET_ADAPTOR (adaptor), FALSE); g_return_val_if_fail (G_IS_OBJECT (container), FALSE); g_return_val_if_fail (G_IS_OBJECT (child), FALSE); g_return_val_if_fail (property_name != NULL && value != NULL, FALSE); g_return_val_if_fail (g_type_is_a (G_OBJECT_TYPE (container), adaptor->type), FALSE); if (GLADE_WIDGET_ADAPTOR_GET_CLASS (adaptor)->child_verify_property) return GLADE_WIDGET_ADAPTOR_GET_CLASS (adaptor)->child_verify_property (adaptor, container, child, property_name, value); return TRUE; } /** * glade_widget_adaptor_replace_child: * @adaptor: A #GladeWidgetAdaptor * @container: The #GObject container * @old_obj: The old #GObject child * @new_obj: The new #GObject child * * Replaces @old_obj with @new_obj in @container while positioning * @new_obj where @old_obj was and assigning it appropriate packing * property values. */ void glade_widget_adaptor_replace_child (GladeWidgetAdaptor *adaptor, GObject *container, GObject *old_obj, GObject *new_obj) { g_return_if_fail (GLADE_IS_WIDGET_ADAPTOR (adaptor)); g_return_if_fail (G_IS_OBJECT (container)); g_return_if_fail (G_IS_OBJECT (old_obj)); g_return_if_fail (G_IS_OBJECT (new_obj)); g_return_if_fail (g_type_is_a (G_OBJECT_TYPE (container), adaptor->type)); if (GLADE_WIDGET_ADAPTOR_GET_CLASS (adaptor)->replace_child) GLADE_WIDGET_ADAPTOR_GET_CLASS (adaptor)->replace_child (adaptor, container, old_obj, new_obj); else g_critical ("No replace_child() support in adaptor %s", adaptor->name); } /** * glade_widget_adaptor_query: * @adaptor: A #GladeWidgetAdaptor * * Returns: whether the user needs to be queried for * certain properties upon creation of this class. */ gboolean glade_widget_adaptor_query (GladeWidgetAdaptor *adaptor) { GladePropertyClass *pclass; GList *l; g_return_val_if_fail (GLADE_IS_WIDGET_ADAPTOR (adaptor), FALSE); for (l = adaptor->properties; l; l = l->next) { pclass = l->data; if (pclass->query) return TRUE; } return FALSE; } /** * glade_widget_adaptor_get_packing_default: * @child_adaptor: A #GladeWidgetAdaptor * @container_adaptor: The #GladeWidgetAdaptor for the parent object * @id: The string property identifier * * Gets the default value for @property_id on a widget governed by * @child_adaptor when parented in a widget governed by @parent_adaptor * * Returns: a string representing the default value for @property_id */ G_CONST_RETURN gchar * glade_widget_adaptor_get_packing_default (GladeWidgetAdaptor *child_adaptor, GladeWidgetAdaptor *container_adaptor, const gchar *id) { GladeChildPacking *packing = NULL; GList *l; g_return_val_if_fail (GLADE_IS_WIDGET_ADAPTOR (child_adaptor), NULL); g_return_val_if_fail (GLADE_IS_WIDGET_ADAPTOR (container_adaptor), NULL); if ((packing = glade_widget_adaptor_get_child_packing (child_adaptor, container_adaptor->name)) != NULL) { for (l = packing->packing_defaults; l; l = l->next) { GladePackingDefault *def = l->data; if (strcmp (def->id, id) == 0) return def->value; } } return NULL; } /** * glade_widget_adaptor_is_container: * @adaptor: A #GladeWidgetAdaptor * * Checks whether or not this adaptor has support * to interface with child objects. * * Returns whether or not @adaptor is a container */ gboolean glade_widget_adaptor_is_container (GladeWidgetAdaptor *adaptor) { g_return_val_if_fail (GLADE_IS_WIDGET_ADAPTOR (adaptor), FALSE); /* A GWA container must at least implement add/remove/get_children */ return (GLADE_WIDGET_ADAPTOR_GET_CLASS (adaptor)->add && GLADE_WIDGET_ADAPTOR_GET_CLASS (adaptor)->remove && GLADE_WIDGET_ADAPTOR_GET_CLASS (adaptor)->get_children); } static const gchar * gwa_action_path_get_id (const gchar *action_path) { const gchar *id; if ((id = g_strrstr (action_path, "/")) && id[1] != '\0') return &id[1]; else return action_path; } static GWActionClass * gwa_action_lookup (GList *actions, const gchar *action_id) { GList *l; for (l = actions; l; l = g_list_next (l)) { GWActionClass *action = l->data; if (strcmp (action->id, action_id) == 0) return action; } return NULL; } static GWActionClass * gwa_action_get_last_group (GList *actions, const gchar *action_path) { gchar **tokens = g_strsplit (action_path, "/", 0); GWActionClass *group = NULL; gint i; for (i = 0; tokens[i] && tokens[i+1]; i++) { if ((group = gwa_action_lookup (actions, tokens[i])) == NULL) { g_strfreev (tokens); return NULL; } actions = group->actions; } g_strfreev (tokens); return group; } static gboolean glade_widget_adaptor_action_add_real (GList **list, const gchar *action_path, const gchar *label, const gchar *stock, gboolean important) { GWActionClass *action, *group; const gchar *id; id = gwa_action_path_get_id (action_path); if ((group = gwa_action_get_last_group (*list, action_path))) list = &group->actions; if ((action = gwa_action_lookup (*list, id))) { /* Update parent's label/stock */ if (label && action->label) { g_free (action->label); if (strcmp (label, "") == 0) label = NULL; action->label = (label) ? g_strdup (label) : NULL; } if (stock && action->stock) { g_free (action->stock); if (strcmp (stock, "") == 0) stock = NULL; action->stock = (stock) ? g_strdup (stock) : NULL; } } else { /* New Action */ action = g_new0 (GWActionClass, 1); action->path = g_strdup (action_path); action->id = (gchar*) gwa_action_path_get_id (action->path); if (label && strcmp (label, "") == 0) label = NULL; if (stock && strcmp (stock, "") == 0) stock = NULL; action->label = (label) ? g_strdup (label) : NULL; action->stock = (stock) ? g_strdup (stock) : NULL; } action->important = important; *list = g_list_append (*list, action); return TRUE; } /** * glade_widget_adaptor_action_add: * @adaptor: A #GladeWidgetAdaptor * @action_path: The identifier of this action in the action tree * @label: A translated label to show in the UI for this action * @stock: If set, this stock item will be shown in the UI along side the label. * @important: if this action is important. * * Add an action to @adaptor. * If the action is present then it overrides label and stock * * Returns: whether or not the action was added/updated. */ gboolean glade_widget_adaptor_action_add (GladeWidgetAdaptor *adaptor, const gchar *action_path, const gchar *label, const gchar *stock, gboolean important) { g_return_val_if_fail (GLADE_IS_WIDGET_ADAPTOR (adaptor), FALSE); g_return_val_if_fail (action_path != NULL, FALSE); return glade_widget_adaptor_action_add_real (&adaptor->actions, action_path, label, stock, important); } /** * glade_widget_adaptor_pack_action_add: * @adaptor: A #GladeWidgetAdaptor * @action_path: The identifier of this action in the action tree * @label: A translated label to show in the UI for this action * @stock: If set, this stock item will be shown in the UI along side the label. * @important: if this action is important. * * Add a packing action to @adaptor. * If the action is present then it overrides label and stock * * Returns: whether or not the action was added/updated. */ gboolean glade_widget_adaptor_pack_action_add (GladeWidgetAdaptor *adaptor, const gchar *action_path, const gchar *label, const gchar *stock, gboolean important) { g_return_val_if_fail (GLADE_IS_WIDGET_ADAPTOR (adaptor), FALSE); g_return_val_if_fail (action_path != NULL, FALSE); return glade_widget_adaptor_action_add_real (&adaptor->packing_actions, action_path, label, stock, important); } static gboolean glade_widget_adaptor_action_remove_real (GList **list, const gchar *action_path) { GWActionClass *action, *group; const gchar *id; id = gwa_action_path_get_id (action_path); if ((group = gwa_action_get_last_group (*list, action_path))) list = &group->actions; if ((action = gwa_action_lookup (*list, id)) == NULL) return FALSE; *list = g_list_remove (*list, action); glade_widget_action_class_free (action); return TRUE; } /** * glade_widget_adaptor_action_remove: * @adaptor: A #GladeWidgetAdaptor * @action_path: The identifier of this action in the action tree * * Remove an @adaptor's action. * * Returns: whether or not the action was removed. */ gboolean glade_widget_adaptor_action_remove (GladeWidgetAdaptor *adaptor, const gchar *action_path) { g_return_val_if_fail (GLADE_IS_WIDGET_ADAPTOR (adaptor), FALSE); g_return_val_if_fail (action_path != NULL, FALSE); return glade_widget_adaptor_action_remove_real (&adaptor->actions, action_path); } /** * glade_widget_adaptor_pack_action_remove: * @adaptor: A #GladeWidgetAdaptor * @action_path: The identifier of this action in the action tree * * Remove an @adaptor's packing action. * * Returns: whether or not the action was removed. */ gboolean glade_widget_adaptor_pack_action_remove (GladeWidgetAdaptor *adaptor, const gchar *action_path) { g_return_val_if_fail (GLADE_IS_WIDGET_ADAPTOR (adaptor), FALSE); g_return_val_if_fail (action_path != NULL, FALSE); return glade_widget_adaptor_action_remove_real (&adaptor->packing_actions, action_path); } /** * glade_widget_adaptor_pack_actions_new: * @adaptor: A #GladeWidgetAdaptor * * Create a list of packing actions. * * Returns: a new list of GladeWidgetAction. */ GList * glade_widget_adaptor_pack_actions_new (GladeWidgetAdaptor *adaptor) { GList *l, *list = NULL; g_return_val_if_fail (GLADE_IS_WIDGET_ADAPTOR (adaptor), NULL); for (l = adaptor->packing_actions; l; l = g_list_next (l)) { GWActionClass *action = l->data; GObject *obj = g_object_new (GLADE_TYPE_WIDGET_ACTION, "class", action, NULL); list = g_list_prepend (list, GLADE_WIDGET_ACTION (obj)); } return g_list_reverse (list); } /** * glade_widget_adaptor_action_activate: * @adaptor: A #GladeWidgetAdaptor * @object: The #GObject * @action_path: The action identifier in the action tree * * An adaptor function to be called on widget actions. */ void glade_widget_adaptor_action_activate (GladeWidgetAdaptor *adaptor, GObject *object, const gchar *action_path) { g_return_if_fail (GLADE_IS_WIDGET_ADAPTOR (adaptor)); g_return_if_fail (G_IS_OBJECT (object)); g_return_if_fail (g_type_is_a (G_OBJECT_TYPE (object), adaptor->type)); GLADE_WIDGET_ADAPTOR_GET_CLASS (adaptor)->action_activate (adaptor, object, action_path); } /** * glade_widget_adaptor_child_action_activate: * @adaptor: A #GladeWidgetAdaptor * @object: The #GObject * @action_path: The action identifier in the action tree * * An adaptor function to be called on widget actions. */ void glade_widget_adaptor_child_action_activate (GladeWidgetAdaptor *adaptor, GObject *container, GObject *object, const gchar *action_path) { g_return_if_fail (GLADE_IS_WIDGET_ADAPTOR (adaptor)); g_return_if_fail (G_IS_OBJECT (container)); g_return_if_fail (G_IS_OBJECT (object)); g_return_if_fail (g_type_is_a (G_OBJECT_TYPE (container), adaptor->type)); GLADE_WIDGET_ADAPTOR_GET_CLASS (adaptor)->child_action_activate (adaptor, container, object, action_path); }