summaryrefslogtreecommitdiff
path: root/tests
diff options
context:
space:
mode:
authorAlexander Larsson <alla@lysator.liu.se>2001-05-17 16:22:06 +0000
committerAlexander Larsson <alexl@src.gnome.org>2001-05-17 16:22:06 +0000
commit6ee1ae13adafbb6a0ac5a75a948f0a9bc8f0e751 (patch)
treebd9689851eabea933a0ef00c0ad9c97c376b62cd /tests
parentbe277ae41303b9d5ba92a911360e66f197c82eba (diff)
downloadgtk+-6ee1ae13adafbb6a0ac5a75a948f0a9bc8f0e751.tar.gz
Add properties, based on patch by Lee Mallabone.GTK_MULTIHEAD_MERGE1
2001-05-17 Alexander Larsson <alla@lysator.liu.se> * gtk/gtkbbox.c: Add properties, based on patch by Lee Mallabone. * gtk/gtknotebook.c: * gtk/gtktoolbar.c: Convert from GtkArg to GParam, based on patch by John Margaglione. * gtk/gtkhscale.c: * gtk/gtkvscale.c: * gtk/gtkhscrollbar.c: * gtk/gtkvscrollbar.c: * gtk/gtkrange.c: Move adjustment property to GtkRange. * gtk/gtklabel.c: Setup mnemonics on property changes * gtk/gtkwidget.c (gtk_widget_get_property): GdkExtensionMode is an enum, not a flag. Set it with g_value_set_enum (). * tests/prop-editor.c: Better propery editor. * tests/testgtk.c: Add new property test. Pass zero to the property editor to get properties from all derived types.
Diffstat (limited to 'tests')
-rw-r--r--tests/prop-editor.c593
-rw-r--r--tests/testgtk.c252
2 files changed, 634 insertions, 211 deletions
diff --git a/tests/prop-editor.c b/tests/prop-editor.c
index 2c91578155..a8e3cc2610 100644
--- a/tests/prop-editor.c
+++ b/tests/prop-editor.c
@@ -33,7 +33,7 @@ get_param_specs (GType type,
/* We count on the fact we have an instance, or else we'd have
* to use g_type_class_ref ();
*/
-
+
/* Use private interface for now, fix later */
*specs = class->property_specs;
*n_specs = class->n_property_specs;
@@ -133,7 +133,8 @@ block_controller (GObject *controller)
{
ObjectProperty *p = g_object_get_data (controller, "object-property");
- g_signal_handler_block (controller, p->modified_id);
+ if (p)
+ g_signal_handler_block (controller, p->modified_id);
}
static void
@@ -141,7 +142,8 @@ unblock_controller (GObject *controller)
{
ObjectProperty *p = g_object_get_data (controller, "object-property");
- g_signal_handler_unblock (controller, p->modified_id);
+ if (p)
+ g_signal_handler_unblock (controller, p->modified_id);
}
static void
@@ -172,6 +174,33 @@ int_changed (GObject *object, GParamSpec *pspec, gpointer data)
}
static void
+uint_modified (GtkAdjustment *adj, gpointer data)
+{
+ ObjectProperty *p = data;
+
+ g_object_set (p->obj, p->prop, (guint) adj->value, NULL);
+}
+
+static void
+uint_changed (GObject *object, GParamSpec *pspec, gpointer data)
+{
+ GtkAdjustment *adj = GTK_ADJUSTMENT (data);
+ GValue val = { 0, };
+
+ g_value_init (&val, G_TYPE_UINT);
+ g_object_get_property (object, pspec->name, &val);
+
+ if (g_value_get_uint (&val) != (guint)adj->value)
+ {
+ block_controller (G_OBJECT (adj));
+ gtk_adjustment_set_value (adj, g_value_get_uint (&val));
+ unblock_controller (G_OBJECT (adj));
+ }
+
+ g_value_unset (&val);
+}
+
+static void
float_modified (GtkAdjustment *adj, gpointer data)
{
ObjectProperty *p = data;
@@ -199,6 +228,33 @@ float_changed (GObject *object, GParamSpec *pspec, gpointer data)
}
static void
+double_modified (GtkAdjustment *adj, gpointer data)
+{
+ ObjectProperty *p = data;
+
+ g_object_set (p->obj, p->prop, (double) adj->value, NULL);
+}
+
+static void
+double_changed (GObject *object, GParamSpec *pspec, gpointer data)
+{
+ GtkAdjustment *adj = GTK_ADJUSTMENT (data);
+ GValue val = { 0, };
+
+ g_value_init (&val, G_TYPE_DOUBLE);
+ g_object_get_property (object, pspec->name, &val);
+
+ if (g_value_get_double (&val) != adj->value)
+ {
+ block_controller (G_OBJECT (adj));
+ gtk_adjustment_set_value (adj, g_value_get_double (&val));
+ unblock_controller (G_OBJECT (adj));
+ }
+
+ g_value_unset (&val);
+}
+
+static void
string_modified (GtkEntry *entry, gpointer data)
{
ObjectProperty *p = data;
@@ -362,6 +418,40 @@ unichar_changed (GObject *object, GParamSpec *pspec, gpointer data)
}
}
+static void
+pointer_changed (GObject *object, GParamSpec *pspec, gpointer data)
+{
+ GtkLabel *label = GTK_LABEL (data);
+ gchar *str;
+ gpointer ptr;
+
+ g_object_get (object, pspec->name, &ptr, NULL);
+
+ str = g_strdup_printf ("Pointer: %p", ptr);
+ gtk_label_set_text (label, str);
+ g_free (str);
+}
+
+static void
+object_changed (GObject *object, GParamSpec *pspec, gpointer data)
+{
+ GtkLabel *label = GTK_LABEL (data);
+ gchar *str;
+ GObject *obj;
+ const gchar *name;
+
+ g_object_get (object, pspec->name, &obj, NULL);
+
+ if (obj)
+ name = g_type_name (G_TYPE_FROM_INSTANCE (obj));
+ else
+ name = "unknown";
+ str = g_strdup_printf ("Objetct: %p (%s)", obj, name);
+
+ gtk_label_set_text (label, str);
+ g_free (str);
+}
+
void
model_destroy (gpointer data)
{
@@ -375,43 +465,224 @@ window_destroy (gpointer data)
g_object_steal_data (data, "prop-editor-win");
}
-GtkWidget*
-create_prop_editor (GObject *object,
- GType type)
+static GtkWidget *
+property_widget (GObject *object, GParamSpec *spec, gboolean can_modify)
{
- GtkWidget *win;
- GtkWidget *vbox;
- GtkWidget *hbox;
- GtkWidget *label;
GtkWidget *prop_edit;
+ GtkAdjustment *adj;
+ gchar *msg;
+
+ switch (G_PARAM_SPEC_TYPE (spec))
+ {
+ case G_TYPE_PARAM_INT:
+ adj = GTK_ADJUSTMENT (gtk_adjustment_new (G_PARAM_SPEC_INT (spec)->default_value,
+ G_PARAM_SPEC_INT (spec)->minimum,
+ G_PARAM_SPEC_INT (spec)->maximum,
+ 1,
+ MAX ((G_PARAM_SPEC_INT (spec)->maximum -
+ G_PARAM_SPEC_INT (spec)->minimum) / 10, 1),
+ 0.0));
+
+ prop_edit = gtk_spin_button_new (adj, 1.0, 0);
+
+ g_object_connect_property (object, spec->name,
+ GTK_SIGNAL_FUNC (int_changed),
+ adj, G_OBJECT (adj));
+
+ if (can_modify)
+ connect_controller (G_OBJECT (adj), "value_changed",
+ object, spec->name, (GtkSignalFunc) int_modified);
+ break;
+
+ case G_TYPE_PARAM_UINT:
+ adj = GTK_ADJUSTMENT (
+ gtk_adjustment_new (G_PARAM_SPEC_UINT (spec)->default_value,
+ G_PARAM_SPEC_UINT (spec)->minimum,
+ G_PARAM_SPEC_UINT (spec)->maximum,
+ 1,
+ MAX ((G_PARAM_SPEC_UINT (spec)->maximum -
+ G_PARAM_SPEC_UINT (spec)->minimum) / 10, 1),
+ 0.0));
+
+ prop_edit = gtk_spin_button_new (adj, 1.0, 0);
+
+ g_object_connect_property (object, spec->name,
+ GTK_SIGNAL_FUNC (uint_changed),
+ adj, G_OBJECT (adj));
+
+ if (can_modify)
+ connect_controller (G_OBJECT (adj), "value_changed",
+ object, spec->name, (GtkSignalFunc) uint_modified);
+ break;
+
+ case G_TYPE_PARAM_FLOAT:
+ adj = GTK_ADJUSTMENT (gtk_adjustment_new (G_PARAM_SPEC_FLOAT (spec)->default_value,
+ G_PARAM_SPEC_FLOAT (spec)->minimum,
+ G_PARAM_SPEC_FLOAT (spec)->maximum,
+ 0.1,
+ MAX ((G_PARAM_SPEC_FLOAT (spec)->maximum -
+ G_PARAM_SPEC_FLOAT (spec)->minimum) / 10, 0.1),
+ 0.0));
+
+ prop_edit = gtk_spin_button_new (adj, 0.1, 2);
+
+ g_object_connect_property (object, spec->name,
+ GTK_SIGNAL_FUNC (float_changed),
+ adj, G_OBJECT (adj));
+
+ if (can_modify)
+ connect_controller (G_OBJECT (adj), "value_changed",
+ object, spec->name, (GtkSignalFunc) float_modified);
+ break;
+
+ case G_TYPE_PARAM_DOUBLE:
+ adj = GTK_ADJUSTMENT (gtk_adjustment_new (G_PARAM_SPEC_DOUBLE (spec)->default_value,
+ G_PARAM_SPEC_DOUBLE (spec)->minimum,
+ G_PARAM_SPEC_DOUBLE (spec)->maximum,
+ 0.1,
+ MAX ((G_PARAM_SPEC_DOUBLE (spec)->maximum -
+ G_PARAM_SPEC_DOUBLE (spec)->minimum) / 10, 0.1),
+ 0.0));
+
+ prop_edit = gtk_spin_button_new (adj, 0.1, 2);
+
+ g_object_connect_property (object, spec->name,
+ GTK_SIGNAL_FUNC (double_changed),
+ adj, G_OBJECT (adj));
+
+ if (can_modify)
+ connect_controller (G_OBJECT (adj), "value_changed",
+ object, spec->name, (GtkSignalFunc) double_modified);
+ break;
+
+ case G_TYPE_PARAM_STRING:
+ prop_edit = gtk_entry_new ();
+
+ g_object_connect_property (object, spec->name,
+ GTK_SIGNAL_FUNC (string_changed),
+ prop_edit, G_OBJECT (prop_edit));
+
+ if (can_modify)
+ connect_controller (G_OBJECT (prop_edit), "changed",
+ object, spec->name, (GtkSignalFunc) string_modified);
+ break;
+
+ case G_TYPE_PARAM_BOOLEAN:
+ prop_edit = gtk_toggle_button_new_with_label ("");
+
+ g_object_connect_property (object, spec->name,
+ GTK_SIGNAL_FUNC (bool_changed),
+ prop_edit, G_OBJECT (prop_edit));
+
+ if (can_modify)
+ connect_controller (G_OBJECT (prop_edit), "toggled",
+ object, spec->name, (GtkSignalFunc) bool_modified);
+ break;
+
+ case G_TYPE_PARAM_ENUM:
+ {
+ GtkWidget *menu;
+ GEnumClass *eclass;
+ gint j;
+
+ prop_edit = gtk_option_menu_new ();
+
+ menu = gtk_menu_new ();
+
+ eclass = G_ENUM_CLASS (g_type_class_ref (spec->value_type));
+
+ j = 0;
+ while (j < eclass->n_values)
+ {
+ GtkWidget *mi;
+
+ mi = gtk_menu_item_new_with_label (eclass->values[j].value_name);
+
+ gtk_widget_show (mi);
+
+ gtk_menu_shell_append (GTK_MENU_SHELL (menu), mi);
+
+ ++j;
+ }
+
+ g_type_class_unref (eclass);
+
+ gtk_option_menu_set_menu (GTK_OPTION_MENU (prop_edit), menu);
+
+ g_object_connect_property (object, spec->name,
+ GTK_SIGNAL_FUNC (enum_changed),
+ prop_edit, G_OBJECT (prop_edit));
+
+ if (can_modify)
+ connect_controller (G_OBJECT (prop_edit), "changed",
+ object, spec->name, (GtkSignalFunc) enum_modified);
+ }
+ break;
+
+ case G_TYPE_PARAM_UNICHAR:
+ prop_edit = gtk_entry_new ();
+ gtk_entry_set_max_length (GTK_ENTRY (prop_edit), 1);
+
+ g_object_connect_property (object, spec->name,
+ GTK_SIGNAL_FUNC (unichar_changed),
+ prop_edit, G_OBJECT (prop_edit));
+
+ if (can_modify)
+ connect_controller (G_OBJECT (prop_edit), "changed",
+ object, spec->name, (GtkSignalFunc) unichar_modified);
+ break;
+
+ case G_TYPE_PARAM_POINTER:
+ prop_edit = gtk_label_new ("");
+
+ g_object_connect_property (object, spec->name,
+ GTK_SIGNAL_FUNC (pointer_changed),
+ prop_edit, G_OBJECT (prop_edit));
+ break;
+
+ case G_TYPE_PARAM_OBJECT:
+ prop_edit = gtk_label_new ("");
+
+ g_object_connect_property (object, spec->name,
+ GTK_SIGNAL_FUNC (object_changed),
+ prop_edit, G_OBJECT (prop_edit));
+ break;
+
+
+ default:
+ msg = g_strdup_printf ("uneditable property type: %s",
+ g_type_name (G_PARAM_SPEC_TYPE (spec)));
+ prop_edit = gtk_label_new (msg);
+ g_free (msg);
+ gtk_misc_set_alignment (GTK_MISC (prop_edit), 0.0, 0.5);
+ }
+
+ return prop_edit;
+}
+
+static GtkWidget *
+properties_from_type (GObject *object,
+ GType type,
+ GtkTooltips *tips)
+{
+ GtkWidget *prop_edit;
+ GtkWidget *label;
GtkWidget *sw;
+ GtkWidget *vbox;
+ GtkWidget *table;
+ int i;
gint n_specs = 0;
GParamSpec **specs = NULL;
- gint i;
- GtkAdjustment *adj;
- GtkTooltips *tips;
-
- win = gtk_window_new (GTK_WINDOW_TOPLEVEL);
- tips = gtk_tooltips_new ();
- gtk_signal_connect_object (GTK_OBJECT (win), "destroy",
- GTK_SIGNAL_FUNC (gtk_object_destroy), GTK_OBJECT (tips));
+ get_param_specs (type, &specs, &n_specs);
- /* hold a weak ref to the object we're editing */
- g_object_set_data_full (G_OBJECT (object), "prop-editor-win", win, model_destroy);
- g_object_set_data_full (G_OBJECT (win), "model-object", object, window_destroy);
+ if (n_specs == 0)
+ return NULL;
- vbox = gtk_vbox_new (TRUE, 2);
+ table = gtk_table_new (n_specs, 2, FALSE);
+ gtk_table_set_col_spacing (GTK_TABLE (table), 0, 10);
+ gtk_table_set_row_spacings (GTK_TABLE (table), 3);
- sw = gtk_scrolled_window_new (NULL, NULL);
- gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW (sw),
- GTK_POLICY_AUTOMATIC, GTK_POLICY_AUTOMATIC);
-
- gtk_scrolled_window_add_with_viewport (GTK_SCROLLED_WINDOW (sw), vbox);
- gtk_container_add (GTK_CONTAINER (win), sw);
-
- get_param_specs (type, &specs, &n_specs);
-
i = 0;
while (i < n_specs)
{
@@ -430,184 +701,12 @@ create_prop_editor (GObject *object,
continue;
}
- switch (G_PARAM_SPEC_TYPE (spec))
- {
- case G_TYPE_PARAM_INT:
- hbox = gtk_hbox_new (FALSE, 10);
- label = gtk_label_new (spec->nick);
- gtk_misc_set_alignment (GTK_MISC (label), 0.0, 0.5);
- gtk_box_pack_start (GTK_BOX (hbox), label, FALSE, FALSE, 0);
- adj = GTK_ADJUSTMENT (gtk_adjustment_new (G_PARAM_SPEC_INT (spec)->default_value,
- G_PARAM_SPEC_INT (spec)->minimum,
- G_PARAM_SPEC_INT (spec)->maximum,
- 1,
- MAX ((G_PARAM_SPEC_INT (spec)->maximum -
- G_PARAM_SPEC_INT (spec)->minimum) / 10, 1),
- 0.0));
-
- prop_edit = gtk_spin_button_new (adj, 1.0, 0);
- gtk_box_pack_end (GTK_BOX (hbox), prop_edit, FALSE, FALSE, 0);
-
- gtk_box_pack_start (GTK_BOX (vbox), hbox, FALSE, FALSE, 0);
-
- g_object_connect_property (object, spec->name,
- GTK_SIGNAL_FUNC (int_changed),
- adj, G_OBJECT (adj));
-
- if (can_modify)
- connect_controller (G_OBJECT (adj), "value_changed",
- object, spec->name, (GtkSignalFunc) int_modified);
- break;
-
- case G_TYPE_PARAM_FLOAT:
- hbox = gtk_hbox_new (FALSE, 10);
- label = gtk_label_new (spec->nick);
- gtk_misc_set_alignment (GTK_MISC (label), 0.0, 0.5);
- gtk_box_pack_start (GTK_BOX (hbox), label, FALSE, FALSE, 0);
- adj = GTK_ADJUSTMENT (gtk_adjustment_new (G_PARAM_SPEC_FLOAT (spec)->default_value,
- G_PARAM_SPEC_FLOAT (spec)->minimum,
- G_PARAM_SPEC_FLOAT (spec)->maximum,
- 0.1,
- MAX ((G_PARAM_SPEC_FLOAT (spec)->maximum -
- G_PARAM_SPEC_FLOAT (spec)->minimum) / 10, 0.1),
- 0.0));
-
- prop_edit = gtk_spin_button_new (adj, 0.1, 2);
-
- gtk_box_pack_end (GTK_BOX (hbox), prop_edit, FALSE, FALSE, 0);
-
- gtk_box_pack_start (GTK_BOX (vbox), hbox, FALSE, FALSE, 0);
-
- g_object_connect_property (object, spec->name,
- GTK_SIGNAL_FUNC (float_changed),
- adj, G_OBJECT (adj));
-
- if (can_modify)
- connect_controller (G_OBJECT (adj), "value_changed",
- object, spec->name, (GtkSignalFunc) float_modified);
- break;
-
- case G_TYPE_PARAM_STRING:
- hbox = gtk_hbox_new (FALSE, 10);
- label = gtk_label_new (spec->nick);
- gtk_misc_set_alignment (GTK_MISC (label), 0.0, 0.5);
- gtk_box_pack_start (GTK_BOX (hbox), label, FALSE, FALSE, 0);
-
- prop_edit = gtk_entry_new ();
- gtk_box_pack_end (GTK_BOX (hbox), prop_edit, FALSE, FALSE, 0);
-
- gtk_box_pack_start (GTK_BOX (vbox), hbox, FALSE, FALSE, 0);
-
- g_object_connect_property (object, spec->name,
- GTK_SIGNAL_FUNC (string_changed),
- prop_edit, G_OBJECT (prop_edit));
-
- if (can_modify)
- connect_controller (G_OBJECT (prop_edit), "changed",
- object, spec->name, (GtkSignalFunc) string_modified);
- break;
-
- case G_TYPE_PARAM_BOOLEAN:
- hbox = gtk_hbox_new (FALSE, 10);
- label = gtk_label_new (spec->nick);
- gtk_misc_set_alignment (GTK_MISC (label), 0.0, 0.5);
- gtk_box_pack_start (GTK_BOX (hbox), label, FALSE, FALSE, 0);
-
- prop_edit = gtk_toggle_button_new_with_label ("");
- gtk_box_pack_end (GTK_BOX (hbox), prop_edit, FALSE, FALSE, 0);
-
- gtk_box_pack_start (GTK_BOX (vbox), hbox, FALSE, FALSE, 0);
-
- g_object_connect_property (object, spec->name,
- GTK_SIGNAL_FUNC (bool_changed),
- prop_edit, G_OBJECT (prop_edit));
-
- if (can_modify)
- connect_controller (G_OBJECT (prop_edit), "toggled",
- object, spec->name, (GtkSignalFunc) bool_modified);
- break;
-
- case G_TYPE_PARAM_ENUM:
- {
- GtkWidget *menu;
- GEnumClass *eclass;
- gint i;
-
- hbox = gtk_hbox_new (FALSE, 10);
- label = gtk_label_new (spec->nick);
- gtk_misc_set_alignment (GTK_MISC (label), 0.0, 0.5);
- gtk_box_pack_start (GTK_BOX (hbox), label, FALSE, FALSE, 0);
-
- prop_edit = gtk_option_menu_new ();
-
- menu = gtk_menu_new ();
-
- eclass = G_ENUM_CLASS (g_type_class_ref (spec->value_type));
-
- i = 0;
- while (i < eclass->n_values)
- {
- GtkWidget *mi;
-
- mi = gtk_menu_item_new_with_label (eclass->values[i].value_name);
-
- gtk_widget_show (mi);
-
- gtk_menu_shell_append (GTK_MENU_SHELL (menu), mi);
-
- ++i;
- }
-
- g_type_class_unref (eclass);
-
- gtk_option_menu_set_menu (GTK_OPTION_MENU (prop_edit), menu);
-
- gtk_box_pack_end (GTK_BOX (hbox), prop_edit, FALSE, FALSE, 0);
-
- gtk_box_pack_start (GTK_BOX (vbox), hbox, FALSE, FALSE, 0);
-
- g_object_connect_property (object, spec->name,
- GTK_SIGNAL_FUNC (enum_changed),
- prop_edit, G_OBJECT (prop_edit));
-
- if (can_modify)
- connect_controller (G_OBJECT (prop_edit), "changed",
- object, spec->name, (GtkSignalFunc) enum_modified);
- }
-
- case G_TYPE_PARAM_UNICHAR:
- hbox = gtk_hbox_new (FALSE, 10);
- label = gtk_label_new (spec->nick);
- gtk_misc_set_alignment (GTK_MISC (label), 0.0, 0.5);
- gtk_box_pack_start (GTK_BOX (hbox), label, FALSE, FALSE, 0);
-
- prop_edit = gtk_entry_new ();
- gtk_entry_set_max_length (GTK_ENTRY (prop_edit), 1);
- gtk_box_pack_end (GTK_BOX (hbox), prop_edit, FALSE, FALSE, 0);
-
- gtk_box_pack_start (GTK_BOX (vbox), hbox, FALSE, FALSE, 0);
-
- g_object_connect_property (object, spec->name,
- GTK_SIGNAL_FUNC (unichar_changed),
- prop_edit, G_OBJECT (prop_edit));
-
- if (can_modify)
- connect_controller (G_OBJECT (prop_edit), "changed",
- object, spec->name, (GtkSignalFunc) unichar_modified);
- break;
-
- default:
- {
- gchar *msg = g_strdup_printf ("%s: don't know how to edit property type %s",
- spec->nick, g_type_name (G_PARAM_SPEC_TYPE (spec)));
- hbox = gtk_hbox_new (FALSE, 10);
- label = gtk_label_new (msg);
- g_free (msg);
- gtk_misc_set_alignment (GTK_MISC (label), 0.0, 0.5);
- gtk_box_pack_start (GTK_BOX (hbox), label, FALSE, FALSE, 0);
- gtk_box_pack_start (GTK_BOX (vbox), hbox, FALSE, FALSE, 0);
- }
- }
+ label = gtk_label_new (spec->nick);
+ gtk_misc_set_alignment (GTK_MISC (label), 0.0, 0.5);
+ gtk_table_attach_defaults (GTK_TABLE (table), label, 0, 1, i, i + 1);
+
+ prop_edit = property_widget (object, spec, can_modify);
+ gtk_table_attach_defaults (GTK_TABLE (table), prop_edit, 1, 2, i, i + 1);
if (prop_edit)
{
@@ -624,7 +723,81 @@ create_prop_editor (GObject *object,
++i;
}
- gtk_window_set_default_size (GTK_WINDOW (win), 300, 500);
+
+ vbox = gtk_vbox_new (FALSE, 0);
+ gtk_box_pack_start (GTK_BOX (vbox), table, FALSE, FALSE, 0);
+
+ sw = gtk_scrolled_window_new (NULL, NULL);
+ gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW (sw),
+ GTK_POLICY_NEVER, GTK_POLICY_AUTOMATIC);
+
+ gtk_scrolled_window_add_with_viewport (GTK_SCROLLED_WINDOW (sw), vbox);
+ return sw;
+}
+
+
+/* Pass zero for type if you want all properties */
+GtkWidget*
+create_prop_editor (GObject *object, GType type)
+{
+ GtkWidget *win;
+ GtkWidget *notebook;
+ GtkTooltips *tips;
+ GtkWidget *properties;
+ GtkWidget *label;
+ gchar *title;
+
+ if ((win = g_object_get_data (G_OBJECT (object), "prop-editor-win")))
+ {
+ gtk_window_present (GTK_WINDOW (win));
+ return win;
+ }
+
+ win = gtk_window_new (GTK_WINDOW_TOPLEVEL);
+
+ tips = gtk_tooltips_new ();
+ gtk_signal_connect_object (GTK_OBJECT (win), "destroy",
+ GTK_SIGNAL_FUNC (gtk_object_destroy), GTK_OBJECT (tips));
+
+ /* hold a weak ref to the object we're editing */
+ g_object_set_data_full (G_OBJECT (object), "prop-editor-win", win, model_destroy);
+ g_object_set_data_full (G_OBJECT (win), "model-object", object, window_destroy);
+
+ if (type == 0)
+ {
+ notebook = gtk_notebook_new ();
+ gtk_notebook_set_tab_pos (GTK_NOTEBOOK (notebook), GTK_POS_LEFT);
+
+ gtk_container_add (GTK_CONTAINER (win), notebook);
+
+ type = G_TYPE_FROM_INSTANCE (object);
+
+ title = g_strdup_printf ("Properties of %s widget", g_type_name (type));
+ gtk_window_set_title (GTK_WINDOW (win), title);
+ g_free (title);
+
+ while (type)
+ {
+ properties = properties_from_type (object, type, tips);
+ if (properties)
+ {
+ label = gtk_label_new (g_type_name (type));
+ gtk_notebook_append_page (GTK_NOTEBOOK (notebook),
+ properties, label);
+ }
+
+ type = g_type_parent (type);
+ }
+ }
+ else
+ {
+ properties = properties_from_type (object, type, tips);
+ gtk_container_add (GTK_CONTAINER (win), properties);
+ title = g_strdup_printf ("Properties of %s", g_type_name (type));
+ gtk_window_set_title (GTK_WINDOW (win), title);
+ }
+
+ gtk_window_set_default_size (GTK_WINDOW (win), -1, 400);
gtk_widget_show_all (win);
diff --git a/tests/testgtk.c b/tests/testgtk.c
index 6b27120bab..edb9741fe1 100644
--- a/tests/testgtk.c
+++ b/tests/testgtk.c
@@ -3530,7 +3530,7 @@ static void
entry_props_clicked (GtkWidget *button,
GObject *entry)
{
- GtkWidget *window = create_prop_editor (entry, GTK_TYPE_ENTRY);
+ GtkWidget *window = create_prop_editor (entry, 0);
gtk_window_set_title (GTK_WINDOW (window), "Entry Properties");
}
@@ -8955,6 +8955,255 @@ create_progress_bar (void)
}
/*
+ * Properties
+ */
+
+typedef struct {
+ int x;
+ int y;
+ gboolean found;
+ gboolean first;
+ GtkWidget *res_widget;
+} FindWidgetData;
+
+static void
+find_widget (GtkWidget *widget, FindWidgetData *data)
+{
+ GtkAllocation new_allocation;
+ gint x_offset = 0;
+ gint y_offset = 0;
+
+ new_allocation = widget->allocation;
+
+ if (data->found || !GTK_WIDGET_MAPPED (widget))
+ return;
+
+ /* Note that in the following code, we only count the
+ * position as being inside a WINDOW widget if it is inside
+ * widget->window; points that are outside of widget->window
+ * but within the allocation are not counted. This is consistent
+ * with the way we highlight drag targets.
+ */
+ if (!GTK_WIDGET_NO_WINDOW (widget))
+ {
+ new_allocation.x = 0;
+ new_allocation.y = 0;
+ }
+
+ if (widget->parent && !data->first)
+ {
+ GdkWindow *window = widget->window;
+ while (window != widget->parent->window)
+ {
+ gint tx, ty, twidth, theight;
+ gdk_window_get_size (window, &twidth, &theight);
+
+ if (new_allocation.x < 0)
+ {
+ new_allocation.width += new_allocation.x;
+ new_allocation.x = 0;
+ }
+ if (new_allocation.y < 0)
+ {
+ new_allocation.height += new_allocation.y;
+ new_allocation.y = 0;
+ }
+ if (new_allocation.x + new_allocation.width > twidth)
+ new_allocation.width = twidth - new_allocation.x;
+ if (new_allocation.y + new_allocation.height > theight)
+ new_allocation.height = theight - new_allocation.y;
+
+ gdk_window_get_position (window, &tx, &ty);
+ new_allocation.x += tx;
+ x_offset += tx;
+ new_allocation.y += ty;
+ y_offset += ty;
+
+ window = gdk_window_get_parent (window);
+ }
+ }
+
+ if ((data->x >= new_allocation.x) && (data->y >= new_allocation.y) &&
+ (data->x < new_allocation.x + new_allocation.width) &&
+ (data->y < new_allocation.y + new_allocation.height))
+ {
+ /* First, check if the drag is in a valid drop site in
+ * one of our children
+ */
+ if (GTK_IS_CONTAINER (widget))
+ {
+ FindWidgetData new_data = *data;
+
+ new_data.x -= x_offset;
+ new_data.y -= y_offset;
+ new_data.found = FALSE;
+ new_data.first = FALSE;
+
+ gtk_container_forall (GTK_CONTAINER (widget),
+ (GtkCallback)find_widget,
+ &new_data);
+
+ data->found = new_data.found;
+ if (data->found)
+ data->res_widget = new_data.res_widget;
+ }
+
+ /* If not, and this widget is registered as a drop site, check to
+ * emit "drag_motion" to check if we are actually in
+ * a drop site.
+ */
+ if (!data->found)
+ {
+ data->found = TRUE;
+ data->res_widget = widget;
+ }
+ }
+}
+
+static GtkWidget *
+find_widget_at_pointer (void)
+{
+ GtkWidget *widget = NULL;
+ GdkWindow *pointer_window;
+ gint x, y;
+ FindWidgetData data;
+
+ pointer_window = gdk_window_at_pointer (NULL, NULL);
+
+ if (pointer_window)
+ gdk_window_get_user_data (pointer_window, (gpointer*) &widget);
+
+ if (widget)
+ {
+ gdk_window_get_pointer (widget->window,
+ &x, &y, NULL);
+
+ data.x = x;
+ data.y = y;
+ data.found = FALSE;
+ data.first = TRUE;
+
+ find_widget (widget, &data);
+ if (data.found)
+ return data.res_widget;
+ return widget;
+ }
+ return NULL;
+}
+
+struct PropertiesData {
+ GtkWidget **window;
+ GdkCursor *cursor;
+ gboolean in_query;
+ gint handler;
+};
+
+static void
+destroy_properties (GtkWidget *widget,
+ struct PropertiesData *data)
+{
+ *data->window = NULL;
+
+ if (data->cursor)
+ gdk_cursor_destroy (data->cursor);
+
+ gtk_signal_disconnect (widget, data->handler);
+
+ g_free (data);
+}
+
+static gint
+property_query_event (GtkWidget *widget,
+ GdkEvent *event,
+ struct PropertiesData *data)
+{
+ GtkWidget *res_widget = NULL;
+
+ if (!data->in_query)
+ return FALSE;
+
+ if (event->type == GDK_BUTTON_RELEASE)
+ {
+ gtk_grab_remove (widget);
+ gdk_pointer_ungrab (GDK_CURRENT_TIME);
+
+ res_widget = find_widget_at_pointer ();
+ if (res_widget)
+ create_prop_editor (G_OBJECT (res_widget), 0);
+
+ data->in_query = FALSE;
+ }
+ return FALSE;
+}
+
+
+static void
+query_properties (GtkButton *button,
+ struct PropertiesData *data)
+{
+ gint failure;
+
+ gtk_signal_connect (GTK_OBJECT (button), "event",
+ (GtkSignalFunc) property_query_event, data);
+
+
+ if (!data->cursor)
+ data->cursor = gdk_cursor_new (GDK_TARGET);
+
+ failure = gdk_pointer_grab (GTK_WIDGET (button)->window,
+ TRUE,
+ GDK_BUTTON_RELEASE_MASK,
+ NULL,
+ data->cursor,
+ GDK_CURRENT_TIME);
+
+ gtk_grab_add (GTK_WIDGET (button));
+
+ data->in_query = TRUE;
+}
+
+static void
+create_properties (void)
+{
+ static GtkWidget *window = NULL;
+ GtkWidget *button;
+ struct PropertiesData *data;
+
+ data = g_new (struct PropertiesData, 1);
+ data->window = &window;
+ data->in_query = FALSE;
+ data->cursor = NULL;
+ data->handler = 0;
+
+ if (!window)
+ {
+ window = gtk_window_new (GTK_WINDOW_TOPLEVEL);
+
+ data->handler = gtk_signal_connect_object (GTK_OBJECT (window), "destroy",
+ GTK_SIGNAL_FUNC(destroy_properties),
+ data);
+
+ gtk_window_set_title (GTK_WINDOW (window), "test properties");
+ gtk_container_set_border_width (GTK_CONTAINER (window), 10);
+
+ button = gtk_button_new_with_label ("Query properties");
+ gtk_signal_connect (GTK_OBJECT (button), "clicked",
+ GTK_SIGNAL_FUNC(query_properties),
+ data);
+
+
+ gtk_container_add (GTK_CONTAINER (window), button);
+ }
+
+ if (!GTK_WIDGET_VISIBLE (window))
+ gtk_widget_show_all (window);
+ else
+ gtk_widget_destroy (window);
+
+}
+
+
+/*
* Color Preview
*/
@@ -10173,6 +10422,7 @@ create_main_window (void)
{ "preview color", create_color_preview },
{ "preview gray", create_gray_preview },
{ "progress bar", create_progress_bar },
+ { "properties", create_properties },
{ "radio buttons", create_radio_buttons },
{ "range controls", create_range_controls },
{ "rc file", create_rc_file },