/* GTK - The GIMP Toolkit * Copyright (C) 1995-1997 Peter Mattis, Spencer Kimball and Josh MacDonald * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the * Free Software Foundation, Inc., 59 Temple Place - Suite 330, * Boston, MA 02111-1307, USA. */ #include "gtksignal.h" #include "gtkargcollector.c" #include "gtkmarshal.c" /* the real parameter limit is of course given by GSignal, bu we need * an upper limit for the implementations. so this should be adjusted * with any future changes on the GSignal side of things. */ #define SIGNAL_MAX_PARAMS 12 /* --- functions --- */ guint gtk_signal_newv (const gchar *name, GtkSignalRunType signal_flags, GtkType object_type, guint function_offset, GtkSignalMarshaller marshaller, GtkType return_val, guint n_params, GtkType *params) { GClosure *closure; g_return_val_if_fail (n_params < SIGNAL_MAX_PARAMS, 0); closure = g_signal_type_closure_new (object_type, function_offset); return g_signal_newv (name, object_type, signal_flags, closure, NULL, marshaller, return_val, n_params, params); } guint gtk_signal_new (const gchar *name, GtkSignalRunType signal_flags, GtkType object_type, guint function_offset, GtkSignalMarshaller marshaller, GtkType return_val, guint n_params, ...) { GtkType *params; guint signal_id; if (n_params) { va_list args; guint i; params = g_new (GtkType, n_params); va_start (args, n_params); for (i = 0; i < n_params; i++) params[i] = va_arg (args, GtkType); va_end (args); } else params = NULL; signal_id = gtk_signal_newv (name, signal_flags, object_type, function_offset, marshaller, return_val, n_params, params); g_free (params); return signal_id; } void gtk_signal_emit_stop_by_name (GtkObject *object, const gchar *name) { g_return_if_fail (GTK_IS_OBJECT (object)); g_signal_stop_emission (object, g_signal_lookup (name, G_OBJECT_TYPE (object)), 0); } void gtk_signal_connect_object_while_alive (GtkObject *object, const gchar *signal, GtkSignalFunc func, GtkObject *alive_object) { g_return_if_fail (GTK_IS_OBJECT (object)); g_signal_connect_closure (object, g_signal_lookup (signal, G_OBJECT_TYPE (object)), 0, g_cclosure_new_object_swap (func, alive_object), FALSE); } void gtk_signal_connect_while_alive (GtkObject *object, const gchar *signal, GtkSignalFunc func, gpointer func_data, GtkObject *alive_object) { GClosure *closure; g_return_if_fail (GTK_IS_OBJECT (object)); closure = g_cclosure_new (func, func_data, NULL); g_object_watch_closure (G_OBJECT (alive_object), closure); g_signal_connect_closure (object, g_signal_lookup (signal, G_OBJECT_TYPE (object)), 0, closure, FALSE); } guint gtk_signal_connect_full (GtkObject *object, const gchar *name, GtkSignalFunc func, GtkCallbackMarshal unsupported, gpointer data, GtkDestroyNotify destroy_func, gint object_signal, gint after) { g_return_val_if_fail (GTK_IS_OBJECT (object), 0); g_return_val_if_fail (unsupported == NULL, 0); return g_signal_connect_closure (object, g_signal_lookup (name, G_OBJECT_TYPE (object)), 0, (object_signal ? g_cclosure_new_swap : g_cclosure_new) (func, data, (GClosureNotify) destroy_func), after); } void gtk_signal_compat_matched (GtkObject *object, GtkSignalFunc func, gpointer data, GSignalMatchType match, guint action) { guint id; g_return_if_fail (GTK_IS_OBJECT (object)); id = g_signal_handler_find (object, match, 0, 0, NULL, func, data); if (!id) g_warning ("unable to find signal handler for object(%p) with func(%p) and data(%p)", object, func, data); else switch (action) { case 0: g_signal_handler_disconnect (object, id); break; case 1: g_signal_handler_block (object, id); break; case 2: g_signal_handler_unblock (object, id); break; } } static inline gboolean gtk_arg_to_value (GtkArg *arg, GValue *value) { switch (G_TYPE_FUNDAMENTAL (arg->type)) { case G_TYPE_CHAR: g_value_set_char (value, GTK_VALUE_CHAR (*arg)); break; case G_TYPE_UCHAR: g_value_set_uchar (value, GTK_VALUE_UCHAR (*arg)); break; case G_TYPE_BOOLEAN: g_value_set_boolean (value, GTK_VALUE_BOOL (*arg)); break; case G_TYPE_INT: g_value_set_int (value, GTK_VALUE_INT (*arg)); break; case G_TYPE_UINT: g_value_set_uint (value, GTK_VALUE_UINT (*arg)); break; case G_TYPE_LONG: g_value_set_long (value, GTK_VALUE_LONG (*arg)); break; case G_TYPE_ULONG: g_value_set_ulong (value, GTK_VALUE_ULONG (*arg)); break; case G_TYPE_ENUM: g_value_set_enum (value, GTK_VALUE_ENUM (*arg)); break; case G_TYPE_FLAGS: g_value_set_flags (value, GTK_VALUE_FLAGS (*arg)); break; case G_TYPE_FLOAT: g_value_set_float (value, GTK_VALUE_FLOAT (*arg)); break; case G_TYPE_DOUBLE: g_value_set_double (value, GTK_VALUE_DOUBLE (*arg)); break; case G_TYPE_STRING: g_value_set_string (value, GTK_VALUE_STRING (*arg)); break; case G_TYPE_BOXED: g_value_set_boxed (value, GTK_VALUE_BOXED (*arg)); break; case G_TYPE_POINTER: g_value_set_pointer (value, GTK_VALUE_POINTER (*arg)); break; case G_TYPE_OBJECT: g_value_set_object (value, GTK_VALUE_POINTER (*arg)); break; default: return FALSE; } return TRUE; } static inline gboolean gtk_arg_static_to_value (GtkArg *arg, GValue *value) { switch (G_TYPE_FUNDAMENTAL (arg->type)) { case G_TYPE_CHAR: g_value_set_char (value, GTK_VALUE_CHAR (*arg)); break; case G_TYPE_UCHAR: g_value_set_uchar (value, GTK_VALUE_UCHAR (*arg)); break; case G_TYPE_BOOLEAN: g_value_set_boolean (value, GTK_VALUE_BOOL (*arg)); break; case G_TYPE_INT: g_value_set_int (value, GTK_VALUE_INT (*arg)); break; case G_TYPE_UINT: g_value_set_uint (value, GTK_VALUE_UINT (*arg)); break; case G_TYPE_LONG: g_value_set_long (value, GTK_VALUE_LONG (*arg)); break; case G_TYPE_ULONG: g_value_set_ulong (value, GTK_VALUE_ULONG (*arg)); break; case G_TYPE_ENUM: g_value_set_enum (value, GTK_VALUE_ENUM (*arg)); break; case G_TYPE_FLAGS: g_value_set_flags (value, GTK_VALUE_FLAGS (*arg)); break; case G_TYPE_FLOAT: g_value_set_float (value, GTK_VALUE_FLOAT (*arg)); break; case G_TYPE_DOUBLE: g_value_set_double (value, GTK_VALUE_DOUBLE (*arg)); break; case G_TYPE_STRING: g_value_set_static_string (value, GTK_VALUE_STRING (*arg)); break; case G_TYPE_BOXED: g_value_set_static_boxed (value, GTK_VALUE_BOXED (*arg)); break; case G_TYPE_POINTER: g_value_set_pointer (value, GTK_VALUE_POINTER (*arg)); break; case G_TYPE_OBJECT: g_value_set_object (value, GTK_VALUE_POINTER (*arg)); break; default: return FALSE; } return TRUE; } static inline gboolean gtk_arg_set_from_value (GtkArg *arg, GValue *value, gboolean copy_string) { switch (G_TYPE_FUNDAMENTAL (arg->type)) { case G_TYPE_CHAR: GTK_VALUE_CHAR (*arg) = g_value_get_char (value); break; case G_TYPE_UCHAR: GTK_VALUE_UCHAR (*arg) = g_value_get_uchar (value); break; case G_TYPE_BOOLEAN: GTK_VALUE_BOOL (*arg) = g_value_get_boolean (value); break; case G_TYPE_INT: GTK_VALUE_INT (*arg) = g_value_get_int (value); break; case G_TYPE_UINT: GTK_VALUE_UINT (*arg) = g_value_get_uint (value); break; case G_TYPE_LONG: GTK_VALUE_LONG (*arg) = g_value_get_long (value); break; case G_TYPE_ULONG: GTK_VALUE_ULONG (*arg) = g_value_get_ulong (value); break; case G_TYPE_ENUM: GTK_VALUE_ENUM (*arg) = g_value_get_enum (value); break; case G_TYPE_FLAGS: GTK_VALUE_FLAGS (*arg) = g_value_get_flags (value); break; case G_TYPE_FLOAT: GTK_VALUE_FLOAT (*arg) = g_value_get_float (value); break; case G_TYPE_DOUBLE: GTK_VALUE_DOUBLE (*arg) = g_value_get_double (value); break; case G_TYPE_BOXED: GTK_VALUE_BOXED (*arg) = g_value_get_boxed (value); break; case G_TYPE_POINTER: GTK_VALUE_POINTER (*arg) = g_value_get_pointer (value); break; case G_TYPE_OBJECT: GTK_VALUE_POINTER (*arg) = g_value_get_object (value); break; case G_TYPE_STRING: if (copy_string) GTK_VALUE_STRING (*arg) = g_value_dup_string (value); else GTK_VALUE_STRING (*arg) = g_value_get_string (value); break; default: return FALSE; } return TRUE; } static inline gboolean gtk_argloc_set_from_value (GtkArg *arg, GValue *value, gboolean copy_string) { switch (G_TYPE_FUNDAMENTAL (arg->type)) { case G_TYPE_CHAR: *GTK_RETLOC_CHAR (*arg) = g_value_get_char (value); break; case G_TYPE_UCHAR: *GTK_RETLOC_UCHAR (*arg) = g_value_get_uchar (value); break; case G_TYPE_BOOLEAN: *GTK_RETLOC_BOOL (*arg) = g_value_get_boolean (value); break; case G_TYPE_INT: *GTK_RETLOC_INT (*arg) = g_value_get_int (value); break; case G_TYPE_UINT: *GTK_RETLOC_UINT (*arg) = g_value_get_uint (value); break; case G_TYPE_LONG: *GTK_RETLOC_LONG (*arg) = g_value_get_long (value); break; case G_TYPE_ULONG: *GTK_RETLOC_ULONG (*arg) = g_value_get_ulong (value); break; case G_TYPE_ENUM: *GTK_RETLOC_ENUM (*arg) = g_value_get_enum (value); break; case G_TYPE_FLAGS: *GTK_RETLOC_FLAGS (*arg) = g_value_get_flags (value); break; case G_TYPE_FLOAT: *GTK_RETLOC_FLOAT (*arg) = g_value_get_float (value); break; case G_TYPE_DOUBLE: *GTK_RETLOC_DOUBLE (*arg) = g_value_get_double (value); break; case G_TYPE_BOXED: *GTK_RETLOC_BOXED (*arg) = g_value_get_boxed (value); break; case G_TYPE_POINTER: *GTK_RETLOC_POINTER (*arg) = g_value_get_pointer (value); break; case G_TYPE_OBJECT: *GTK_RETLOC_POINTER (*arg) = g_value_get_object (value); break; case G_TYPE_STRING: if (copy_string) *GTK_RETLOC_STRING (*arg) = g_value_dup_string (value); else *GTK_RETLOC_STRING (*arg) = g_value_get_string (value); break; default: return FALSE; } return TRUE; } void gtk_signal_emitv (GtkObject *object, guint signal_id, GtkArg *args) { GSignalQuery query; GValue params[SIGNAL_MAX_PARAMS + 1] = { { 0, }, }; GValue rvalue = { 0, }; guint i; g_return_if_fail (GTK_IS_OBJECT (object)); g_signal_query (signal_id, &query); g_return_if_fail (query.signal_id != 0); g_return_if_fail (g_type_conforms_to (GTK_OBJECT_TYPE (object), query.itype)); g_return_if_fail (query.n_params < SIGNAL_MAX_PARAMS); if (query.n_params > 0) g_return_if_fail (args != NULL); g_value_init (params + 0, GTK_OBJECT_TYPE (object)); g_value_set_object (params + 0, G_OBJECT (object)); for (i = 0; i < query.n_params; i++) { GValue *value = params + 1 + i; GtkArg *arg = args + i; g_value_init (value, arg->type); if (!gtk_arg_static_to_value (arg, value)) { g_warning ("%s: failed to convert arg type `%s' to value type `%s'", G_STRLOC, g_type_name (arg->type), g_type_name (G_VALUE_TYPE (value))); return; } } if (query.return_type != G_TYPE_NONE) g_value_init (&rvalue, query.return_type); g_signal_emitv (params, signal_id, 0, &rvalue); if (query.return_type != G_TYPE_NONE) { gtk_argloc_set_from_value (args + query.n_params, &rvalue, TRUE); g_value_unset (&rvalue); } for (i = 0; i < query.n_params; i++) g_value_unset (params + 1 + i); g_value_unset (params + 0); } static gboolean gtk_signal_collect_args (GtkArg *args, guint n_args, const GtkType *arg_types, GtkType return_type, va_list var_args) { register GtkArg *last_arg; register gboolean failed = FALSE; for (last_arg = args + n_args; args < last_arg; args++) { register gchar *error; args->name = NULL; args->type = *(arg_types++); GTK_ARG_COLLECT_VALUE (args, var_args, error); if (error) { failed = TRUE; g_warning ("gtk_signal_collect_args(): %s", error); g_free (error); } } args->type = return_type; args->name = NULL; return_type = GTK_FUNDAMENTAL_TYPE (return_type); if (return_type != G_TYPE_NONE) { if (return_type != 0) /* FIXME: check for IS_ARG */ { GTK_VALUE_POINTER (*args) = va_arg (var_args, gpointer); if (GTK_VALUE_POINTER (*args) == NULL) { failed = TRUE; g_warning ("gtk_signal_collect_args(): invalid NULL pointer for return argument type `%s'", gtk_type_name (args->type)); } } else { failed = TRUE; g_warning ("gtk_signal_collect_args(): unsupported return argument type `%s'", gtk_type_name (args->type)); } } else GTK_VALUE_POINTER (*args) = NULL; return failed; } void gtk_signal_emit (GtkObject *object, guint signal_id, ...) { GtkArg args[SIGNAL_MAX_PARAMS + 1]; GSignalQuery query; gboolean abort; va_list var_args; g_return_if_fail (GTK_IS_OBJECT (object)); g_signal_query (signal_id, &query); g_return_if_fail (query.signal_id != 0); g_return_if_fail (query.n_params < SIGNAL_MAX_PARAMS); va_start (var_args, signal_id); abort = gtk_signal_collect_args (args, query.n_params, query.param_types, query.return_type, var_args); va_end (var_args); if (!abort) gtk_signal_emitv (object, signal_id, args); } void gtk_signal_emit_by_name (GtkObject *object, const gchar *name, ...) { GtkArg args[SIGNAL_MAX_PARAMS + 1]; GSignalQuery query; gboolean abort; va_list var_args; g_return_if_fail (GTK_IS_OBJECT (object)); g_return_if_fail (name != NULL); g_signal_query (g_signal_lookup (name, GTK_OBJECT_TYPE (object)), &query); g_return_if_fail (query.signal_id != 0); g_return_if_fail (query.n_params < SIGNAL_MAX_PARAMS); va_start (var_args, name); abort = gtk_signal_collect_args (args, query.n_params, query.param_types, query.return_type, var_args); va_end (var_args); if (!abort) gtk_signal_emitv (object, query.signal_id, args); } void gtk_signal_emitv_by_name (GtkObject *object, const gchar *name, GtkArg *args) { g_return_if_fail (GTK_IS_OBJECT (object)); gtk_signal_emitv (object, g_signal_lookup (name, GTK_OBJECT_TYPE (object)), args); }