/* * 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. * * 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. * */ #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" #include "glade-displayable-values.h" #include "glade-editor-table.h" #include "glade-cursor.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 { 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 * example "button" so that we generate button1, * button2, buttonX .. */ 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 */ GList *properties; /* List of GladePropertyClass objects. * [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. */ GList *packing_props; /* List of GladePropertyClass objects that describe * 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 * managed on the GladePropertyClass proper. */ GList *signals; /* List of GladeSignalClass objects */ GList *child_packings; /* Default packing property values */ GList *actions; /* A list of GWActionClass */ GList *packing_actions; /* A list of GWActionClass for child objects */ 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; }; struct _GladePackingDefault { gchar *id; gchar *value; }; 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; typedef struct _GladePackingDefault GladePackingDefault; static GObjectClass *parent_class = NULL; static GHashTable *adaptor_hash = NULL; /******************************************************************************* Helper functions *******************************************************************************/ 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->priv->type) == FALSE || G_TYPE_IS_ABSTRACT (adaptor->priv->type) != FALSE || adaptor->priv->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->priv->icon_name)) { widget_pixbuf = gtk_icon_theme_load_icon (gtk_icon_theme_get_default (), adaptor->priv->icon_name, 22, 0, &error); if (error) { g_warning ("Could not load image data for named icon '%s': %s", adaptor->priv->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->priv->type, *type)) { *type = adaptor->priv->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 *******************************************************************************/ #define gwa_get_parent_adaptor(a) glade_widget_adaptor_get_parent_adaptor (a) static GladeWidgetAdaptor * glade_widget_adaptor_get_parent_adaptor_by_type (GType adaptor_type) { 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; } /* XXX DOCME */ GladeWidgetAdaptor * glade_widget_adaptor_get_parent_adaptor (GladeWidgetAdaptor * adaptor) { g_return_val_if_fail (GLADE_IS_WIDGET_ADAPTOR (adaptor), NULL); return glade_widget_adaptor_get_parent_adaptor_by_type (adaptor->priv->type); } static gint gwa_signal_comp (gpointer a, gpointer b) { GladeSignalClass *signal_a = a, *signal_b = b; return strcmp (glade_signal_class_get_name (signal_b), glade_signal_class_get_name (signal_a)); } static gint gwa_signal_find_comp (gpointer a, gpointer b) { GladeSignalClass *signal = a; gchar *name = b; return strcmp (name, glade_signal_class_get_name (signal)); } static void gwa_add_signals (GladeWidgetAdaptor * adaptor, GList ** signals, GType type) { guint count, *sig_ids, num_signals; GladeWidgetAdaptor *type_adaptor; GladeSignalClass *signal; GList *list = NULL; type_adaptor = glade_widget_adaptor_get_by_type (type); sig_ids = g_signal_list_ids (type, &num_signals); for (count = 0; count < num_signals; count++) { signal = glade_signal_class_new (type_adaptor ? type_adaptor : adaptor, type, sig_ids[count]); list = g_list_prepend (list, signal); } g_free (sig_ids); list = g_list_sort (list, (GCompareFunc)gwa_signal_comp); *signals = g_list_concat (list, *signals); } static GList * gwa_list_signals (GladeWidgetAdaptor * adaptor, GType real_type) { 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++) if (!g_type_is_a (parent, *i)) gwa_add_signals (adaptor, &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) { gboolean reset_version; proplist = is_packing ? parent_adaptor->priv->packing_props : parent_adaptor->priv->properties; /* Reset versioning in derived catalogs just once */ reset_version = strcmp (adaptor->priv->catalog, parent_adaptor->priv->catalog) != 0; for (list = proplist; list; list = list->next) { GladePropertyClass *pclass = glade_property_class_clone (list->data, reset_version); glade_property_class_set_adaptor (pclass, 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; 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 && !glade_widget_adaptor_get_property_class (parent_adaptor, specs[i]->name)) || (is_packing && !glade_widget_adaptor_get_pack_property_class (parent_adaptor, specs[i]->name))) { if ((property_class = glade_property_class_new_from_spec (adaptor, specs[i])) != NULL) list = g_list_prepend (list, property_class); } } if (is_packing) adaptor->priv->packing_props = g_list_concat (adaptor->priv->packing_props, g_list_reverse (list)); else adaptor->priv->properties = g_list_concat (adaptor->priv->properties, g_list_reverse (list)); } 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->priv->type, GTK_TYPE_CONTAINER)) return; /* First clone the parents properties */ if (is_packing) adaptor->priv->packing_props = gwa_clone_parent_properties (adaptor, is_packing); else adaptor->priv->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->priv->packing_props; l; l = l->next) { GladePropertyClass *property_class = l->data; glade_property_class_set_is_packing (property_class, 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->priv->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 void gwa_inherit_signals (GladeWidgetAdaptor * adaptor) { GladeWidgetAdaptor *parent_adaptor; GList *list, *node; GladeSignalClass *signal, *parent_signal; if ((parent_adaptor = gwa_get_parent_adaptor (adaptor)) != NULL) { for (list = adaptor->priv->signals; list; list = list->next) { signal = list->data; if ((node = g_list_find_custom (parent_adaptor->priv->signals, glade_signal_class_get_name (signal), (GCompareFunc) gwa_signal_find_comp)) != NULL) { parent_signal = node->data; /* Reset versioning in derived catalogs just once */ if (strcmp (adaptor->priv->catalog, parent_adaptor->priv->catalog)) glade_signal_class_set_since (signal, 0, 0); else glade_signal_class_set_since (signal, glade_signal_class_since_major (parent_signal), glade_signal_class_since_minor (parent_signal)); } } } } 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->priv->type == G_TYPE_NONE) g_warning ("Adaptor created without a type"); if (adaptor->priv->name == NULL) g_warning ("Adaptor created without a name"); /* Build decorations */ if (!adaptor->priv->icon_name) { adaptor->priv->icon_name = g_strdup ("gtk-missing-image"); } gwa_create_cursor (adaptor); /* Let it leek */ if ((object_class = g_type_class_ref (adaptor->priv->type))) { /* Build signals & properties */ adaptor->priv->signals = gwa_list_signals (adaptor, adaptor->priv->type); gwa_inherit_signals (adaptor); gwa_setup_properties (adaptor, object_class, FALSE); gwa_setup_properties (adaptor, object_class, TRUE); } /* Inherit packing defaults here */ adaptor->priv->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; /* Reset version numbering if we're in a new catalog just once */ if (parent_adaptor && strcmp (adaptor->priv->catalog, parent_adaptor->priv->catalog)) { 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; if (parent_adaptor->priv->actions) { for (l = parent_adaptor->priv->actions; l; l = g_list_next (l)) { GWActionClass *child = glade_widget_action_class_clone (l->data); adaptor->priv->actions = g_list_prepend (adaptor->priv->actions, child); } adaptor->priv->actions = g_list_reverse (adaptor->priv->actions); } if (parent_adaptor->priv->packing_actions) { for (l = parent_adaptor->priv->packing_actions; l; l = g_list_next (l)) { GWActionClass *child = glade_widget_action_class_clone (l->data); adaptor->priv->packing_actions = g_list_prepend (adaptor->priv->packing_actions, child); } adaptor->priv->packing_actions = g_list_reverse (adaptor->priv->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->priv->properties, (GFunc) glade_property_class_free, NULL); g_list_free (adaptor->priv->properties); g_list_foreach (adaptor->priv->packing_props, (GFunc) glade_property_class_free, NULL); g_list_free (adaptor->priv->packing_props); /* Be careful, this list holds GladeSignalClass* not GladeSignal, * thus g_free is enough as all members are const */ g_list_foreach (adaptor->priv->signals, (GFunc) g_free, NULL); g_list_free (adaptor->priv->signals); /* Free child packings */ g_list_foreach (adaptor->priv->child_packings, (GFunc) gwa_child_packing_free, NULL); g_list_free (adaptor->priv->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->priv->name) g_free (adaptor->priv->name); if (adaptor->priv->generic_name) g_free (adaptor->priv->generic_name); if (adaptor->priv->title) g_free (adaptor->priv->title); if (adaptor->priv->icon_name) g_free (adaptor->priv->icon_name); if (adaptor->priv->missing_icon) g_free (adaptor->priv->missing_icon); if (adaptor->priv->actions) { g_list_foreach (adaptor->priv->actions, (GFunc) glade_widget_action_class_free, NULL); g_list_free (adaptor->priv->actions); } if (adaptor->priv->packing_actions) { g_list_foreach (adaptor->priv->packing_actions, (GFunc) glade_widget_action_class_free, NULL); g_list_free (adaptor->priv->packing_actions); } 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->priv->name = g_value_dup_string (value); adaptor->priv->real_type = g_type_from_name (adaptor->priv->name); break; case PROP_ICON_NAME: /* assume once (construct-only) */ adaptor->priv->icon_name = g_value_dup_string (value); break; case PROP_TYPE: adaptor->priv->type = g_value_get_gtype (value); break; case PROP_TITLE: if (adaptor->priv->title) g_free (adaptor->priv->title); adaptor->priv->title = g_value_dup_string (value); break; case PROP_GENERIC_NAME: if (adaptor->priv->generic_name) g_free (adaptor->priv->generic_name); adaptor->priv->generic_name = g_value_dup_string (value); break; case PROP_CATALOG: /* assume once (construct-only) */ g_free (adaptor->priv->catalog); adaptor->priv->catalog = g_value_dup_string (value); break; case PROP_BOOK: /* assume once (construct-only) */ g_free (adaptor->priv->book); adaptor->priv->book = g_value_dup_string (value); break; case PROP_SPECIAL_TYPE: /* assume once (construct-only) */ g_free (adaptor->priv->special_child_type); 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->priv->name); break; case PROP_TYPE: g_value_set_gtype (value, adaptor->priv->type); break; case PROP_TITLE: g_value_set_string (value, adaptor->priv->title); break; case PROP_GENERIC_NAME: g_value_set_string (value, adaptor->priv->generic_name); break; case PROP_ICON_NAME: g_value_set_string (value, adaptor->priv->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 GladeWidget * glade_widget_adaptor_object_create_widget (GladeWidgetAdaptor * adaptor, const gchar * first_property_name, va_list var_args) { return (GladeWidget *) g_object_new_valist (GLADE_TYPE_WIDGET, first_property_name, var_args); } static GObject * glade_widget_adaptor_object_construct_object (GladeWidgetAdaptor * adaptor, guint n_parameters, GParameter * parameters) { return g_object_newv (adaptor->priv->type, n_parameters, parameters); } static gboolean glade_widget_adaptor_object_add_verify (GladeWidgetAdaptor *adaptor, GObject *parent, GObject *child, gboolean user_feedback) { if (user_feedback) glade_util_ui_message (glade_app_get_window (), GLADE_UI_INFO, NULL, _("%s does not support adding any children."), adaptor->priv->title); return FALSE; } 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->priv->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->priv->name, action_id); } static gboolean glade_widget_adaptor_object_depends (GladeWidgetAdaptor * adaptor, GladeWidget * widget, GladeWidget * another) { return FALSE; } static void glade_widget_adaptor_object_read_widget (GladeWidgetAdaptor * adaptor, GladeWidget * widget, GladeXmlNode * node) { 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) { glade_property_read (property, glade_widget_get_project (widget), iter_node); 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.. */ for (l = glade_widget_get_properties (widget); l; l = l->next) { 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; if (!(signal = glade_signal_read (iter_node, adaptor))) continue; /* The widget doesnt use the signal handler directly but rather * creates it's own copy */ glade_widget_add_signal_handler (widget, signal); g_object_unref (signal); } /* 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); if (glade_project_load_cancelled (glade_widget_get_project (widget))) return; } } static void glade_widget_adaptor_object_write_widget (GladeWidgetAdaptor * adaptor, GladeWidget * widget, GladeXmlContext * context, GladeXmlNode * node) { GList *props; /* Write the properties */ for (props = glade_widget_get_properties (widget); props; props = props->next) { GladeProperty *property = props->data; GladePropertyClass *klass = glade_property_get_class (property); if (glade_property_class_save (klass) && glade_property_get_enabled (property)) glade_property_write (GLADE_PROPERTY (props->data), context, node); } } static void glade_widget_adaptor_object_read_child (GladeWidgetAdaptor * adaptor, GladeWidget * widget, GladeXmlNode * node) { 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 = glade_widget_read (glade_widget_get_project (widget), widget, widget_node, internal_name); if (child_widget) { if (!internal_name) { glade_widget_set_child_type_from_node (widget, glade_widget_get_object (child_widget), node); 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) glade_property_read (property, glade_widget_get_project (child_widget), 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); glade_widget_adaptor_add (adaptor, glade_widget_get_object (widget), palaceholder); } g_free (internal_name); } static void glade_widget_adaptor_object_write_child (GladeWidgetAdaptor * adaptor, GladeWidget * widget, GladeXmlContext * context, GladeXmlNode * node) { 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 */ if (glade_widget_get_internal (widget)) glade_xml_node_set_property_string (child_node, GLADE_XML_TAG_INTERNAL_CHILD, glade_widget_get_internal (widget)); /* 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); for (props = glade_widget_get_packing_properties (widget); props; props = props->next) { GladeProperty *property = props->data; GladePropertyClass *klass = glade_property_get_class (property); if (glade_property_class_save (klass) && glade_property_get_enabled (property)) glade_property_write (GLADE_PROPERTY (props->data), context, packing_node); } glade_widget_write_special_child_prop (glade_widget_get_parent (widget), glade_widget_get_object (widget), context, child_node); /* 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 glade_widget_adaptor_get_eprop_type (GParamSpec * pspec) { 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)) { if (pspec->value_type == G_TYPE_VALUE_ARRAY) type = GLADE_TYPE_EPROP_TEXT; } else if (G_IS_PARAM_SPEC_BOXED (pspec)) { if (pspec->value_type == GDK_TYPE_COLOR) type = GLADE_TYPE_EPROP_COLOR; else if (pspec->value_type == G_TYPE_STRV) type = GLADE_TYPE_EPROP_TEXT; } else if (G_IS_PARAM_SPEC_STRING (pspec)) 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)) { if (pspec->value_type == GDK_TYPE_PIXBUF) 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; } static GladeEditorProperty * glade_widget_adaptor_object_create_eprop (GladeWidgetAdaptor * adaptor, GladePropertyClass * klass, gboolean use_command) { GladeEditorProperty *eprop; GParamSpec *pspec; GType type = 0; pspec = glade_property_class_get_pspec (klass); /* Find the right type of GladeEditorProperty for this * GladePropertyClass. */ if ((type = glade_widget_adaptor_get_eprop_type (pspec)) == 0) return NULL; /* special case for string specs that denote themed application icons. */ if (glade_property_class_themed_icon (klass)) type = GLADE_TYPE_EPROP_NAMED_ICON; /* Create and return the correct type of GladeEditorProperty */ eprop = g_object_new (type, "property-class", klass, "use-command", use_command, NULL); return eprop; } static gchar * glade_widget_adaptor_object_string_from_value (GladeWidgetAdaptor * adaptor, GladePropertyClass * klass, const GValue * value) { return glade_property_class_make_string_from_gvalue (klass, value); } static GladeEditable * glade_widget_adaptor_object_create_editable (GladeWidgetAdaptor * adaptor, GladeEditorPageType type) { return (GladeEditable *) glade_editor_table_new (adaptor, type); } /******************************************************************************* 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->create_widget = glade_widget_adaptor_object_create_widget; adaptor_class->construct_object = glade_widget_adaptor_object_construct_object; 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_verify = glade_widget_adaptor_object_add_verify; 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; adaptor_class->action_submenu = NULL; adaptor_class->depends = glade_widget_adaptor_object_depends; adaptor_class->read_widget = glade_widget_adaptor_object_read_widget; adaptor_class->write_widget = glade_widget_adaptor_object_write_widget; adaptor_class->read_child = glade_widget_adaptor_object_read_child; adaptor_class->write_child = glade_widget_adaptor_object_write_child; adaptor_class->create_eprop = glade_widget_adaptor_object_create_eprop; adaptor_class->string_from_value = glade_widget_adaptor_object_string_from_value; adaptor_class->create_editable = glade_widget_adaptor_object_create_editable; /* Base defaults here */ 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_CREATE_WIDGET_FUNCTION, &symbol)) klass->create_widget = symbol; if (glade_xml_load_sym_from_node (node, module, GLADE_TAG_CONSTRUCT_OBJECT_FUNCTION, &symbol)) klass->construct_object = 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_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_VERIFY_FUNCTION, &symbol)) klass->add_verify = 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_REPLACE_CHILD_FUNCTION, &symbol)) klass->replace_child = 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_GET_INTERNAL_CHILD_FUNCTION, &symbol)) klass->get_internal_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; if (glade_xml_load_sym_from_node (node, module, GLADE_TAG_ACTION_SUBMENU_FUNCTION, &symbol)) klass->action_submenu = symbol; if (glade_xml_load_sym_from_node (node, module, GLADE_TAG_DEPENDS_FUNCTION, &symbol)) klass->depends = symbol; if (glade_xml_load_sym_from_node (node, module, GLADE_TAG_READ_WIDGET_FUNCTION, &symbol)) klass->read_widget = symbol; if (glade_xml_load_sym_from_node (node, module, GLADE_TAG_WRITE_WIDGET_FUNCTION, &symbol)) klass->write_widget = symbol; if (glade_xml_load_sym_from_node (node, module, GLADE_TAG_READ_CHILD_FUNCTION, &symbol)) klass->read_child = symbol; if (glade_xml_load_sym_from_node (node, module, GLADE_TAG_WRITE_CHILD_FUNCTION, &symbol)) klass->write_child = symbol; if (glade_xml_load_sym_from_node (node, module, GLADE_TAG_CREATE_EPROP_FUNCTION, &symbol)) klass->create_eprop = symbol; if (glade_xml_load_sym_from_node (node, module, GLADE_TAG_STRING_FROM_VALUE_FUNCTION, &symbol)) klass->string_from_value = symbol; if (glade_xml_load_sym_from_node (node, module, GLADE_TAG_CREATE_EDITABLE_FUNCTION, &symbol)) klass->create_editable = 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); glade_xml_get_property_version (node, GLADE_TAG_VERSION_SINCE, &adaptor_class->version_since_major, &adaptor_class->version_since_minor); adaptor_class->deprecated = glade_xml_get_property_boolean (node, GLADE_TAG_DEPRECATED, adaptor_class->deprecated); adaptor_class->toplevel = glade_xml_get_property_boolean (node, GLADE_TAG_TOPLEVEL, adaptor_class->toplevel); adaptor_class->use_placeholders = glade_xml_get_property_boolean (node, GLADE_TAG_USE_PLACEHOLDERS, adaptor_class->use_placeholders); 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); g_free (type_name); return derived_type; } /******************************************************************************* API *******************************************************************************/ GType glade_widget_adaptor_get_object_type (GladeWidgetAdaptor *adaptor) { g_return_val_if_fail (GLADE_IS_WIDGET_ADAPTOR (adaptor), G_TYPE_INVALID); return adaptor->priv->type; } G_CONST_RETURN gchar * glade_widget_adaptor_get_name (GladeWidgetAdaptor *adaptor) { g_return_val_if_fail (GLADE_IS_WIDGET_ADAPTOR (adaptor), NULL); return adaptor->priv->name; } G_CONST_RETURN gchar * glade_widget_adaptor_get_generic_name (GladeWidgetAdaptor *adaptor) { g_return_val_if_fail (GLADE_IS_WIDGET_ADAPTOR (adaptor), NULL); return adaptor->priv->generic_name; } G_CONST_RETURN gchar * glade_widget_adaptor_get_title (GladeWidgetAdaptor *adaptor) { g_return_val_if_fail (GLADE_IS_WIDGET_ADAPTOR (adaptor), NULL); return adaptor->priv->title; } G_CONST_RETURN gchar * glade_widget_adaptor_get_icon_name (GladeWidgetAdaptor *adaptor) { g_return_val_if_fail (GLADE_IS_WIDGET_ADAPTOR (adaptor), NULL); return adaptor->priv->icon_name; } G_CONST_RETURN gchar * glade_widget_adaptor_get_missing_icon (GladeWidgetAdaptor *adaptor) { g_return_val_if_fail (GLADE_IS_WIDGET_ADAPTOR (adaptor), NULL); return adaptor->priv->missing_icon; } G_CONST_RETURN GList * glade_widget_adaptor_get_properties (GladeWidgetAdaptor *adaptor) { g_return_val_if_fail (GLADE_IS_WIDGET_ADAPTOR (adaptor), NULL); return adaptor->priv->properties; } G_CONST_RETURN GList * glade_widget_adaptor_get_packing_props (GladeWidgetAdaptor *adaptor) { g_return_val_if_fail (GLADE_IS_WIDGET_ADAPTOR (adaptor), NULL); return adaptor->priv->packing_props; } G_CONST_RETURN GList * glade_widget_adaptor_get_signals (GladeWidgetAdaptor *adaptor) { g_return_val_if_fail (GLADE_IS_WIDGET_ADAPTOR (adaptor), NULL); return adaptor->priv->signals; } static void accum_adaptor (GType * type, GladeWidgetAdaptor * adaptor, GList ** list) { *list = g_list_prepend (*list, adaptor); } /** * glade_widget_adaptor_list_adaptors: * * Compiles a list of all registered adaptors. * * Returns: A newly allocated #GList which must be freed with g_list_free() */ GList * glade_widget_adaptor_list_adaptors (void) { GList *adaptors = NULL; g_hash_table_foreach (adaptor_hash, (GHFunc) accum_adaptor, &adaptors); return adaptors; } /** * 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->priv->name)) { g_warning ("Adaptor class for '%s' already registered", adaptor->priv->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->priv->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->priv->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->priv->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->priv->child_packings = g_list_prepend (adaptor->priv->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->priv->name)) == NULL) continue; if ((value = glade_xml_get_property_string_required (prop_node, GLADE_TAG_DEFAULT, adaptor->priv->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->priv->child_packings = g_list_prepend (adaptor->priv->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->priv->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 (glade_property_class_id (property_class) != NULL && g_ascii_strcasecmp (id, glade_property_class_id (property_class)) == 0) break; } if (list) { property_class = GLADE_PROPERTY_CLASS (list->data); } else { property_class = glade_property_class_new (adaptor, id); /* When creating new virtual packing properties, * make sure we mark them as such here. */ if (is_packing) glade_property_class_set_is_packing (property_class, TRUE); *properties = g_list_append (*properties, property_class); list = g_list_last (*properties); } if ((updated = glade_property_class_update_from_node (child, adaptor->priv->type, &property_class, domain)) == FALSE) { g_warning ("failed to update %s property of %s from xml", id, adaptor->priv->name); g_free (id); continue; } /* if this pointer was set to null, its a property we dont handle. */ if (!property_class) *properties = g_list_delete_link (*properties, list); g_free (id); } } static GParamSpec * pspec_dup (GParamSpec * spec) { const gchar *name, *nick, *blurb; GType spec_type, value_type; GParamSpec *pspec = NULL; spec_type = G_PARAM_SPEC_TYPE (spec); value_type = spec->value_type; name = g_param_spec_get_name (spec); nick = g_param_spec_get_nick (spec); blurb = g_param_spec_get_blurb (spec); if (spec_type == G_TYPE_PARAM_ENUM || spec_type == G_TYPE_PARAM_FLAGS || spec_type == G_TYPE_PARAM_BOXED || spec_type == G_TYPE_PARAM_OBJECT || spec_type == GLADE_TYPE_PARAM_OBJECTS) { if (spec_type == G_TYPE_PARAM_ENUM) { GParamSpecEnum *p = (GParamSpecEnum *) spec; pspec = g_param_spec_enum (name, nick, blurb, value_type, p->default_value, 0); } else if (spec_type == G_TYPE_PARAM_FLAGS) { GParamSpecFlags *p = (GParamSpecFlags *) spec; pspec = g_param_spec_flags (name, nick, blurb, value_type, p->default_value, 0); } else if (spec_type == G_TYPE_PARAM_OBJECT) pspec = g_param_spec_object (name, nick, blurb, value_type, 0); else if (spec_type == GLADE_TYPE_PARAM_OBJECTS) pspec = glade_param_spec_objects (name, nick, blurb, value_type, 0); else pspec = g_param_spec_boxed (name, nick, blurb, value_type, 0); } else if (spec_type == G_TYPE_PARAM_STRING) { GParamSpecString *p = (GParamSpecString *) spec; pspec = g_param_spec_string (name, nick, blurb, p->default_value, 0); } else if (spec_type == G_TYPE_PARAM_BOOLEAN) { GParamSpecBoolean *p = (GParamSpecBoolean *) spec; pspec = g_param_spec_boolean (name, nick, blurb, p->default_value, 0); } else { if (spec_type == G_TYPE_PARAM_CHAR) { GParamSpecChar *p = (GParamSpecChar *) spec; pspec = g_param_spec_char (name, nick, blurb, p->minimum, p->maximum, p->default_value, 0); } else if (spec_type == G_TYPE_PARAM_UCHAR) { GParamSpecUChar *p = (GParamSpecUChar *) spec; pspec = g_param_spec_uchar (name, nick, blurb, p->minimum, p->maximum, p->default_value, 0); } else if (spec_type == G_TYPE_PARAM_INT) { GParamSpecInt *p = (GParamSpecInt *) spec; pspec = g_param_spec_int (name, nick, blurb, p->minimum, p->maximum, p->default_value, 0); } else if (spec_type == G_TYPE_PARAM_UINT) { GParamSpecUInt *p = (GParamSpecUInt *) spec; pspec = g_param_spec_uint (name, nick, blurb, p->minimum, p->maximum, p->default_value, 0); } else if (spec_type == G_TYPE_PARAM_LONG) { GParamSpecLong *p = (GParamSpecLong *) spec; pspec = g_param_spec_long (name, nick, blurb, p->minimum, p->maximum, p->default_value, 0); } else if (spec_type == G_TYPE_PARAM_ULONG) { GParamSpecULong *p = (GParamSpecULong *) spec; pspec = g_param_spec_ulong (name, nick, blurb, p->minimum, p->maximum, p->default_value, 0); } else if (spec_type == G_TYPE_PARAM_INT64) { GParamSpecInt64 *p = (GParamSpecInt64 *) spec; pspec = g_param_spec_int64 (name, nick, blurb, p->minimum, p->maximum, p->default_value, 0); } else if (spec_type == G_TYPE_PARAM_UINT64) { GParamSpecUInt64 *p = (GParamSpecUInt64 *) spec; pspec = g_param_spec_uint64 (name, nick, blurb, p->minimum, p->maximum, p->default_value, 0); } else if (spec_type == G_TYPE_PARAM_FLOAT) { GParamSpecFloat *p = (GParamSpecFloat *) spec; pspec = g_param_spec_float (name, nick, blurb, p->minimum, p->maximum, p->default_value, 0); } else if (spec_type == G_TYPE_PARAM_DOUBLE) { GParamSpecDouble *p = (GParamSpecDouble *) spec; pspec = g_param_spec_float (name, nick, blurb, p->minimum, p->maximum, p->default_value, 0); } } return pspec; } static void gwa_update_properties_from_type (GladeWidgetAdaptor * adaptor, GType type, GList ** properties, gboolean is_packing) { gpointer object_class = g_type_class_ref (type); GParamSpec **specs = NULL, *spec; guint i, n_specs = 0; /* only GtkContainer child propeties can be introspected */ if (is_packing && !g_type_is_a (adaptor->priv->type, GTK_TYPE_CONTAINER)) return; 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); for (i = 0; i < n_specs; i++) { GladePropertyClass *property_class; GList *list; /* 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 (glade_property_class_id (property_class) != NULL && g_ascii_strcasecmp (specs[i]->name, glade_property_class_id (property_class)) == 0) break; } if (list == NULL && (spec = pspec_dup (specs[i]))) { property_class = glade_property_class_new (adaptor, spec->name); glade_property_class_set_pspec (property_class, spec); /* Make sure we can tell properties apart by there * owning class. */ spec->owner_type = adaptor->priv->type; /* Disable properties by default since the does not really implement them */ glade_property_class_set_virtual (property_class, TRUE); glade_property_class_set_ignore (property_class, TRUE); glade_property_class_set_tooltip (property_class, g_param_spec_get_blurb (spec)); glade_property_class_set_name (property_class, g_param_spec_get_nick (spec)); if (spec->flags & G_PARAM_CONSTRUCT_ONLY) glade_property_class_set_construct_only (property_class, TRUE); glade_property_class_load_defaults_from_spec (property_class); glade_property_class_set_is_packing (property_class, is_packing); *properties = g_list_append (*properties, property_class); } } g_free (specs); } 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->priv->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 void gwa_set_signals_from_node (GladeWidgetAdaptor *adaptor, GladeXmlNode *node, const gchar *domain) { GladeXmlNode *child; GladeSignalClass *signal; GList *list; gchar *id; for (child = glade_xml_node_get_children (node); child; child = glade_xml_node_next (child)) { if (!glade_xml_node_verify (child, GLADE_TAG_SIGNAL)) continue; if (!(id = glade_xml_get_property_string_required (child, GLADE_TAG_ID, NULL))) continue; if ((list = g_list_find_custom (adaptor->priv->signals, id, (GCompareFunc) gwa_signal_find_comp)) != NULL) { signal = list->data; glade_signal_class_update_from_node (signal, child, domain); } g_free (id); } } 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 ((child = glade_xml_search_child (node, GLADE_TAG_PROPERTIES)) != NULL) gwa_update_properties_from_node (adaptor, child, module, &adaptor->priv->properties, domain, FALSE); if ((child = glade_xml_search_child (node, GLADE_TAG_PACKING_PROPERTIES)) != NULL) gwa_update_properties_from_node (adaptor, child, module, &adaptor->priv->packing_props, domain, TRUE); if ((child = glade_xml_search_child (node, GLADE_TAG_PACKING_DEFAULTS)) != NULL) gwa_set_packing_defaults_from_node (adaptor, child); if ((child = glade_xml_search_child (node, GLADE_TAG_SIGNALS)) != NULL) gwa_set_signals_from_node (adaptor, child, domain); if ((child = glade_xml_search_child (node, GLADE_TAG_ACTIONS)) != NULL) gwa_action_update_from_node (adaptor, FALSE, child, domain, NULL); 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_object_class: * @class_name: The name of the widget class * @class_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 object class, based on several parameters. * * Returns: An icon name, or NULL if the object class does not require one. */ static gchar * create_icon_name_for_object_class (const gchar * class_name, GType class_type, const gchar * icon_name, const gchar * icon_prefix, const gchar * generic_name) { gchar *name; /* only certain object classes need to have icons */ if (G_TYPE_IS_INSTANTIATABLE (class_type) == FALSE || G_TYPE_IS_ABSTRACT (class_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); return name; } static void gwa_displayable_values_check (GladeWidgetAdaptor * adaptor, gboolean packing) { GList *l, *p = (packing) ? adaptor->priv->packing_props : adaptor->priv->properties; for (l = p; l; l = g_list_next (l)) { GladePropertyClass *klass = l->data; GParamSpec *pspec = glade_property_class_get_pspec (klass); if (adaptor->priv->type == pspec->owner_type && glade_property_class_is_visible (klass) && (G_IS_PARAM_SPEC_ENUM (pspec) || G_IS_PARAM_SPEC_FLAGS (pspec)) && !glade_type_has_displayable_values (pspec->value_type) && pspec->value_type != GLADE_TYPE_STOCK && 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->priv->name, glade_property_class_id (klass)); } } } static GType generate_type (const char *name, const char *parent_name) { GType parent_type, retval; GTypeQuery query; GTypeInfo *type_info; char *new_name; 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); /* * If the type already exist it means we want to use the parent type * instead of the real one at runtime. * This is currently used to instantiate GtkWindow as a GtkEventBox * at runtime. */ if (g_type_from_name (name)) new_name = g_strdup_printf ("GladeFake%s", name); else new_name = NULL; type_info = g_new0 (GTypeInfo, 1); type_info->class_size = query.class_size; type_info->instance_size = query.instance_size; retval = g_type_register_static (parent_type, (new_name) ? new_name : name, type_info, 0); g_free (new_name); return retval; } /** * glade_widget_adaptor_from_catalog: * @catalog: A #GladeCatalog * @class_node: the #GladeXmlNode to load * @module: the plugin GModule. * * 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 (GladeCatalog * catalog, GladeXmlNode * class_node, GModule * module) { 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; gchar *missing_icon = NULL; 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 { GType type_iter; object_type = glade_util_get_type_from_name (name, FALSE); for (type_iter = g_type_parent (object_type); type_iter; type_iter = g_type_parent (type_iter)) { GladeWidgetAdaptor *a = glade_widget_adaptor_get_by_name (g_type_name (type_iter)); if (a && a->priv->real_type != a->priv->type) { object_type = generate_type (name, g_type_name (a->priv->type)); break; } } } 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_object_class (name, object_type, icon_name, glade_catalog_get_icon_prefix (catalog), generic_name); /* check if icon is available (a null icon-name is an abstract class) */ if (adaptor_icon_name && !gtk_icon_theme_has_icon (gtk_icon_theme_get_default (), adaptor_icon_name)) { GladeWidgetAdaptor *parent = glade_widget_adaptor_get_parent_adaptor_by_type (object_type); /* Save the desired name */ missing_icon = adaptor_icon_name; adaptor_icon_name = g_strdup ((parent && parent->priv->icon_name) ? parent->priv->icon_name : DEFAULT_ICON_NAME); } adaptor = g_object_new (adaptor_type, "type", object_type, "name", name, "catalog", glade_catalog_get_name (catalog), "generic-name", generic_name, "icon-name", adaptor_icon_name, NULL); adaptor->priv->missing_icon = missing_icon; 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->priv->title = g_strdup (name); } else { /* translate */ translated_title = dgettext (glade_catalog_get_domain (catalog), title); if (translated_title != title) { /* gettext owns translated_title */ adaptor->priv->title = g_strdup (translated_title); g_free (title); } else { adaptor->priv->title = title; } } if (G_TYPE_IS_INSTANTIATABLE (adaptor->priv->type) && G_TYPE_IS_ABSTRACT (adaptor->priv->type) == FALSE && adaptor->priv->generic_name == NULL) { g_warning ("Instantiatable class '%s' built without a '%s'", name, GLADE_TAG_GENERIC_NAME); } /* if adaptor->priv->type (the runtime used by glade) differs from adaptor->priv->name * (the name specified in the catalog) means we are using the type specified in the * the parent tag as the runtime and the class already exist. * So we need to add the properties and signals from the real class * even though they wont be aplied at runtime. */ if (adaptor->priv->type != adaptor->priv->real_type) { adaptor->priv->signals = gwa_list_signals (adaptor, adaptor->priv->real_type); gwa_update_properties_from_type (adaptor, adaptor->priv->real_type, &adaptor->priv->properties, FALSE); gwa_update_properties_from_type (adaptor, adaptor->priv->real_type, &adaptor->priv->packing_props, TRUE); } /* Perform a stoopid fallback just incase */ if (adaptor->priv->generic_name == NULL) adaptor->priv->generic_name = g_strdup ("widget"); adaptor->priv->catalog = g_strdup (glade_catalog_get_name (catalog)); if (glade_catalog_get_book (catalog)) adaptor->priv->book = g_strdup (glade_catalog_get_book (catalog)); gwa_extend_with_node (adaptor, class_node, module, glade_catalog_get_domain (catalog)); /* Set default weight on properties */ for (parent_type = adaptor->priv->type; parent_type != 0; parent_type = g_type_parent (parent_type)) { glade_property_class_set_weights (&adaptor->priv->properties, parent_type); glade_property_class_set_weights (&adaptor->priv->packing_props, parent_type); } gwa_displayable_values_check (adaptor, FALSE); gwa_displayable_values_check (adaptor, TRUE); glade_widget_adaptor_register (adaptor); g_free (name); 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. * @parent_name: the generic name of the parent used for fancy child names. * @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; 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; } gwidget = GLADE_WIDGET_ADAPTOR_GET_CLASS (adaptor)->create_widget (adaptor, first_property, vl_copy); va_end (vl_copy); if (query && glade_widget_adaptor_query (adaptor)) { /* If user pressed cancel on query popup. */ if (!glade_editor_query_dialog (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->priv->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_from_pspec: * @adaptor: a #GladeWidgetAdaptor * @pspec: a #GParamSpec * * Assumes @pspec is a property in an object class wrapped by @adaptor, * this function will search for the specific parent adaptor class which * originally introduced @pspec. * * Returns: the closest #GladeWidgetAdaptor in the ancestry to @adaptor * which is responsable for introducing @pspec. **/ GladeWidgetAdaptor * glade_widget_adaptor_from_pspec (GladeWidgetAdaptor * adaptor, GParamSpec * spec) { GladeWidgetAdaptor *spec_adaptor; GType spec_type = spec->owner_type; if (!spec_type) return adaptor; spec_adaptor = glade_widget_adaptor_get_by_type (spec->owner_type); g_return_val_if_fail (g_type_is_a (adaptor->priv->type, spec->owner_type), NULL); while (spec_type && !spec_adaptor && spec_type != adaptor->priv->type) { spec_type = g_type_parent (spec_type); spec_adaptor = glade_widget_adaptor_get_by_type (spec_type); } if (spec_adaptor) return spec_adaptor; return adaptor; } /** * 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->priv->properties; list && list->data; list = list->next) { pclass = list->data; if (strcmp (glade_property_class_id (pclass), 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->priv->packing_props; list && list->data; list = list->next) { pclass = list->data; if (strcmp (glade_property_class_id (pclass), 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->priv->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 */ glade_property_class_get_virtual (pclass) || /* should not be set before GladeWidget wrapper exists */ glade_property_class_get_ignore (pclass)) /* 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 (glade_property_class_get_default (pclass)), pspec[i]->value_type) == FALSE) { g_critical ("Type mismatch on %s property of %s", parameter.name, adaptor->priv->name); continue; } if (g_param_values_cmp (pspec[i], glade_property_class_get_default (pclass), glade_property_class_get_original_default (pclass)) == 0) continue; parameter.name = pspec[i]->name; /* These are not copied/freed */ g_value_init (¶meter.value, pspec[i]->value_type); g_value_copy (glade_property_class_get_default (pclass), ¶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_construct_object: * @adaptor: A #GladeWidgetAdaptor * @n_parameters: amount of construct parameters * @parameters: array of construct #GParameter args to create * the new object with. * * This function is called to construct a GObject instance for * a #GladeWidget of the said @adaptor. (provided for language * bindings that may need to construct a wrapper object). * * Returns: A newly created #GObject */ GObject * glade_widget_adaptor_construct_object (GladeWidgetAdaptor * adaptor, guint n_parameters, GParameter * parameters) { g_return_val_if_fail (GLADE_IS_WIDGET_ADAPTOR (adaptor), NULL); return GLADE_WIDGET_ADAPTOR_GET_CLASS (adaptor)->construct_object (adaptor, n_parameters, parameters); } /** * 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->priv->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->priv->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->priv->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->priv->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->priv->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->priv->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_verify: * @adaptor: A #GladeWidgetAdaptor * @parent: A #GObject container * @child: A #GObject child * @user_feedback: whether a notification dialog should be * presented in the case that the child cannot not be added. * * Checks whether @child can be added to @parent. * * If @user_feedback is %TRUE and @child cannot be * added then this shows a notification dialog to the user * explaining why. * * Returns: whether @child can be added to @parent. */ gboolean glade_widget_adaptor_add_verify (GladeWidgetAdaptor *adaptor, GObject *container, GObject *child, gboolean user_feedback) { 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 (g_type_is_a (G_OBJECT_TYPE (container), adaptor->priv->type), FALSE); return GLADE_WIDGET_ADAPTOR_GET_CLASS (adaptor)->add_verify (adaptor, container, child, user_feedback); } /** * 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->priv->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->priv->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->priv->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->priv->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->priv->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->priv->type)); /* XXX Valgrind says that the above 'g_type_is_a' line allocates uninitialized stack memory * that is later used in glade_gtk_box_child_set_property, why ? */ 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->priv->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->priv->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->priv->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->priv->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->priv->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->priv->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->priv->properties; l; l = l->next) { pclass = l->data; if (glade_property_class_query (pclass)) 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->priv->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 (strcmp (label, "") == 0) label = NULL; if (stock && strcmp (stock, "") == 0) stock = NULL; if ((action = gwa_action_lookup (*list, id)) == NULL) { /* New Action */ action = glade_widget_action_class_new (action_path); *list = g_list_append (*list, action); } glade_widget_action_class_set_label (action, label); glade_widget_action_class_set_stock (action, stock); glade_widget_action_class_set_important (action, important); 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->priv->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->priv->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->priv->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->priv->packing_actions, action_path); } /** * glade_widget_adaptor_actions_new: * @adaptor: A #GladeWidgetAdaptor * * Create a list of actions. * * Returns: a new list of GladeWidgetAction. */ GList * glade_widget_adaptor_actions_new (GladeWidgetAdaptor * adaptor) { GList *l, *list = NULL; g_return_val_if_fail (GLADE_IS_WIDGET_ADAPTOR (adaptor), NULL); for (l = adaptor->priv->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_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->priv->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->priv->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->priv->type)); GLADE_WIDGET_ADAPTOR_GET_CLASS (adaptor)->child_action_activate (adaptor, container, object, action_path); } /** * glade_widget_adaptor_action_submenu: * @adaptor: A #GladeWidgetAdaptor * @object: The #GObject * @action_path: The action identifier in the action tree * * This delagate function is used to create dynamically customized * submenus. Called only for actions that dont have children. * * Returns: A newly created #GtkMenu or %NULL */ GtkWidget * glade_widget_adaptor_action_submenu (GladeWidgetAdaptor * adaptor, GObject * object, const gchar * action_path) { 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 (g_type_is_a (G_OBJECT_TYPE (object), adaptor->priv->type), NULL); if (GLADE_WIDGET_ADAPTOR_GET_CLASS (adaptor)->action_submenu) return GLADE_WIDGET_ADAPTOR_GET_CLASS (adaptor)->action_submenu (adaptor, object, action_path); return NULL; } /** * glade_widget_adaptor_depends: * @adaptor: A #GladeWidgetAdaptor * @widget: A #GladeWidget of the adaptor * @another: another #GladeWidget * * Checks whether @widget depends on @another to be placed earlier in * the glade file. * * Returns: whether @widget depends on @another being parsed first in * the resulting glade file. */ gboolean glade_widget_adaptor_depends (GladeWidgetAdaptor * adaptor, GladeWidget * widget, GladeWidget * another) { g_return_val_if_fail (GLADE_IS_WIDGET_ADAPTOR (adaptor), FALSE); g_return_val_if_fail (GLADE_IS_WIDGET (widget), FALSE); g_return_val_if_fail (GLADE_IS_WIDGET (another), FALSE); return GLADE_WIDGET_ADAPTOR_GET_CLASS (adaptor)->depends (adaptor, widget, another); } /** * glade_widget_adaptor_read_widget: * @adaptor: A #GladeWidgetAdaptor * @widget: The #GladeWidget * @node: The #GladeXmlNode * * This function is called to update @widget from @node * when loading xml files. */ void glade_widget_adaptor_read_widget (GladeWidgetAdaptor * adaptor, GladeWidget * widget, GladeXmlNode * node) { g_return_if_fail (GLADE_IS_WIDGET_ADAPTOR (adaptor)); g_return_if_fail (GLADE_IS_WIDGET (widget)); g_return_if_fail (node != NULL); GLADE_WIDGET_ADAPTOR_GET_CLASS (adaptor)->read_widget (adaptor, widget, node); } /** * glade_widget_adaptor_write_widget: * @adaptor: A #GladeWidgetAdaptor * @widget: The #GladeWidget * @context: The #GladeXmlContext * @node: The #GladeXmlNode * * This function is called to write @widget to @node * when writing xml files. */ void glade_widget_adaptor_write_widget (GladeWidgetAdaptor * adaptor, GladeWidget * widget, GladeXmlContext * context, GladeXmlNode * node) { g_return_if_fail (GLADE_IS_WIDGET_ADAPTOR (adaptor)); g_return_if_fail (GLADE_IS_WIDGET (widget)); g_return_if_fail (node != NULL); GLADE_WIDGET_ADAPTOR_GET_CLASS (adaptor)->write_widget (adaptor, widget, context, node); } /** * glade_widget_adaptor_read_child: * @adaptor: A #GladeWidgetAdaptor * @widget: The #GladeWidget * @node: The #GladeXmlNode * * This function is called to update load a child @widget * from @node when loading xml files (will recurse into * glade_widget_read()) */ void glade_widget_adaptor_read_child (GladeWidgetAdaptor * adaptor, GladeWidget * widget, GladeXmlNode * node) { g_return_if_fail (GLADE_IS_WIDGET_ADAPTOR (adaptor)); g_return_if_fail (GLADE_IS_WIDGET (widget)); g_return_if_fail (node != NULL); GLADE_WIDGET_ADAPTOR_GET_CLASS (adaptor)->read_child (adaptor, widget, node); } /** * glade_widget_adaptor_write_child: * @adaptor: A #GladeWidgetAdaptor * @widget: The #GladeWidget * @context: The #GladeXmlContext * @node: The #GladeXmlNode * * This function is called to write the child @widget to @node * when writing xml files (takes care of packing and recurses * into glade_widget_write()) */ void glade_widget_adaptor_write_child (GladeWidgetAdaptor * adaptor, GladeWidget * widget, GladeXmlContext * context, GladeXmlNode * node) { g_return_if_fail (GLADE_IS_WIDGET_ADAPTOR (adaptor)); g_return_if_fail (GLADE_IS_WIDGET (widget)); g_return_if_fail (node != NULL); GLADE_WIDGET_ADAPTOR_GET_CLASS (adaptor)->write_child (adaptor, widget, context, node); } /** * glade_widget_adaptor_create_eprop: * @adaptor: A #GladeWidgetAdaptor * @klass: The #GladePropertyClass to be edited * @use_command: whether to use the GladeCommand interface * to commit property changes * * Creates a GladeEditorProperty to edit @klass * * Returns: A newly created #GladeEditorProperty */ GladeEditorProperty * glade_widget_adaptor_create_eprop (GladeWidgetAdaptor * adaptor, GladePropertyClass * klass, gboolean use_command) { GladeEditorProperty *eprop; g_return_val_if_fail (GLADE_IS_WIDGET_ADAPTOR (adaptor), NULL); g_return_val_if_fail (GLADE_IS_PROPERTY_CLASS (klass), NULL); eprop = GLADE_WIDGET_ADAPTOR_GET_CLASS (adaptor)->create_eprop (adaptor, klass, use_command); /* XXX we really need to print a g_error() here, exept we are * now using this func to test for unsupported properties * at init time from glade-property-class */ return eprop; } /** * glade_widget_adaptor_create_eprop_by_name: * @adaptor: A #GladeWidgetAdaptor * @property_id: the string if of the coresponding #GladePropertyClass to be edited * @packing: whether this reffers to a packing property * @use_command: whether to use the GladeCommand interface * to commit property changes * * Creates a #GladeEditorProperty to edit #GladePropertyClass @name in @adaptor * * Returns: A newly created #GladeEditorProperty */ GladeEditorProperty * glade_widget_adaptor_create_eprop_by_name (GladeWidgetAdaptor * adaptor, const gchar * property_id, gboolean packing, gboolean use_command) { GladePropertyClass *klass; g_return_val_if_fail (GLADE_IS_WIDGET_ADAPTOR (adaptor), NULL); g_return_val_if_fail (property_id && property_id[0], NULL); if (packing) klass = glade_widget_adaptor_get_pack_property_class (adaptor, property_id); else klass = glade_widget_adaptor_get_property_class (adaptor, property_id); g_return_val_if_fail (klass != NULL, NULL); return GLADE_WIDGET_ADAPTOR_GET_CLASS (adaptor)->create_eprop (adaptor, klass, use_command); } /** * glade_widget_adaptor_string_from_value: * @adaptor: A #GladeWidgetAdaptor * @klass: The #GladePropertyClass * @value: The #GValue to convert to a string * * For normal properties this is used to serialize * property values, for custom properties its still * needed to update the UI for undo/redo items etc. * * Returns: A newly allocated string representation of @value */ gchar * glade_widget_adaptor_string_from_value (GladeWidgetAdaptor * adaptor, GladePropertyClass * klass, const GValue * value) { g_return_val_if_fail (GLADE_IS_WIDGET_ADAPTOR (adaptor), NULL); g_return_val_if_fail (GLADE_IS_PROPERTY_CLASS (klass), NULL); g_return_val_if_fail (value != NULL, NULL); return GLADE_WIDGET_ADAPTOR_GET_CLASS (adaptor)->string_from_value (adaptor, klass, value); } /** * glade_widget_adaptor_get_signal_class: * @adaptor: A #GladeWidgetAdaptor * @name: the name of the signal class. * * Looks up signal class @name on @adaptor. * * Returns: a #GladeSignalClass or %NULL */ GladeSignalClass * glade_widget_adaptor_get_signal_class (GladeWidgetAdaptor * adaptor, const gchar * name) { GList *list; GladeSignalClass *signal; g_return_val_if_fail (GLADE_IS_WIDGET_ADAPTOR (adaptor), NULL); g_return_val_if_fail (name != NULL, NULL); for (list = adaptor->priv->signals; list; list = list->next) { signal = list->data; if (!strcmp (glade_signal_class_get_name (signal), name)) return signal; } return NULL; } /** * glade_widget_adaptor_create_editable: * @adaptor: A #GladeWidgetAdaptor * @type: The #GladeEditorPageType * * This is used to allow the backend to override the way an * editor page is layed out (note that editor widgets are created * on demand and not at startup). * * Returns: A new #GladeEditable widget */ GladeEditable * glade_widget_adaptor_create_editable (GladeWidgetAdaptor * adaptor, GladeEditorPageType type) { g_return_val_if_fail (GLADE_IS_WIDGET_ADAPTOR (adaptor), NULL); return GLADE_WIDGET_ADAPTOR_GET_CLASS (adaptor)->create_editable (adaptor, type); }