diff --git a/modules/other/parasite/parasite.h b/modules/other/parasite/parasite.h index 8ff6d0925c..107dca135c 100644 --- a/modules/other/parasite/parasite.h +++ b/modules/other/parasite/parasite.h @@ -36,6 +36,7 @@ typedef struct GtkWidget *window; GtkWidget *widget_tree; GtkWidget *prop_list; + GtkWidget *child_prop_list; GtkWidget *python_shell; GtkWidget *button_path; GtkWidget *classes_list; diff --git a/modules/other/parasite/prop-list.c b/modules/other/parasite/prop-list.c index 90d395e0ea..8cedde329b 100644 --- a/modules/other/parasite/prop-list.c +++ b/modules/other/parasite/prop-list.c @@ -39,7 +39,8 @@ enum enum { PROP_0, - PROP_WIDGET_TREE + PROP_WIDGET_TREE, + PROP_CHILD_PROPERTIES }; struct _ParasitePropListPrivate @@ -50,6 +51,8 @@ struct _ParasitePropListPrivate GList *signal_cnxs; GtkWidget *widget_tree; GtkTreeViewColumn *property_column; + GtkTreeViewColumn *value_column; + gboolean child_properties; }; G_DEFINE_TYPE_WITH_PRIVATE (ParasitePropList, parasite_proplist, GTK_TYPE_TREE_VIEW) @@ -163,19 +166,20 @@ constructed (GObject *object) g_object_set (renderer, "scale", TREE_TEXT_SCALE, "editable", TRUE, + "is-child-property", pl->priv->child_properties, NULL); - column = gtk_tree_view_column_new_with_attributes ("Value", renderer, - "text", COLUMN_VALUE, - "object", COLUMN_OBJECT, - "name", COLUMN_NAME, - NULL); - gtk_tree_view_append_column (GTK_TREE_VIEW (pl), column); - gtk_tree_view_column_set_resizable (column, TRUE); + pl->priv->value_column = gtk_tree_view_column_new_with_attributes ("Value", renderer, + "text", COLUMN_VALUE, + "object", COLUMN_OBJECT, + "name", COLUMN_NAME, + NULL); + gtk_tree_view_append_column (GTK_TREE_VIEW (pl), pl->priv->value_column); + gtk_tree_view_column_set_resizable (pl->priv->value_column, TRUE); gtk_tree_sortable_set_sort_column_id (GTK_TREE_SORTABLE (pl->priv->model), COLUMN_NAME, GTK_SORT_ASCENDING); - gtk_tree_view_column_set_cell_data_func (column, + gtk_tree_view_column_set_cell_data_func (pl->priv->value_column, renderer, (GtkTreeCellDataFunc) draw_columns, pl, @@ -212,6 +216,10 @@ get_property (GObject *object, g_value_take_object (value, pl->priv->widget_tree); break; + case PROP_CHILD_PROPERTIES: + g_value_set_boolean (value, pl->priv->child_properties); + break; + default: G_OBJECT_WARN_INVALID_PROPERTY_ID (object, param_id, pspec); break; @@ -232,6 +240,10 @@ set_property (GObject *object, pl->priv->widget_tree = g_value_get_object (value); break; + case PROP_CHILD_PROPERTIES: + pl->priv->child_properties = g_value_get_boolean (value); + break; + default: G_OBJECT_WARN_INVALID_PROPERTY_ID (object, param_id, pspec); break; @@ -254,6 +266,9 @@ parasite_proplist_class_init (ParasitePropListClass *klass) "Widget tree", GTK_TYPE_WIDGET, G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY)); + g_object_class_install_property (object_class, PROP_CHILD_PROPERTIES, + g_param_spec_boolean ("child-properties", "Child properties", "Child properties", + FALSE, G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY)); } static void @@ -265,7 +280,17 @@ parasite_prop_list_update_prop (ParasitePropList *pl, char *value; g_value_init(&gvalue, prop->value_type); - g_object_get_property (pl->priv->object, prop->name, &gvalue); + if (pl->priv->child_properties) + { + GtkWidget *parent; + + parent = gtk_widget_get_parent (GTK_WIDGET (pl->priv->object)); + gtk_container_child_get_property (GTK_CONTAINER (parent), + GTK_WIDGET (pl->priv->object), + prop->name, &gvalue); + } + else + g_object_get_property (pl->priv->object, prop->name, &gvalue); if (G_VALUE_HOLDS_ENUM (&gvalue)) { @@ -281,7 +306,7 @@ parasite_prop_list_update_prop (ParasitePropList *pl, gtk_list_store_set (pl->priv->model, iter, COLUMN_NAME, prop->name, - COLUMN_VALUE, value, + COLUMN_VALUE, value ? value : g_strdup (""), COLUMN_DEFINED_AT, g_type_name (prop->owner_type), COLUMN_OBJECT, pl->priv->object, COLUMN_TOOLTIP, g_param_spec_get_blurb (prop), @@ -304,10 +329,12 @@ parasite_proplist_prop_changed_cb (GObject *pspec, } GtkWidget * -parasite_proplist_new (GtkWidget *widget_tree) +parasite_proplist_new (GtkWidget *widget_tree, + gboolean child_properties) { return g_object_new (PARASITE_TYPE_PROPLIST, "widget-tree", widget_tree, + "child-properties", child_properties, NULL); } @@ -336,7 +363,22 @@ parasite_proplist_set_object (ParasitePropList* pl, GObject *object) g_hash_table_remove_all (pl->priv->prop_iters); gtk_list_store_clear (pl->priv->model); - props = g_object_class_list_properties (G_OBJECT_GET_CLASS (object), &num_properties); + if (pl->priv->child_properties) + { + GtkWidget *parent; + + if (!GTK_IS_WIDGET (object)) + return; + + parent = gtk_widget_get_parent (GTK_WIDGET (object)); + if (!parent) + return; + + props = gtk_container_class_list_child_properties (G_OBJECT_GET_CLASS (parent), &num_properties); + } + else + props = g_object_class_list_properties (G_OBJECT_GET_CLASS (object), &num_properties); + for (i = 0; i < num_properties; i++) { GParamSpec *prop = props[i]; @@ -351,7 +393,10 @@ parasite_proplist_set_object (ParasitePropList* pl, GObject *object) g_hash_table_insert (pl->priv->prop_iters, (gpointer) prop->name, gtk_tree_iter_copy (&iter)); /* Listen for updates */ - signal_name = g_strdup_printf ("notify::%s", prop->name); + if (pl->priv->child_properties) + signal_name = g_strdup_printf ("child-notify::%s", prop->name); + else + signal_name = g_strdup_printf ("notify::%s", prop->name); pl->priv->signal_cnxs = g_list_prepend (pl->priv->signal_cnxs, GINT_TO_POINTER( diff --git a/modules/other/parasite/prop-list.h b/modules/other/parasite/prop-list.h index d5eed223e0..efc75b5750 100644 --- a/modules/other/parasite/prop-list.h +++ b/modules/other/parasite/prop-list.h @@ -49,7 +49,8 @@ typedef struct _ParasitePropListClass { G_BEGIN_DECLS GType parasite_proplist_get_type (void); -GtkWidget *parasite_proplist_new (GtkWidget *widget_tree); +GtkWidget *parasite_proplist_new (GtkWidget *widget_tree, + gboolean child_properties); void parasite_proplist_set_object (ParasitePropList *proplist, GObject *object); diff --git a/modules/other/parasite/property-cell-renderer.c b/modules/other/parasite/property-cell-renderer.c index 16a7d0fdc0..1e0f4e919c 100644 --- a/modules/other/parasite/property-cell-renderer.c +++ b/modules/other/parasite/property-cell-renderer.c @@ -28,13 +28,15 @@ struct _ParasitePropertyCellRendererPrivate { GObject *object; char *name; + gboolean is_child_property; }; enum { PROP_0, PROP_OBJECT, - PROP_NAME + PROP_NAME, + PROP_IS_CHILD_PROPERTY }; G_DEFINE_TYPE_WITH_PRIVATE (ParasitePropertyCellRenderer, parasite_property_cell_renderer, GTK_TYPE_CELL_RENDERER_TEXT); @@ -63,6 +65,10 @@ get_property (GObject *object, g_value_set_string(value, r->priv->name); break; + case PROP_IS_CHILD_PROPERTY: + g_value_set_boolean (value, r->priv->is_child_property); + break; + default: G_OBJECT_WARN_INVALID_PROPERTY_ID(object, param_id, pspec); break; @@ -88,24 +94,81 @@ set_property (GObject *object, r->priv->name = g_value_dup_string (value); break; + case PROP_IS_CHILD_PROPERTY: + r->priv->is_child_property = g_value_get_boolean (value); + g_object_notify (object, "is-child-property"); + break; + default: G_OBJECT_WARN_INVALID_PROPERTY_ID(object, param_id, pspec); break; } } +static GParamSpec * +find_property (GtkCellRenderer *renderer) +{ + ParasitePropertyCellRenderer *r = PARASITE_PROPERTY_CELL_RENDERER (renderer); + + if (r->priv->is_child_property) + { + GtkWidget *parent; + + parent = gtk_widget_get_parent (GTK_WIDGET (r->priv->object)); + + return gtk_container_class_find_child_property (G_OBJECT_GET_CLASS (parent), r->priv->name); + } + + return g_object_class_find_property (G_OBJECT_GET_CLASS (r->priv->object), r->priv->name); +} + +static void +get_value (GtkCellRenderer *renderer, + GValue *gvalue) +{ + ParasitePropertyCellRenderer *r = PARASITE_PROPERTY_CELL_RENDERER (renderer); + + if (r->priv->is_child_property) + { + GtkWidget *widget; + GtkWidget *parent; + + widget = GTK_WIDGET (r->priv->object); + parent = gtk_widget_get_parent (widget); + + gtk_container_child_get_property (GTK_CONTAINER (parent), widget, r->priv->name, gvalue); + } + else + g_object_get_property (r->priv->object, r->priv->name, gvalue); +} + +static void +set_value (GtkCellRenderer *renderer, + GValue *gvalue) +{ + ParasitePropertyCellRenderer *r = PARASITE_PROPERTY_CELL_RENDERER (renderer); + + if (r->priv->is_child_property) + { + GtkWidget *widget; + GtkWidget *parent; + + widget = GTK_WIDGET (r->priv->object); + parent = gtk_widget_get_parent (widget); + + gtk_container_child_set_property (GTK_CONTAINER (parent), widget, r->priv->name, gvalue); + } + else + g_object_set_property (r->priv->object, r->priv->name, gvalue); +} + static void stop_editing(GtkCellEditable *editable, GtkCellRenderer *renderer) { - GObject *object; - const char *name; GValue gvalue = {0}; GParamSpec *prop; - object = g_object_get_data(G_OBJECT(editable), "_prop_object"); - name = g_object_get_data(G_OBJECT(editable), "_prop_name"); - - prop = g_object_class_find_property(G_OBJECT_GET_CLASS(object), name); + prop = find_property (renderer); g_value_init(&gvalue, prop->value_type); if (GTK_IS_ENTRY(editable)) @@ -172,7 +235,7 @@ stop_editing(GtkCellEditable *editable, GtkCellRenderer *renderer) } } - g_object_set_property(object, name, &gvalue); + set_value (renderer, &gvalue); g_value_unset(&gvalue); } @@ -187,19 +250,15 @@ start_editing (GtkCellRenderer *renderer, { PangoFontDescription *font_desc; GtkCellEditable *editable = NULL; - GObject *object; - const char *name; GValue gvalue = {0}; GParamSpec *prop; + ParasitePropertyCellRenderer *r = PARASITE_PROPERTY_CELL_RENDERER (renderer); - g_object_get(renderer, - "object", &object, - "name", &name, - NULL); + prop = find_property (renderer); - prop = g_object_class_find_property(G_OBJECT_GET_CLASS(object), name); g_value_init(&gvalue, prop->value_type); - g_object_get_property(object, name, &gvalue); + + get_value (renderer, &gvalue); if (G_VALUE_HOLDS_OBJECT (&gvalue)) { @@ -214,7 +273,7 @@ start_editing (GtkCellRenderer *renderer, { parasite_widget_tree_select_object (widget_tree, prop_object); } - else if (parasite_widget_tree_find_object (widget_tree, object, &iter)) + else if (parasite_widget_tree_find_object (widget_tree, r->priv->object, &iter)) { parasite_widget_tree_append_object (widget_tree, prop_object, &iter); parasite_widget_tree_select_object (widget_tree, prop_object); @@ -366,8 +425,6 @@ start_editing (GtkCellRenderer *renderer, pango_font_description_free(font_desc); g_signal_connect(editable, "editing_done", G_CALLBACK (stop_editing), renderer); - g_object_set_data_full (G_OBJECT (editable), "_prop_name", g_strdup (name), g_free); - g_object_set_data (G_OBJECT (editable), "_prop_object", object); return editable; } @@ -398,6 +455,10 @@ parasite_property_cell_renderer_class_init (ParasitePropertyCellRendererClass *k "The property name", NULL, G_PARAM_READWRITE)); + + g_object_class_install_property (object_class, PROP_IS_CHILD_PROPERTY, + g_param_spec_boolean ("is-child-property", "Child property", "Child property", + FALSE, G_PARAM_READWRITE)); } GtkCellRenderer * diff --git a/modules/other/parasite/window.c b/modules/other/parasite/window.c index 4b12b186b3..fd7dc870e8 100644 --- a/modules/other/parasite/window.c +++ b/modules/other/parasite/window.c @@ -42,10 +42,9 @@ on_widget_tree_selection_changed (ParasiteWidgetTree *widget_tree, if (selected != NULL) { - parasite_proplist_set_object (PARASITE_PROPLIST (parasite->prop_list), - selected); - parasite_objecthierarchy_set_object (PARASITE_OBJECTHIERARCHY (parasite->oh), - selected); + parasite_proplist_set_object (PARASITE_PROPLIST (parasite->prop_list), selected); + parasite_proplist_set_object (PARASITE_PROPLIST (parasite->child_prop_list), selected); + parasite_objecthierarchy_set_object (PARASITE_OBJECTHIERARCHY (parasite->oh), selected); if (GTK_IS_WIDGET (selected)) { @@ -135,9 +134,11 @@ create_widget_list_pane(ParasiteWindow *parasite) } static GtkWidget * -create_prop_list_pane(ParasiteWindow *parasite) +create_prop_list_pane (ParasiteWindow *parasite, + gboolean child_properties) { GtkWidget *swin; + GtkWidget *pl; swin = g_object_new (GTK_TYPE_SCROLLED_WINDOW, "hscrollbar-policy", GTK_POLICY_AUTOMATIC, @@ -146,8 +147,13 @@ create_prop_list_pane(ParasiteWindow *parasite) "width-request", 250, NULL); - parasite->prop_list = parasite_proplist_new (parasite->widget_tree); - gtk_container_add(GTK_CONTAINER(swin), parasite->prop_list); + pl = parasite_proplist_new (parasite->widget_tree, child_properties); + gtk_container_add (GTK_CONTAINER (swin), pl); + + if (child_properties) + parasite->child_prop_list = pl; + else + parasite->prop_list = pl; return swin; } @@ -273,8 +279,12 @@ gtkparasite_window_create() "show-border", FALSE, NULL); gtk_notebook_append_page (GTK_NOTEBOOK (nb), - create_prop_list_pane (window), - gtk_label_new ("GObject Properties")); + create_prop_list_pane (window, FALSE), + gtk_label_new ("Properties")); + + gtk_notebook_append_page (GTK_NOTEBOOK (nb), + create_prop_list_pane (window, TRUE), + gtk_label_new ("Child Properties")); window->oh = parasite_objecthierarchy_new (); gtk_notebook_append_page (GTK_NOTEBOOK (nb),