GSignal convenience functions
- From: James Henstridge <james daa com au>
- To: gtk-devel-list gnome org
- Subject: GSignal convenience functions
- Date: Thu, 7 Dec 2000 21:21:58 +0800 (WST)
It seems that one of the things that is holding up use of GObject is that
it is more difficult to use the GSignal functions than the old GtkSignal
ones. To try and get things moving a bit, I put together a patch that
adds g_signal_new, g_signal_emit, g_signal_emitv and
g_signal_connect_cclosure functions that make signals more convenient to
use from C.
I have done a little testing of these functions, and they seem to work
well. One bit of ugly code is putting the instance variable in the GValue
array. At the moment, I misuse the collect_value function for the type
(if it is available) to set the value, or just set it as a G_TYPE_POINTER
value. This could probably be cleaned up a bit more.
We may want to change the name of g_signal_connect_cclosure
though. Alternatively, with a few #defines, we could provide APIs more
similar to gtk_signal_connect, _after, _object and _object_after in terms
of connect_cclosure.
There are probably a few problems with this patch, but it is probably a
good start for these functions.
James.
Index: gsignal.c
===================================================================
RCS file: /cvs/gnome/glib/gobject/gsignal.c,v
retrieving revision 1.13
diff -u -r1.13 gsignal.c
--- gsignal.c 2000/11/29 12:34:14 1.13
+++ gsignal.c 2000/12/07 13:05:56
@@ -24,6 +24,8 @@
#include "gsignal.h"
#include "gbsearcharray.h"
+#include "gvaluetypes.h"
+#include "gvaluecollector.h"
/* pre allocation configurations
@@ -965,6 +967,56 @@
return signal_id;
}
+guint
+g_signal_new (const gchar *signal_name,
+ GType itype,
+ GSignalFlags signal_flags,
+ guint function_offset,
+ GSignalAccumulator accumulator,
+ GSignalCMarshaller c_marshaller,
+ GType return_type,
+ guint n_params,
+ ...)
+{
+ GClosure *class_closure = NULL;
+ GType *params;
+ guint i;
+ va_list args;
+ guint signal_id;
+
+ if (function_offset != 0)
+ class_closure = g_signal_type_closure_new (itype, function_offset);
+
+ if (n_params > 0)
+ {
+ params = g_new (GType, n_params);
+
+ va_start (args, n_params);
+
+ for (i = 0; i < n_params; i++)
+ params[i] = va_arg (args, GType);
+
+ va_end (args);
+ }
+ else
+ params = NULL;
+
+ signal_id = g_signal_newv (signal_name,
+ itype,
+ signal_flags,
+ class_closure,
+ accumulator,
+ c_marshaller,
+ return_type,
+ n_params,
+ params);
+
+ g_free (params);
+
+ return signal_id;
+}
+
+
static void
signal_destroy_R (SignalNode *signal_node)
{
@@ -1047,6 +1099,29 @@
return handler_id;
}
+guint
+g_signal_connect_cclosure (gpointer instance,
+ gchar *signal,
+ GQuark detail,
+ GCallback func,
+ gpointer user_data,
+ gboolean after,
+ gboolean swap)
+{
+ GClosure *closure;
+
+ if (swap)
+ closure = g_cclosure_new_swap (func, user_data, NULL);
+ else
+ closure = g_cclosure_new (func, user_data, NULL);
+
+ return g_signal_connect_closure_by_id (instance,
+ g_signal_lookup (signal, G_TYPE_FROM_INSTANCE (instance)),
+ detail,
+ closure,
+ after);
+}
+
void
g_signal_handler_block (gpointer instance,
guint handler_id)
@@ -1408,6 +1483,171 @@
G_UNLOCK (g_signal_mutex);
}
+
+static gboolean
+g_signal_collect_params (GValue *instance_and_params,
+ guint n_params,
+ GType itype,
+ const GType *param_types,
+ gpointer instance,
+ va_list var_args)
+{
+ GTypeValueTable *value_table;
+ register GValue *last_param;
+ register gboolean failed = FALSE;
+
+ /* set instance member. Misuse the collect_value method if
+ * available. Otherwise, just use G_TYPE_POINTER. */
+ value_table = g_type_value_table_peek (itype);
+ if (value_table->collect_value)
+ {
+ GType collect_type;
+ GTypeCValue collect_value;
+ gchar *error;
+
+ g_value_init (instance_and_params, itype);
+ collect_value.v_pointer = instance;
+ error = (value_table->collect_value) (instance_and_params, 0,
+ &collect_type, &collect_value);
+ if (error)
+ {
+ g_warning("g_signal_collect_params(): %s", error);
+ g_free(error);
+ failed = TRUE;
+ }
+ }
+ else
+ {
+ /* not perfect, but will work with the generated marshalers */
+ g_value_init (instance_and_params, G_TYPE_POINTER);
+ g_value_set_pointer (instance_and_params, instance);
+ }
+
+ instance_and_params++;
+ for (last_param = instance_and_params + n_params;
+ instance_and_params < last_param; instance_and_params++)
+ {
+ gchar *error;
+
+ g_value_init (instance_and_params, *(param_types++));
+ G_VALUE_COLLECT (instance_and_params, var_args, &error);
+ if (error)
+ {
+ failed = TRUE;
+ g_warning ("g_signal_collect_params(): %s", error);
+ g_free (error);
+ }
+ }
+
+ return failed;
+}
+
+void
+g_signal_emit (gpointer instance,
+ guint signal_id,
+ GQuark detail,
+ ...)
+{
+ GValue *instance_and_params;
+ GValue return_value = { 0, };
+ GSignalQuery query;
+ gboolean abort = FALSE;
+ va_list var_args;
+ guint i;
+
+ g_signal_query (signal_id, &query);
+ g_return_if_fail (query.signal_id != 0);
+
+ instance_and_params = g_new0 (GValue, query.n_params + 1);
+
+ va_start (var_args, detail);
+ abort = g_signal_collect_params (instance_and_params,
+ query.n_params,
+ query.itype,
+ query.param_types,
+ instance,
+ var_args);
+ if (!abort)
+ {
+ if (query.return_type != G_TYPE_NONE)
+ g_value_init (&return_value, query.return_type);
+
+ g_signal_emitv (instance_and_params, query.signal_id,
+ detail, &return_value);
+
+ if (query.return_type != G_TYPE_NONE)
+ {
+ gchar *error;
+ G_VALUE_LCOPY (&return_value, var_args, &error);
+ if (error)
+ {
+ g_warning("g_signal_emit(): %s", error);
+ g_free(error);
+ }
+ g_value_unset (&return_value);
+ }
+ }
+ va_end (var_args);
+
+ for (i = 0; i <= query.n_params; i++)
+ g_value_unset (instance_and_params + i);
+ g_free (instance_and_params);
+}
+
+void
+g_signal_emit_by_name (gpointer instance,
+ gchar *name,
+ GQuark detail,
+ ...)
+{
+ GValue *instance_and_params;
+ GValue return_value = { 0, };
+ GSignalQuery query;
+ gboolean abort = FALSE;
+ va_list var_args;
+ guint i;
+
+ g_signal_query (g_signal_lookup (name, G_TYPE_FROM_INSTANCE(instance)),
+ &query);
+ g_return_if_fail (query.signal_id != 0);
+
+ instance_and_params = g_new0 (GValue, query.n_params + 1);
+
+ va_start (var_args, detail);
+ abort = g_signal_collect_params (instance_and_params,
+ query.n_params,
+ query.itype,
+ query.param_types,
+ instance,
+ var_args);
+ if (!abort)
+ {
+ if (query.return_type != G_TYPE_NONE)
+ g_value_init (&return_value, query.return_type);
+
+ g_signal_emitv (instance_and_params, query.signal_id,
+ detail, &return_value);
+
+ if (query.return_type != G_TYPE_NONE)
+ {
+ gchar *error;
+
+ G_VALUE_LCOPY (&return_value, var_args, &error);
+ if (error)
+ {
+ g_warning("g_signal_emit(): %s", error);
+ g_free(error);
+ }
+ g_value_unset (&return_value);
+ }
+ }
+ va_end (var_args);
+
+ for (i = 0; i <= query.n_params; i++)
+ g_value_unset (instance_and_params + i);
+ g_free (instance_and_params);
+}
+
static void
signal_emit_R (SignalNode *node,
Index: gsignal.h
===================================================================
RCS file: /cvs/gnome/glib/gobject/gsignal.h,v
retrieving revision 1.7
diff -u -r1.7 gsignal.h
--- gsignal.h 2000/11/05 05:07:26 1.7
+++ gsignal.h 2000/12/07 13:05:56
@@ -95,10 +95,27 @@
GType return_type,
guint n_params,
GType *param_types);
+guint g_signal_new (const gchar *signal_name,
+ GType itype,
+ GSignalFlags signal_flags,
+ guint function_offset,
+ GSignalAccumulator accumulator,
+ GSignalCMarshaller c_marshaller,
+ GType return_type,
+ guint n_params,
+ ...);
void g_signal_emitv (const GValue *instance_and_params,
guint signal_id,
GQuark detail,
GValue *return_value);
+void g_signal_emit (gpointer instance,
+ guint signal_id,
+ GQuark detail,
+ ...);
+void g_signal_emit_by_name (gpointer instance,
+ gchar *signal,
+ GQuark detail,
+ ...);
guint g_signal_lookup (const gchar *name,
GType itype);
gchar* g_signal_name (guint signal_id);
@@ -127,6 +144,13 @@
GQuark detail,
GClosure *closure,
gboolean after);
+guint g_signal_connect_cclosure (gpointer instance,
+ gchar *name,
+ GQuark detail,
+ GCallback func,
+ gpointer user_data,
+ gboolean after,
+ gboolean swap);
void g_signal_handler_block (gpointer instance,
guint handler_id);
void g_signal_handler_unblock (gpointer instance,
[
Date Prev][
Date Next] [
Thread Prev][
Thread Next]
[
Thread Index]
[
Date Index]
[
Author Index]