GObject patch



Hello all,

Attached is a patch to gobject.h and gobject.c that allows an object to
be notified using GSignal of param changes to another object.

For example:

  /* The GGizmoClass has a "name" parameter.
   */
  subject = g_object_new (G_TYPE_GIZMO, NULL);

  /* Notify observer if "name" param changes for subject.
   */
  observer = g_object_new (G_TYPE_OBJECT, NULL);
  g_object_notify_param_changed (subject, "name", observer);

  /* Emits a param changed signal.
   */
  g_object_set (subject, "name", "Gimp", NULL);

I tested it out and it works like a charm.  Enjoy!

Eric.
--- gobject.h.orig	Fri Oct 27 12:06:56 2000
+++ gobject.h	Fri Oct 27 14:50:52 2000
@@ -92,7 +92,8 @@
   void	     (*queue_param_changed)	(GObject	*object,
 					 GParamSpec	*pspec);
   void	     (*dispatch_param_changed)	(GObject	*object,
-					 GParamSpec	*pspec);
+					 GParamSpec	*pspec,
+					 GObject	*subject);
   void	     (*shutdown)		(GObject	*object);
   void	     (*finalize)		(GObject	*object);
 };
@@ -136,6 +137,9 @@
 					    GValue	   *value);
 void	    g_object_queue_param_changed   (GObject	   *object,
 					    const gchar	   *param_name);
+guint	    g_object_notify_param_changed  (GObject	   *object,
+					    const gchar	   *param_name,
+					    GObject	   *subject);
 GObject*    g_object_ref		   (GObject	   *object);
 void	    g_object_unref		   (GObject	   *object);
 gpointer    g_object_get_qdata		   (GObject	   *object,
--- gobject.c.orig	Thu Oct 26 18:26:38 2000
+++ gobject.c	Fri Oct 27 15:16:41 2000
@@ -21,6 +21,8 @@
 
 #include "gobject.h"
 #include "gvaluecollector.h"
+#include "gsignal.h"
+#include "gvaluetypes.h"
 
 
 #define	DEBUG_OBJECTS
@@ -38,10 +40,17 @@
 static void	g_object_do_queue_param_changed		(GObject	*object,
 							 GParamSpec	*pspec);
 static void	g_object_do_dispatch_param_changed	(GObject	*object,
-							 GParamSpec	*pspec);
+							 GParamSpec	*pspec,
+							 GObject	*subject);
 static void	g_object_last_unref			(GObject	*object);
 static void	g_object_do_shutdown			(GObject	*object);
 static void	g_object_do_finalize			(GObject	*object);
+static void	g_object_VOID__POINTER			(GClosure* closure,
+							 guint invocation_hint,
+							 GValue* return_value,
+							 guint n_param_values,
+							 const GValue* param_values,
+							 gpointer marshal_data);
 static void	g_value_object_init			(GValue		*value);
 static void	g_value_object_free_value		(GValue		*value);
 static void	g_value_object_copy_value		(const GValue	*src_value,
@@ -57,11 +66,19 @@
 							 GTypeCValue	*collect_value);
 
 
+/* --- constants --- */
+enum {
+  PARAM_CHANGED,
+  LAST_SIGNAL
+};
+
+
 /* --- variables --- */
 static GQuark		 quark_param_id = 0;
 static GQuark		 quark_param_changed_queue = 0;
 static GQuark		 quark_closure_array = 0;
 static GHashTable	*param_spec_hash_table = NULL;
+static guint		 object_signals [LAST_SIGNAL];
 
 
 /* --- functions --- */
@@ -179,6 +196,9 @@
 static void
 g_object_do_class_init (GObjectClass *class)
 {
+  GClosure *closure = NULL;
+  GType param_types[] = { G_TYPE_POINTER };
+
   quark_param_id = g_quark_from_static_string ("glib-object-param-id");
   quark_param_changed_queue = g_quark_from_static_string ("glib-object-param-changed-queue");
   quark_closure_array = g_quark_from_static_string ("GObject-closure-array");
@@ -186,6 +206,15 @@
   
   class->queue_param_changed = g_object_do_queue_param_changed;
   class->dispatch_param_changed = g_object_do_dispatch_param_changed;
+
+  closure = g_signal_type_closure_new (G_TYPE_FROM_CLASS (class),
+				       G_STRUCT_OFFSET (GObjectClass,
+							dispatch_param_changed));
+  object_signals[PARAM_CHANGED] = g_signal_newv ("glib-object-param-changed-signal",
+						 G_TYPE_OBJECT, (GSignalType)0,
+						 closure, NULL, g_object_VOID__POINTER,
+						 G_TYPE_NONE, 1, param_types);
+
   class->shutdown = g_object_do_shutdown;
   class->finalize = g_object_do_finalize;
 }
@@ -338,13 +367,50 @@
   return object;
 }
 
+void
+g_object_VOID__POINTER (GClosure     *closure,
+                        guint         invocation_hint,
+                        GValue       *return_value,
+                        guint         n_param_values,
+                        const GValue *param_values,
+                        gpointer      marshal_data)
+{
+  typedef void (*GSignalFunc_VOID__POINTER) (gpointer     data1,
+                                             gpointer     arg_1,
+                                             gpointer     data2);
+  register GSignalFunc_VOID__POINTER callback;
+  register GCClosure *cc = (GCClosure*) closure;
+  register gpointer data1, data2;
+
+  g_return_if_fail (n_param_values >= 2);
+
+  if (G_CCLOSURE_SWAP_DATA (closure))
+    {
+      data1 = closure->data;
+      data2 = g_value_get_as_pointer (param_values + 0);
+    }
+  else
+    {
+      data1 = g_value_get_as_pointer (param_values + 0);
+      data2 = closure->data;
+    }
+
+  callback = (GSignalFunc_VOID__POINTER) (marshal_data ? marshal_data : cc->callback);
+  callback (data1,
+            g_value_get_as_pointer (param_values + 1),
+            data2);
+}
+
 static void
 g_object_do_dispatch_param_changed (GObject    *object,
-				    GParamSpec *pspec)
+				    GParamSpec *pspec,
+				    GObject    *subject)
 {
-/*  g_message ("NOTIFICATION: parameter `%s' changed on object `%s'",
+    g_message ("NOTIFICATION: object `%s' notified that parameter `%s' "
+	     "changed on object `%s'", 
+	     G_OBJECT_TYPE_NAME (object),
 	     pspec->name,
-	     G_OBJECT_TYPE_NAME (object));*/
+	     G_OBJECT_TYPE_NAME (subject));
 }
 
 static gboolean
@@ -368,7 +434,7 @@
 	GParamSpec *pspec = slist->data;
 	
 	slist->data = NULL;
-	class->dispatch_param_changed (object, pspec);
+	class->dispatch_param_changed (object, pspec, object);
       }
   
   g_datalist_id_set_data (&object->qdata, quark_param_changed_queue, NULL);
@@ -425,6 +491,20 @@
   class->get_param (object, PARAM_SPEC_PARAM_ID (pspec), value, pspec, trailer);
 }
 
+static void
+object_param_changed (GObject		*object,
+		      GParamSpec	*pspec)
+{
+  GValue values[2] = { { 0, } };
+
+  g_value_init (values, G_TYPE_POINTER);
+  g_value_set_pointer (values, (gpointer) object);
+  g_value_init (values+1, G_TYPE_POINTER);
+  g_value_set_pointer (values+1, (gpointer) pspec);
+
+  g_signal_emitv (values, object_signals [PARAM_CHANGED], NULL);
+}
+
 static inline void
 object_set_param (GObject     *object,
 		  GValue      *value,
@@ -440,6 +520,8 @@
   class->set_param (object, PARAM_SPEC_PARAM_ID (pspec), value, pspec, trailer);
   
   class->queue_param_changed (object, pspec);
+
+  object_param_changed (object, pspec);
 }
 
 void
@@ -724,6 +806,40 @@
 	       param_name);
   else
     G_OBJECT_GET_CLASS (object)->queue_param_changed (object, pspec);
+}
+
+guint
+g_object_notify_param_changed (GObject		*object,
+			       const gchar	*param_name,
+			       GObject		*subject)
+{
+  GParamSpec *pspec;
+  guint handler_id = 0;
+
+  g_return_val_if_fail (G_IS_OBJECT (object), 0);
+  g_return_val_if_fail (param_name != NULL, 0);
+  g_return_val_if_fail (G_IS_OBJECT (subject), 0);
+
+  pspec = g_param_spec_hash_table_lookup (param_spec_hash_table,
+					  param_name,
+					  G_OBJECT_TYPE (object),
+					  TRUE, NULL);
+  if (!pspec)
+    g_warning ("%s: object class `%s' has no parameter named `%s'",
+	       G_STRLOC,
+	       G_OBJECT_TYPE_NAME (object),
+	       param_name);
+  else
+    {
+      GObjectClass *class = G_OBJECT_GET_CLASS (object);
+      GClosure *closure = g_cclosure_new_swap (class->dispatch_param_changed,
+                                               subject, NULL);
+      handler_id = g_signal_connect_closure (object,
+                                             object_signals [PARAM_CHANGED],
+                                             closure, FALSE);
+    }
+
+  return (handler_id);
 }
 
 GObject*


[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]