]> Pileus Git - ~andy/gtk/blobdiff - tests/prop-editor.c
Don't leak the tooltip object.
[~andy/gtk] / tests / prop-editor.c
index 701bde80304d09b17c783fb9bbfe602699d37ee6..0dc055b3d9d755218584ed4d07e354ed66c66e14 100644 (file)
  * Boston, MA 02111-1307, USA.
  */
 
+#include <config.h>
 #include <string.h>
 
+#undef GTK_DISABLE_DEPRECATED
 #include <gtk/gtk.h>
 
 #include "prop-editor.h"
 
-static void
-get_param_specs (GType         type,
-                 GParamSpec ***specs,
-                 gint         *n_specs)
-{
-  GObjectClass *class = g_type_class_peek (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 = NULL; /* class->property_specs; */
-  *n_specs = 0; /* class->n_property_specs; */
-}
 
 typedef struct
 {
@@ -67,7 +54,7 @@ signal_removed (gpointer  data,
 static void
 g_object_connect_property (GObject *object,
                            const gchar *prop_name,
-                           GtkSignalFunc func,
+                           GCallback func,
                            gpointer data,
                            GObject *alive_object)
 {
@@ -124,7 +111,7 @@ connect_controller (GObject *controller,
 
   p->modified_id = g_signal_connect_data (controller, signal, func, p,
                                          (GClosureNotify)free_object_property,
-                                         FALSE, FALSE);
+                                         0);
   g_object_set_data (controller, "object-property", p);
 }
 
@@ -435,46 +422,65 @@ pointer_changed (GObject *object, GParamSpec *pspec, gpointer data)
 static void
 object_changed (GObject *object, GParamSpec *pspec, gpointer data)
 {
-  GtkLabel *label = GTK_LABEL (data);
+  GtkWidget *label, *button;
   gchar *str;
   GObject *obj;
   const gchar *name;
   
+  GList *children = gtk_container_get_children (GTK_CONTAINER (data)); 
+  label = GTK_WIDGET (children->data);
+  button = GTK_WIDGET (children->next->data);
   g_object_get (object, pspec->name, &obj, NULL);
+  g_list_free (children);
 
   if (obj)
     name = g_type_name (G_TYPE_FROM_INSTANCE (obj));
   else
     name = "unknown";
-  str = g_strdup_printf ("Objetct: %p (%s)", obj, name);
+  str = g_strdup_printf ("Object: %p (%s)", obj, name);
   
-  gtk_label_set_text (label, str);
+  gtk_label_set_text (GTK_LABEL (label), str);
+  gtk_widget_set_sensitive (button, G_IS_OBJECT (obj));
+
   g_free (str);
 }
 
-void
+static void
 model_destroy (gpointer data)
 {
   g_object_steal_data (data, "model-object");
   gtk_widget_destroy (data);
 }
 
-void
+static void
 window_destroy (gpointer data)
 {
   g_object_steal_data (data, "prop-editor-win");
 }
 
+static void
+object_properties (GtkWidget *button, 
+                  GObject   *object)
+{
+  gchar *name;
+  GObject *obj;
+
+  name = (gchar *) g_object_get_data (G_OBJECT (button), "property-name");
+  g_object_get (object, name, &obj, NULL);
+  if (G_IS_OBJECT (obj)) 
+    create_prop_editor (obj, 0);
+}
 static GtkWidget *
 property_widget (GObject *object, GParamSpec *spec, gboolean can_modify)
 {
   GtkWidget *prop_edit;
   GtkAdjustment *adj;
   gchar *msg;
-  
-  switch (G_PARAM_SPEC_TYPE (spec))
+  GType type = G_PARAM_SPEC_TYPE (spec);
+
+  if (type == G_TYPE_PARAM_INT)
     {
-    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,
@@ -486,36 +492,37 @@ property_widget (GObject *object, GParamSpec *spec, gboolean can_modify)
       prop_edit = gtk_spin_button_new (adj, 1.0, 0);
       
       g_object_connect_property (object, spec->name,
-                                GTK_SIGNAL_FUNC (int_changed),
+                                G_CALLBACK (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:
+    }
+  else if (type == 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));
+                           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),
+                                G_CALLBACK (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:
+    }
+  else if (type == 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,
@@ -527,15 +534,15 @@ property_widget (GObject *object, GParamSpec *spec, gboolean can_modify)
       prop_edit = gtk_spin_button_new (adj, 0.1, 2);
       
       g_object_connect_property (object, spec->name,
-                                GTK_SIGNAL_FUNC (float_changed),
+                                G_CALLBACK (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:
+    }
+  else if (type == 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,
@@ -547,39 +554,39 @@ property_widget (GObject *object, GParamSpec *spec, gboolean can_modify)
       prop_edit = gtk_spin_button_new (adj, 0.1, 2);
       
       g_object_connect_property (object, spec->name,
-                                GTK_SIGNAL_FUNC (double_changed),
+                                G_CALLBACK (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:
+    }
+  else if (type == G_TYPE_PARAM_STRING)
+    {
       prop_edit = gtk_entry_new ();
       
       g_object_connect_property (object, spec->name,
-                                GTK_SIGNAL_FUNC (string_changed),
+                                G_CALLBACK (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:
+    }
+  else if (type == G_TYPE_PARAM_BOOLEAN)
+    {
       prop_edit = gtk_toggle_button_new_with_label ("");
       
       g_object_connect_property (object, spec->name,
-                                GTK_SIGNAL_FUNC (bool_changed),
+                                G_CALLBACK (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:
+    }
+  else if (type == G_TYPE_PARAM_ENUM)
+    {
       {
        GtkWidget *menu;
        GEnumClass *eclass;
@@ -610,46 +617,57 @@ property_widget (GObject *object, GParamSpec *spec, gboolean can_modify)
        gtk_option_menu_set_menu (GTK_OPTION_MENU (prop_edit), menu);
        
        g_object_connect_property (object, spec->name,
-                                  GTK_SIGNAL_FUNC (enum_changed),
+                                  G_CALLBACK (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:
+    }
+  else if (type == 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),
+                                G_CALLBACK (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:
+    }
+  else if (type == G_TYPE_PARAM_POINTER)
+    {
       prop_edit = gtk_label_new ("");
       
       g_object_connect_property (object, spec->name,
-                                GTK_SIGNAL_FUNC (pointer_changed),
+                                G_CALLBACK (pointer_changed),
                                 prop_edit, G_OBJECT (prop_edit));
-      break;
-      
-    case G_TYPE_PARAM_OBJECT:
-      prop_edit = gtk_label_new ("");
+    }
+  else if (type == G_TYPE_PARAM_OBJECT)
+    {
+      GtkWidget *label, *button;
+
+      prop_edit = gtk_hbox_new (FALSE, 5);
+
+      label = gtk_label_new ("");
+      button = gtk_button_new_with_label ("Properties");
+      g_object_set_data (G_OBJECT (button), "property-name", spec->name);
+      g_signal_connect (button, "clicked", 
+                       G_CALLBACK (object_properties), 
+                       object);
+
+      gtk_container_add (GTK_CONTAINER (prop_edit), label);
+      gtk_container_add (GTK_CONTAINER (prop_edit), button);
       
       g_object_connect_property (object, spec->name,
-                                GTK_SIGNAL_FUNC (object_changed),
-                                prop_edit, G_OBJECT (prop_edit));
-      break;
-      
-      
-    default:
+                                G_CALLBACK (object_changed),
+                                prop_edit, G_OBJECT (label));
+    }
+  else
+    {  
       msg = g_strdup_printf ("uneditable property type: %s",
                             g_type_name (G_PARAM_SPEC_TYPE (spec)));
       prop_edit = gtk_label_new (msg);            
@@ -670,12 +688,21 @@ properties_from_type (GObject     *object,
   GtkWidget *sw;
   GtkWidget *vbox;
   GtkWidget *table;
+  GParamSpec **specs;
+  gint n_specs;
   int i;
-  gint n_specs = 0;
-  GParamSpec **specs = NULL;
-
-  get_param_specs (type, &specs, &n_specs);
 
+  if (G_TYPE_IS_INTERFACE (type))
+    {
+      gpointer vtable = g_type_default_interface_peek (type);
+      specs = g_object_interface_list_properties (vtable, &n_specs);
+    }
+  else
+    {
+      GObjectClass *class = G_OBJECT_CLASS (g_type_class_peek (type));
+      specs = g_object_class_list_properties (class, &n_specs);
+    }
+        
   if (n_specs == 0)
     return NULL;
   
@@ -701,7 +728,14 @@ properties_from_type (GObject     *object,
           continue;
         }
       
-      label = gtk_label_new (spec->nick);
+      if (spec->owner_type != type)
+       {
+         /* we're only interested in params of type */
+         ++i;
+         continue;
+       }
+
+      label = gtk_label_new (g_param_spec_get_nick (spec));
       gtk_misc_set_alignment (GTK_MISC (label), 0.0, 0.5);
       gtk_table_attach_defaults (GTK_TABLE (table), label, 0, 1, i, i + 1);
       
@@ -713,8 +747,8 @@ properties_from_type (GObject     *object,
           if (!can_modify)
             gtk_widget_set_sensitive (prop_edit, FALSE);
 
-         if (spec->blurb)
-           gtk_tooltips_set_tip (tips, prop_edit, spec->blurb, NULL);
+         if (g_param_spec_get_blurb (spec))
+           gtk_tooltips_set_tip (tips, prop_edit, g_param_spec_get_blurb (spec), NULL);
          
           /* set initial value */
           g_object_notify (object, spec->name);
@@ -732,13 +766,23 @@ properties_from_type (GObject     *object,
                                   GTK_POLICY_NEVER, GTK_POLICY_AUTOMATIC);
   
   gtk_scrolled_window_add_with_viewport (GTK_SCROLLED_WINDOW (sw), vbox);
+
+  g_free (specs);
+
   return sw;
 }
 
+static void
+kill_tips (GtkWindow *win, GtkObject *tips)
+{
+  gtk_object_destroy (tips);
+  g_object_unref (tips);
+}
 
 /* Pass zero for type if you want all properties */
 GtkWidget*
-create_prop_editor (GObject *object, GType type)
+create_prop_editor (GObject   *object,
+                   GType      type)
 {
   GtkWidget *win;
   GtkWidget *notebook;
@@ -746,7 +790,9 @@ create_prop_editor (GObject *object, GType type)
   GtkWidget *properties;
   GtkWidget *label;
   gchar *title;
-
+  GType *ifaces;
+  guint n_ifaces;
+  
   if ((win = g_object_get_data (G_OBJECT (object), "prop-editor-win")))
     {
       gtk_window_present (GTK_WINDOW (win));
@@ -754,10 +800,16 @@ create_prop_editor (GObject *object, GType type)
     }
 
   win = gtk_window_new (GTK_WINDOW_TOPLEVEL);
+  if (GTK_IS_WIDGET (object))
+    gtk_window_set_screen (GTK_WINDOW (win),
+                          gtk_widget_get_screen (GTK_WIDGET (object)));
 
   tips = gtk_tooltips_new ();
-  gtk_signal_connect_object (GTK_OBJECT (win), "destroy",
-                            GTK_SIGNAL_FUNC (gtk_object_destroy), GTK_OBJECT (tips));
+  g_object_ref (tips);
+  gtk_object_sink (GTK_OBJECT (tips));
+
+  /* Kill the tips when the widget goes away.  */
+  g_signal_connect (G_OBJECT (win), "destroy", G_CALLBACK (kill_tips), 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);
@@ -771,7 +823,7 @@ create_prop_editor (GObject *object, GType type)
       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);
@@ -788,6 +840,20 @@ create_prop_editor (GObject *object, GType type)
          
          type = g_type_parent (type);
        }
+
+      ifaces = g_type_interfaces (G_TYPE_FROM_INSTANCE (object), &n_ifaces);
+      while (n_ifaces--)
+       {
+         properties = properties_from_type (object, ifaces[n_ifaces], tips);
+         if (properties)
+           {
+             label = gtk_label_new (g_type_name (ifaces[n_ifaces]));
+             gtk_notebook_append_page (GTK_NOTEBOOK (notebook),
+                                       properties, label);
+           }
+       }
+
+      g_free (ifaces);
     }
   else
     {
@@ -795,6 +861,7 @@ create_prop_editor (GObject *object, GType type)
       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);
+      g_free (title);
     }
   
   gtk_window_set_default_size (GTK_WINDOW (win), -1, 400);