+Thu Mar 8 16:23:34 2001 Tim Janik <timj@gtk.org>
+
+ * ghook.[hc]: destruction cleanup. there's one
+ ->finalize_hook member in the hooklist now that gets
+ called when a hook should be destroyed, that's it.
+ that function is guarranteed to be called only when
+ all ref_counts to the hook vanished, thus also when
+ the hook is not in call.
+
2001-03-08 Sebastian Wilhelmi <wilhelmi@ira.uka.de>
* configure.in (FLAG_DOES_NOT_WORK): Fix typo and thus bug #51862.
+Thu Mar 8 16:23:34 2001 Tim Janik <timj@gtk.org>
+
+ * ghook.[hc]: destruction cleanup. there's one
+ ->finalize_hook member in the hooklist now that gets
+ called when a hook should be destroyed, that's it.
+ that function is guarranteed to be called only when
+ all ref_counts to the hook vanished, thus also when
+ the hook is not in call.
+
2001-03-08 Sebastian Wilhelmi <wilhelmi@ira.uka.de>
* configure.in (FLAG_DOES_NOT_WORK): Fix typo and thus bug #51862.
+Thu Mar 8 16:23:34 2001 Tim Janik <timj@gtk.org>
+
+ * ghook.[hc]: destruction cleanup. there's one
+ ->finalize_hook member in the hooklist now that gets
+ called when a hook should be destroyed, that's it.
+ that function is guarranteed to be called only when
+ all ref_counts to the hook vanished, thus also when
+ the hook is not in call.
+
2001-03-08 Sebastian Wilhelmi <wilhelmi@ira.uka.de>
* configure.in (FLAG_DOES_NOT_WORK): Fix typo and thus bug #51862.
+Thu Mar 8 16:23:34 2001 Tim Janik <timj@gtk.org>
+
+ * ghook.[hc]: destruction cleanup. there's one
+ ->finalize_hook member in the hooklist now that gets
+ called when a hook should be destroyed, that's it.
+ that function is guarranteed to be called only when
+ all ref_counts to the hook vanished, thus also when
+ the hook is not in call.
+
2001-03-08 Sebastian Wilhelmi <wilhelmi@ira.uka.de>
* configure.in (FLAG_DOES_NOT_WORK): Fix typo and thus bug #51862.
+Thu Mar 8 16:23:34 2001 Tim Janik <timj@gtk.org>
+
+ * ghook.[hc]: destruction cleanup. there's one
+ ->finalize_hook member in the hooklist now that gets
+ called when a hook should be destroyed, that's it.
+ that function is guarranteed to be called only when
+ all ref_counts to the hook vanished, thus also when
+ the hook is not in call.
+
2001-03-08 Sebastian Wilhelmi <wilhelmi@ira.uka.de>
* configure.in (FLAG_DOES_NOT_WORK): Fix typo and thus bug #51862.
+Thu Mar 8 16:23:34 2001 Tim Janik <timj@gtk.org>
+
+ * ghook.[hc]: destruction cleanup. there's one
+ ->finalize_hook member in the hooklist now that gets
+ called when a hook should be destroyed, that's it.
+ that function is guarranteed to be called only when
+ all ref_counts to the hook vanished, thus also when
+ the hook is not in call.
+
2001-03-08 Sebastian Wilhelmi <wilhelmi@ira.uka.de>
* configure.in (FLAG_DOES_NOT_WORK): Fix typo and thus bug #51862.
+Thu Mar 8 16:23:34 2001 Tim Janik <timj@gtk.org>
+
+ * ghook.[hc]: destruction cleanup. there's one
+ ->finalize_hook member in the hooklist now that gets
+ called when a hook should be destroyed, that's it.
+ that function is guarranteed to be called only when
+ all ref_counts to the hook vanished, thus also when
+ the hook is not in call.
+
2001-03-08 Sebastian Wilhelmi <wilhelmi@ira.uka.de>
* configure.in (FLAG_DOES_NOT_WORK): Fix typo and thus bug #51862.
+Thu Mar 8 16:23:34 2001 Tim Janik <timj@gtk.org>
+
+ * ghook.[hc]: destruction cleanup. there's one
+ ->finalize_hook member in the hooklist now that gets
+ called when a hook should be destroyed, that's it.
+ that function is guarranteed to be called only when
+ all ref_counts to the hook vanished, thus also when
+ the hook is not in call.
+
2001-03-08 Sebastian Wilhelmi <wilhelmi@ira.uka.de>
* configure.in (FLAG_DOES_NOT_WORK): Fix typo and thus bug #51862.
@s2:
@Returns:
+<!-- ##### USER_FUNCTION GHookFreeFunc ##### -->
+<para>
+
+</para>
+
+@hook_list:
+@hook:
+
+<!-- ##### MACRO G_HOOK_DEFERRED_DESTROY ##### -->
+<para>
+
+</para>
+
+
<!-- ##### MACRO access ##### -->
<para>
@is_setup:
@hooks:
@hook_memchunk:
-@hook_free:
-@hook_destroy:
+@finalize_hook:
<!-- ##### STRUCT GHook ##### -->
<para>
</para>
@hook:
+@marshal_data:
+<!-- # Unused Parameters # -->
@data:
</para>
@hook:
-@data:
+@marshal_data:
@Returns:
-
-
-<!-- ##### USER_FUNCTION GHookFreeFunc ##### -->
-<para>
-
-</para>
-
-@hook_list:
-@hook:
-
-
-<!-- ##### MACRO G_HOOK_DEFERRED_DESTROY ##### -->
-<para>
-
-</para>
-
+<!-- # Unused Parameters # -->
+@data:
<!-- ##### FUNCTION g_hook_list_init ##### -->
@hook_list: a #GHookList.
@may_recurse:
@marshaller:
+@marshal_data:
+<!-- # Unused Parameters # -->
@data:
@hook_list: a #GHookList.
@may_recurse:
@marshaller:
+@marshal_data:
+<!-- # Unused Parameters # -->
@data:
Portable way to copy <type>va_list</type> variables.
</para>
+<!-- # Unused Parameters # -->
@ap1: the <type>va_list</type> variable to place a copy of @ap2 in.
@ap2: a <type>va_list</type>.
+<!-- ##### FUNCTION g_param_spec_string_c ##### -->
+<para>
+
+</para>
+
+@name:
+@nick:
+@blurb:
+@default_value:
+@flags:
+@Returns:
+
+<!-- ##### FUNCTION g_signal_add_emission_hook_full ##### -->
+<para>
+
+</para>
+
+@signal_id:
+@closure:
+@Returns:
+
<!-- ##### FUNCTION g_type_value_is_a ##### -->
<para>
Determines if @value is a #GValue whose type conforms to @type.
@ihint: Signal invokation hint, see #GSignalInvocationHint.
@return_accu: Accumulator to collect callback return values in, this
is the return value of the current signal emission.
-@return_value: The return value of the most recent callback function.
+@handler_return:
+@data:
@Returns: The accumulator function returns whether the signal emission
should be aborted. Returning %FALSE means to abort the
current emission and %TRUE is returned for continuation.
+<!-- # Unused Parameters # -->
+@return_value: The return value of the most recent callback function.
<!-- ##### TYPEDEF GSignalCMarshaller ##### -->
@ihint:
@n_param_values:
@param_values:
+@data:
@Returns:
<!-- # Unused Parameters # -->
@signal_id:
@signal_flags:
@class_offset:
@accumulator:
+@accu_data:
@c_marshaller:
@return_type:
@n_params:
@signal_flags:
@class_closure:
@accumulator:
+@accu_data:
@c_marshaller:
@return_type:
@n_params:
@signal_flags:
@class_closure:
@accumulator:
+@accu_data:
@c_marshaller:
@return_type:
@n_params:
@detail:
-<!-- ##### FUNCTION g_signal_add_emission_hook_full ##### -->
-<para>
-
-</para>
-
-@signal_id:
-@closure:
-@Returns:
-
-
<!-- ##### FUNCTION g_signal_remove_emission_hook ##### -->
<para>
@Returns:
-<!-- ##### FUNCTION g_param_spec_string_c ##### -->
-<para>
-
-</para>
-
-@name:
-@nick:
-@blurb:
-@default_value:
-@flags:
-@Returns:
-
-
<!-- ##### FUNCTION g_param_spec_boxed ##### -->
<para>
@G_TYPE_RESERVED_BSE_LAST: Last fundamental type ID reserved for BSE.
@G_TYPE_RESERVED_LAST_FUNDAMENTAL: Last reserved fundamental type ID.
@G_TYPE_CLOSURE:
+@G_TYPE_VALUE:
@G_TYPE_VALUE_ARRAY:
@G_TYPE_PARAM_CHAR: Identifier for the "#GParamSpecChar" type.
@G_TYPE_PARAM_UCHAR: Identifier for the "#GParamSpecUChar" type.
/* --- functions --- */
+static void
+default_finalize_hook (GHookList *hook_list,
+ GHook *hook)
+{
+ GDestroyNotify destroy = hook->destroy;
+
+ if (destroy)
+ {
+ hook->destroy = NULL;
+ destroy (hook->data);
+ }
+}
+
void
g_hook_list_init (GHookList *hook_list,
guint hook_size)
{
g_return_if_fail (hook_list != NULL);
g_return_if_fail (hook_size >= sizeof (GHook));
+ g_return_if_fail (hook_size < 65536);
hook_list->seq_id = 1;
hook_list->hook_size = hook_size;
hook_size,
hook_size * G_HOOKS_PREALLOC,
G_ALLOC_AND_FREE);
- hook_list->hook_free = NULL;
- hook_list->hook_destroy = NULL;
+ hook_list->finalize_hook = default_finalize_hook;
}
void
hook = tmp;
}
while (hook);
+ if (hook_list->hook_memchunk)
+ g_warning (G_STRLOC ": failed to clear hooklist, unconsolidated references on hooks left");
}
}
g_return_if_fail (hook_list->is_setup);
g_return_if_fail (hook != NULL);
g_return_if_fail (G_HOOK_IS_UNLINKED (hook));
+ g_return_if_fail (!G_HOOK_IN_CALL (hook));
- if (hook_list->hook_free)
- hook_list->hook_free (hook_list, hook);
-
+ hook_list->finalize_hook (hook_list, hook);
g_chunk_free (hook, hook_list->hook_memchunk);
}
{
g_return_if_fail (hook_list != NULL);
g_return_if_fail (hook != NULL);
-
+
+ hook->flags &= ~G_HOOK_FLAG_ACTIVE;
if (hook->hook_id)
{
hook->hook_id = 0;
- hook->flags &= ~G_HOOK_FLAG_ACTIVE;
- if (hook_list->hook_destroy)
- {
- if (hook_list->hook_destroy != G_HOOK_DEFERRED_DESTROY)
- hook_list->hook_destroy (hook_list, hook);
- }
- else if (hook->destroy)
- {
- hook->destroy (hook->data);
- hook->data = NULL;
- hook->func = NULL;
- hook->destroy = NULL;
- }
g_hook_unref (hook_list, hook); /* counterpart to g_hook_insert_before */
}
}
{
g_return_if_fail (hook->hook_id == 0);
g_return_if_fail (!G_HOOK_IN_CALL (hook));
-
+
if (hook->prev)
hook->prev->next = hook->next;
else
g_return_if_fail (hook_list->is_setup);
g_return_if_fail (hook != NULL);
g_return_if_fail (G_HOOK_IS_UNLINKED (hook));
- g_return_if_fail (hook->func != NULL);
+ g_return_if_fail (hook->ref_count == 0);
hook->hook_id = hook_list->seq_id++;
hook->ref_count = 1; /* counterpart to g_hook_destroy_link */
G_BEGIN_DECLS
+
+/* --- typedefs --- */
typedef struct _GHook GHook;
typedef struct _GHookList GHookList;
typedef gboolean (*GHookFindFunc) (GHook *hook,
gpointer data);
typedef void (*GHookMarshaller) (GHook *hook,
- gpointer data);
+ gpointer marshal_data);
typedef gboolean (*GHookCheckMarshaller) (GHook *hook,
- gpointer data);
+ gpointer marshal_data);
typedef void (*GHookFunc) (gpointer data);
typedef gboolean (*GHookCheckFunc) (gpointer data);
-typedef void (*GHookFreeFunc) (GHookList *hook_list,
+typedef void (*GHookFinalizeFunc) (GHookList *hook_list,
GHook *hook);
-
-/* Callback maintenance functions
- */
-#define G_HOOK_FLAG_USER_SHIFT (4)
typedef enum
{
- G_HOOK_FLAG_ACTIVE = 1 << 0,
- G_HOOK_FLAG_IN_CALL = 1 << 1,
- G_HOOK_FLAG_MASK = 0x0f
+ G_HOOK_FLAG_ACTIVE = 1 << 0,
+ G_HOOK_FLAG_IN_CALL = 1 << 1,
+ G_HOOK_FLAG_MASK = 0x0f
} GHookFlagMask;
+#define G_HOOK_FLAG_USER_SHIFT (4)
-#define G_HOOK_DEFERRED_DESTROY ((GHookFreeFunc) 0x01)
+/* --- structures --- */
struct _GHookList
{
- guint seq_id;
- guint hook_size;
- guint is_setup : 1;
- GHook *hooks;
- GMemChunk *hook_memchunk;
- GHookFreeFunc hook_free; /* virtual function */
- GHookFreeFunc hook_destroy; /* virtual function */
+ guint seq_id;
+ guint hook_size : 16;
+ guint is_setup : 1;
+ GHook *hooks;
+ GMemChunk *hook_memchunk;
+ GHookFinalizeFunc finalize_hook;
};
-
struct _GHook
{
gpointer data;
GDestroyNotify destroy;
};
-#define G_HOOK_ACTIVE(hook) ((((GHook*) hook)->flags & \
+
+/* --- macros --- */
+#define G_HOOK(hook) ((GHook*) (hook))
+#define G_HOOK_FLAGS(hook) (G_HOOK (hook)->flags)
+#define G_HOOK_ACTIVE(hook) ((G_HOOK_FLAGS (hook) & \
G_HOOK_FLAG_ACTIVE) != 0)
-#define G_HOOK_IN_CALL(hook) ((((GHook*) hook)->flags & \
+#define G_HOOK_IN_CALL(hook) ((G_HOOK_FLAGS (hook) & \
G_HOOK_FLAG_IN_CALL) != 0)
-#define G_HOOK_IS_VALID(hook) (((GHook*) hook)->hook_id != 0 && \
- G_HOOK_ACTIVE (hook))
-#define G_HOOK_IS_UNLINKED(hook) (((GHook*) hook)->next == NULL && \
- ((GHook*) hook)->prev == NULL && \
- ((GHook*) hook)->hook_id == 0 && \
- ((GHook*) hook)->ref_count == 0)
+#define G_HOOK_IS_VALID(hook) (G_HOOK (hook)->hook_id != 0 && \
+ (G_HOOK_FLAGS (hook) & \
+ G_HOOK_FLAG_ACTIVE))
+#define G_HOOK_IS_UNLINKED(hook) (G_HOOK (hook)->next == NULL && \
+ G_HOOK (hook)->prev == NULL && \
+ G_HOOK (hook)->hook_id == 0 && \
+ G_HOOK (hook)->ref_count == 0)
+
+/* --- prototypes --- */
+/* callback mainenance functions */
void g_hook_list_init (GHookList *hook_list,
guint hook_size);
void g_hook_list_clear (GHookList *hook_list);
GHook* g_hook_next_valid (GHookList *hook_list,
GHook *hook,
gboolean may_be_in_call);
-
/* GHookCompareFunc implementation to insert hooks sorted by their id */
gint g_hook_compare_ids (GHook *new_hook,
GHook *sibling);
-
/* convenience macros */
#define g_hook_append( hook_list, hook ) \
g_hook_insert_before ((hook_list), NULL, (hook))
-
/* invoke all valid hooks with the (*GHookFunc) signature.
*/
void g_hook_list_invoke (GHookList *hook_list,
void g_hook_list_marshal (GHookList *hook_list,
gboolean may_recurse,
GHookMarshaller marshaller,
- gpointer data);
+ gpointer marshal_data);
void g_hook_list_marshal_check (GHookList *hook_list,
gboolean may_recurse,
GHookCheckMarshaller marshaller,
- gpointer data);
+ gpointer marshal_data);
G_END_DECLS
/* --- functions --- */
+static void
+default_finalize_hook (GHookList *hook_list,
+ GHook *hook)
+{
+ GDestroyNotify destroy = hook->destroy;
+
+ if (destroy)
+ {
+ hook->destroy = NULL;
+ destroy (hook->data);
+ }
+}
+
void
g_hook_list_init (GHookList *hook_list,
guint hook_size)
{
g_return_if_fail (hook_list != NULL);
g_return_if_fail (hook_size >= sizeof (GHook));
+ g_return_if_fail (hook_size < 65536);
hook_list->seq_id = 1;
hook_list->hook_size = hook_size;
hook_size,
hook_size * G_HOOKS_PREALLOC,
G_ALLOC_AND_FREE);
- hook_list->hook_free = NULL;
- hook_list->hook_destroy = NULL;
+ hook_list->finalize_hook = default_finalize_hook;
}
void
hook = tmp;
}
while (hook);
+ if (hook_list->hook_memchunk)
+ g_warning (G_STRLOC ": failed to clear hooklist, unconsolidated references on hooks left");
}
}
g_return_if_fail (hook_list->is_setup);
g_return_if_fail (hook != NULL);
g_return_if_fail (G_HOOK_IS_UNLINKED (hook));
+ g_return_if_fail (!G_HOOK_IN_CALL (hook));
- if (hook_list->hook_free)
- hook_list->hook_free (hook_list, hook);
-
+ hook_list->finalize_hook (hook_list, hook);
g_chunk_free (hook, hook_list->hook_memchunk);
}
{
g_return_if_fail (hook_list != NULL);
g_return_if_fail (hook != NULL);
-
+
+ hook->flags &= ~G_HOOK_FLAG_ACTIVE;
if (hook->hook_id)
{
hook->hook_id = 0;
- hook->flags &= ~G_HOOK_FLAG_ACTIVE;
- if (hook_list->hook_destroy)
- {
- if (hook_list->hook_destroy != G_HOOK_DEFERRED_DESTROY)
- hook_list->hook_destroy (hook_list, hook);
- }
- else if (hook->destroy)
- {
- hook->destroy (hook->data);
- hook->data = NULL;
- hook->func = NULL;
- hook->destroy = NULL;
- }
g_hook_unref (hook_list, hook); /* counterpart to g_hook_insert_before */
}
}
{
g_return_if_fail (hook->hook_id == 0);
g_return_if_fail (!G_HOOK_IN_CALL (hook));
-
+
if (hook->prev)
hook->prev->next = hook->next;
else
g_return_if_fail (hook_list->is_setup);
g_return_if_fail (hook != NULL);
g_return_if_fail (G_HOOK_IS_UNLINKED (hook));
- g_return_if_fail (hook->func != NULL);
+ g_return_if_fail (hook->ref_count == 0);
hook->hook_id = hook_list->seq_id++;
hook->ref_count = 1; /* counterpart to g_hook_destroy_link */
G_BEGIN_DECLS
+
+/* --- typedefs --- */
typedef struct _GHook GHook;
typedef struct _GHookList GHookList;
typedef gboolean (*GHookFindFunc) (GHook *hook,
gpointer data);
typedef void (*GHookMarshaller) (GHook *hook,
- gpointer data);
+ gpointer marshal_data);
typedef gboolean (*GHookCheckMarshaller) (GHook *hook,
- gpointer data);
+ gpointer marshal_data);
typedef void (*GHookFunc) (gpointer data);
typedef gboolean (*GHookCheckFunc) (gpointer data);
-typedef void (*GHookFreeFunc) (GHookList *hook_list,
+typedef void (*GHookFinalizeFunc) (GHookList *hook_list,
GHook *hook);
-
-/* Callback maintenance functions
- */
-#define G_HOOK_FLAG_USER_SHIFT (4)
typedef enum
{
- G_HOOK_FLAG_ACTIVE = 1 << 0,
- G_HOOK_FLAG_IN_CALL = 1 << 1,
- G_HOOK_FLAG_MASK = 0x0f
+ G_HOOK_FLAG_ACTIVE = 1 << 0,
+ G_HOOK_FLAG_IN_CALL = 1 << 1,
+ G_HOOK_FLAG_MASK = 0x0f
} GHookFlagMask;
+#define G_HOOK_FLAG_USER_SHIFT (4)
-#define G_HOOK_DEFERRED_DESTROY ((GHookFreeFunc) 0x01)
+/* --- structures --- */
struct _GHookList
{
- guint seq_id;
- guint hook_size;
- guint is_setup : 1;
- GHook *hooks;
- GMemChunk *hook_memchunk;
- GHookFreeFunc hook_free; /* virtual function */
- GHookFreeFunc hook_destroy; /* virtual function */
+ guint seq_id;
+ guint hook_size : 16;
+ guint is_setup : 1;
+ GHook *hooks;
+ GMemChunk *hook_memchunk;
+ GHookFinalizeFunc finalize_hook;
};
-
struct _GHook
{
gpointer data;
GDestroyNotify destroy;
};
-#define G_HOOK_ACTIVE(hook) ((((GHook*) hook)->flags & \
+
+/* --- macros --- */
+#define G_HOOK(hook) ((GHook*) (hook))
+#define G_HOOK_FLAGS(hook) (G_HOOK (hook)->flags)
+#define G_HOOK_ACTIVE(hook) ((G_HOOK_FLAGS (hook) & \
G_HOOK_FLAG_ACTIVE) != 0)
-#define G_HOOK_IN_CALL(hook) ((((GHook*) hook)->flags & \
+#define G_HOOK_IN_CALL(hook) ((G_HOOK_FLAGS (hook) & \
G_HOOK_FLAG_IN_CALL) != 0)
-#define G_HOOK_IS_VALID(hook) (((GHook*) hook)->hook_id != 0 && \
- G_HOOK_ACTIVE (hook))
-#define G_HOOK_IS_UNLINKED(hook) (((GHook*) hook)->next == NULL && \
- ((GHook*) hook)->prev == NULL && \
- ((GHook*) hook)->hook_id == 0 && \
- ((GHook*) hook)->ref_count == 0)
+#define G_HOOK_IS_VALID(hook) (G_HOOK (hook)->hook_id != 0 && \
+ (G_HOOK_FLAGS (hook) & \
+ G_HOOK_FLAG_ACTIVE))
+#define G_HOOK_IS_UNLINKED(hook) (G_HOOK (hook)->next == NULL && \
+ G_HOOK (hook)->prev == NULL && \
+ G_HOOK (hook)->hook_id == 0 && \
+ G_HOOK (hook)->ref_count == 0)
+
+/* --- prototypes --- */
+/* callback mainenance functions */
void g_hook_list_init (GHookList *hook_list,
guint hook_size);
void g_hook_list_clear (GHookList *hook_list);
GHook* g_hook_next_valid (GHookList *hook_list,
GHook *hook,
gboolean may_be_in_call);
-
/* GHookCompareFunc implementation to insert hooks sorted by their id */
gint g_hook_compare_ids (GHook *new_hook,
GHook *sibling);
-
/* convenience macros */
#define g_hook_append( hook_list, hook ) \
g_hook_insert_before ((hook_list), NULL, (hook))
-
/* invoke all valid hooks with the (*GHookFunc) signature.
*/
void g_hook_list_invoke (GHookList *hook_list,
void g_hook_list_marshal (GHookList *hook_list,
gboolean may_recurse,
GHookMarshaller marshaller,
- gpointer data);
+ gpointer marshal_data);
void g_hook_list_marshal_check (GHookList *hook_list,
gboolean may_recurse,
GHookCheckMarshaller marshaller,
- gpointer data);
+ gpointer marshal_data);
G_END_DECLS
+Thu Mar 8 16:35:48 2001 Tim Janik <timj@gtk.org>
+
+ * gparamspecs.[hc]: s/g_param_spec_string_c/g_param_spec_stringc/.
+
+ * gsignal.[hc]: fixed accumulator invocation, implemented emission
+ hooks. and no, neither of these callbacks are called via a closure,
+ language bindings can wrap the accumulator and emission hook
+ interface, they already get parameters marshalled into a GValue array.
+ (g_signal_connect): removed this function as its C specific, doesn't
+ cover the swapped argument, is too close to its broken original
+ gtk_signal_connect() and creates demand for _swapped, _after and
+ _swapped_after variants <brrr>.
+ (g_signal_connectc): convenience macro to connect a C handler
+ func with data, like the old g_signal_connect() plus swapped
+ argument.
+
+ * gtype.h:
+ * gboxed.c: added G_TYPE_VALUE boxed type.
+
Wed Mar 7 19:02:51 2001 Tim Janik <timj@gtk.org>
* gtype.c (type_node_add_iface_entry_W): catch when adding an interface
}
static gpointer
+value_copy (gpointer boxed)
+{
+ const GValue *src_value = boxed;
+ GValue *dest_value = g_new0 (GValue, 1);
+
+ if (G_VALUE_TYPE (src_value))
+ {
+ g_value_init (dest_value, G_VALUE_TYPE (src_value));
+ g_value_copy (src_value, dest_value);
+ }
+ return dest_value;
+}
+
+static void
+value_free (gpointer boxed)
+{
+ GValue *value = boxed;
+
+ if (G_VALUE_TYPE (value))
+ g_value_unset (value);
+ g_free (value);
+}
+
+static gpointer
value_array_init (void)
{
return g_value_array_new (0);
TRUE);
g_assert (type == G_TYPE_CLOSURE);
+ /* boxed: G_TYPE_VALUE
+ */
+ type = g_boxed_type_register_static ("GValue",
+ (GBoxedInitFunc) NULL,
+ value_copy,
+ value_free,
+ FALSE);
+ g_assert (type == G_TYPE_VALUE);
+
/* boxed: G_TYPE_VALUE_ARRAY
*/
type = g_boxed_type_register_static ("GValueArray",
G_TYPE_FROM_CLASS (class),
G_SIGNAL_RUN_FIRST | G_SIGNAL_NO_RECURSE,
G_STRUCT_OFFSET (GObjectClass, properties_changed),
- NULL, /* accumulator */
- g_cclosure_marshal_VOID__UINT_POINTER,
+ NULL, NULL,
+ g_cclosure_marshal_VOID__UINT_POINTER,
G_TYPE_NONE,
2, G_TYPE_UINT, G_TYPE_POINTER);
gobject_signals[NOTIFY] =
G_TYPE_FROM_CLASS (class),
G_SIGNAL_RUN_FIRST | G_SIGNAL_NO_RECURSE | G_SIGNAL_DETAILED | G_SIGNAL_NO_HOOKS,
G_STRUCT_OFFSET (GObjectClass, notify),
- NULL, /* accumulator */
+ NULL, NULL,
g_cclosure_marshal_VOID__PARAM,
G_TYPE_NONE,
1, G_TYPE_PARAM);
}
GParamSpec*
-g_param_spec_string_c (const gchar *name,
- const gchar *nick,
- const gchar *blurb,
- const gchar *default_value,
- GParamFlags flags)
+g_param_spec_stringc (const gchar *name,
+ const gchar *nick,
+ const gchar *blurb,
+ const gchar *default_value,
+ GParamFlags flags)
{
GParamSpecString *sspec = g_param_spec_internal (G_TYPE_PARAM_STRING,
name,
const gchar *blurb,
const gchar *default_value,
GParamFlags flags);
-GParamSpec* g_param_spec_string_c (const gchar *name,
+GParamSpec* g_param_spec_stringc (const gchar *name,
const gchar *nick,
const gchar *blurb,
const gchar *default_value,
#include "gsignal.h"
#include "gbsearcharray.h"
#include "gvaluecollector.h"
+#include "gvaluetypes.h"
+#include "gboxed.h"
#include <string.h>
/* --- structures --- */
+typedef struct
+{
+ GSignalAccumulator func;
+ gpointer data;
+} SignalAccumulator;
struct _SignalNode
{
/* permanent portion */
GType *param_types; /* mangled with G_SIGNAL_TYPE_STATIC_SCOPE flag */
GType return_type; /* mangled with G_SIGNAL_TYPE_STATIC_SCOPE flag */
GClosure *class_closure;
- GSignalAccumulator accumulator;
+ SignalAccumulator *accumulator;
GSignalCMarshaller c_marshaller;
GHookList *emission_hooks;
};
G_UNLOCK (g_signal_mutex);
}
+static void
+signal_finalize_hook (GHookList *hook_list,
+ GHook *hook)
+{
+ GDestroyNotify destroy = hook->destroy;
+
+ if (destroy)
+ {
+ hook->destroy = NULL;
+ G_UNLOCK (g_signal_mutex);
+ destroy (hook->data);
+ G_LOCK (g_signal_mutex);
+ }
+}
+
+guint
+g_signal_add_emission_hook (guint signal_id,
+ GQuark detail,
+ GSignalEmissionHook hook_func,
+ gpointer hook_data,
+ GDestroyNotify data_destroy)
+{
+ static guint seq_hook_id = 1;
+ SignalNode *node;
+ GHook *hook;
+
+ g_return_val_if_fail (signal_id > 0, 0);
+ g_return_val_if_fail (hook_func != NULL, 0);
+
+ G_LOCK (g_signal_mutex);
+ node = LOOKUP_SIGNAL_NODE (signal_id);
+ if (!node || node->destroyed || (node->flags & G_SIGNAL_NO_HOOKS))
+ {
+ g_warning ("%s: invalid signal id `%u'", G_STRLOC, signal_id);
+ G_UNLOCK (g_signal_mutex);
+ return 0;
+ }
+ if (detail && !(node->flags & G_SIGNAL_DETAILED))
+ {
+ g_warning ("%s: signal id `%u' does not support detail (%u)", G_STRLOC, signal_id, detail);
+ G_UNLOCK (g_signal_mutex);
+ return 0;
+ }
+ if (!node->emission_hooks)
+ {
+ node->emission_hooks = g_new (GHookList, 1);
+ g_hook_list_init (node->emission_hooks, sizeof (GHook));
+ node->emission_hooks->finalize_hook = signal_finalize_hook;
+ }
+ hook = g_hook_alloc (node->emission_hooks);
+ hook->data = hook_data;
+ hook->func = hook_func;
+ hook->destroy = data_destroy;
+ node->emission_hooks->seq_id = seq_hook_id;
+ g_hook_append (node->emission_hooks, hook);
+ seq_hook_id = node->emission_hooks->seq_id;
+ G_UNLOCK (g_signal_mutex);
+
+ return hook->hook_id;
+}
+
+void
+g_signal_remove_emission_hook (guint signal_id,
+ guint hook_id)
+{
+ SignalNode *node;
+
+ g_return_if_fail (signal_id > 0);
+ g_return_if_fail (hook_id > 0);
+
+ G_LOCK (g_signal_mutex);
+ node = LOOKUP_SIGNAL_NODE (signal_id);
+ if (!node || node->destroyed)
+ g_warning ("%s: invalid signal id `%u'", G_STRLOC, signal_id);
+ else if (!node->emission_hooks || !g_hook_destroy (node->emission_hooks, hook_id))
+ g_warning ("%s: signal \"%s\" had no hook (%u) to remove", G_STRLOC, node->name, hook_id);
+ G_UNLOCK (g_signal_mutex);
+}
+
static inline guint
signal_parse_name (const gchar *name,
GType itype,
GSignalFlags signal_flags,
GClosure *class_closure,
GSignalAccumulator accumulator,
+ gpointer accu_data,
GSignalCMarshaller c_marshaller,
GType return_type,
guint n_params,
param_types = NULL;
signal_id = g_signal_newv (signal_name, itype, signal_flags,
- class_closure, accumulator, c_marshaller,
+ class_closure, accumulator, accu_data, c_marshaller,
return_type, n_params, param_types);
g_free (param_types);
GType itype,
GSignalFlags signal_flags,
guint class_offset,
- GSignalAccumulator accumulator,
+ GSignalAccumulator accumulator,
+ gpointer accu_data,
GSignalCMarshaller c_marshaller,
GType return_type,
guint n_params,
signal_id = g_signal_new_valist (signal_name, itype, signal_flags,
g_signal_type_cclosure_new (itype, class_offset),
- accumulator, c_marshaller,
+ accumulator, accu_data, c_marshaller,
return_type, n_params, args);
va_end (args);
GSignalFlags signal_flags,
GClosure *class_closure,
GSignalAccumulator accumulator,
+ gpointer accu_data,
GSignalCMarshaller c_marshaller,
GType return_type,
guint n_params,
g_return_val_if_fail (G_TYPE_IS_INSTANTIATABLE (itype) || G_TYPE_IS_INTERFACE (itype), 0);
if (n_params)
g_return_val_if_fail (param_types != NULL, 0);
- if (return_type != G_TYPE_NONE)
+ if (return_type == (G_TYPE_NONE & ~G_SIGNAL_TYPE_STATIC_SCOPE))
g_return_val_if_fail (accumulator == NULL, 0);
-
+ if (!accumulator)
+ g_return_val_if_fail (accu_data == NULL, 0);
+
name = g_strdup (signal_name);
g_strdelimit (name, G_STR_DELIMITERS ":^", '_'); // FIXME do character checks like for types
node->class_closure = class_closure ? g_closure_ref (class_closure) : NULL;
if (class_closure)
g_closure_sink (class_closure);
- node->accumulator = accumulator;
+ if (accumulator)
+ {
+ node->accumulator = g_new (SignalAccumulator, 1);
+ node->accumulator->func = accumulator;
+ node->accumulator->data = accu_data;
+ }
+ else
+ node->accumulator = NULL;
node->c_marshaller = c_marshaller;
node->emission_hooks = NULL;
if (node->c_marshaller && class_closure && G_CLOSURE_NEEDS_MARSHAL (class_closure))
g_closure_set_marshal (class_closure, node->c_marshaller);
-
G_UNLOCK (g_signal_mutex);
return signal_id;
}
G_UNLOCK (g_signal_mutex);
g_free (node.param_types);
g_closure_unref (node.class_closure);
+ g_free (node.accumulator);
if (node.emission_hooks)
{
g_hook_list_clear (node.emission_hooks);
g_warning ("%s: signal name `%s' is invalid for instance `%p'", G_STRLOC, detailed_signal, instance);
}
+static inline gboolean
+accumulate (GSignalInvocationHint *ihint,
+ GValue *return_accu,
+ GValue *handler_return,
+ SignalAccumulator *accumulator)
+{
+ gboolean continue_emission;
+
+ if (!accumulator)
+ return TRUE;
+
+ continue_emission = accumulator->func (ihint, return_accu, handler_return, accumulator->data);
+ g_value_reset (handler_return);
+
+ return continue_emission;
+}
+
static gboolean
signal_emit_R (SignalNode *node,
GQuark detail,
gpointer instance,
- GValue *return_value,
+ GValue *emission_return,
const GValue *instance_and_params)
{
EmissionState emission_state = 0;
- GSignalAccumulator accumulator;
+ SignalAccumulator *accumulator;
GSignalInvocationHint ihint;
GClosure *class_closure;
HandlerList *hlist;
Handler *handler_list = NULL;
- GValue accu = { 0, };
- gboolean accu_used = FALSE;
+ GValue *return_accu, accu = { 0, };
guint signal_id = node->signal_id;
gboolean return_value_altered = FALSE;
ihint.detail = detail;
accumulator = node->accumulator;
if (accumulator)
- g_value_init (&accu, node->return_type & ~G_SIGNAL_TYPE_STATIC_SCOPE);
+ {
+ g_value_init (&accu, node->return_type & ~G_SIGNAL_TYPE_STATIC_SCOPE);
+ return_accu = &accu;
+ }
+ else
+ return_accu = emission_return;
emission_push ((node->flags & G_SIGNAL_NO_RECURSE) ? &g_restart_emissions : &g_recursive_emissions,
signal_id, detail, instance, &emission_state);
class_closure = node->class_closure;
emission_state = EMISSION_RUN;
G_UNLOCK (g_signal_mutex);
- if (accumulator)
- {
- if (accu_used)
- g_value_reset (&accu);
- g_closure_invoke (class_closure,
- &accu,
- node->n_params + 1,
- instance_and_params,
- &ihint);
- if (!accumulator (&ihint, return_value, &accu) &&
- emission_state == EMISSION_RUN)
- emission_state = EMISSION_STOP;
- accu_used = TRUE;
- }
- else
- g_closure_invoke (class_closure,
- return_value,
- node->n_params + 1,
- instance_and_params,
- &ihint);
+ g_closure_invoke (class_closure,
+ return_accu,
+ node->n_params + 1,
+ instance_and_params,
+ &ihint);
+ if (!accumulate (&ihint, emission_return, &accu, accumulator) &&
+ emission_state == EMISSION_RUN)
+ emission_state = EMISSION_STOP;
G_LOCK (g_signal_mutex);
return_value_altered = TRUE;
if (node->emission_hooks)
{
- emission_state = EMISSION_HOOK;
+ gboolean need_destroy, was_in_call, may_recurse = TRUE;
+ GHook *hook;
- G_UNLOCK (g_signal_mutex);
- g_print ("emission_hooks()\n");
- G_LOCK (g_signal_mutex);
+ emission_state = EMISSION_HOOK;
+ hook = g_hook_first_valid (node->emission_hooks, may_recurse);
+ while (hook)
+ {
+ GQuark hook_detail = GPOINTER_TO_UINT (hook->func);
+
+ if (!hook_detail || hook_detail == detail)
+ {
+ GSignalEmissionHook hook_func = hook->func;
+
+ was_in_call = G_HOOK_IN_CALL (hook);
+ hook->flags |= G_HOOK_FLAG_IN_CALL;
+ G_UNLOCK (g_signal_mutex);
+ need_destroy = !hook_func (&ihint, node->n_params + 1, instance_and_params, hook->data);
+ G_LOCK (g_signal_mutex);
+ if (!was_in_call)
+ hook->flags &= ~G_HOOK_FLAG_IN_CALL;
+ if (need_destroy)
+ g_hook_destroy_link (node->emission_hooks, hook);
+ }
+ hook = g_hook_next_valid (node->emission_hooks, hook, may_recurse);
+ }
if (emission_state == EMISSION_RESTART)
goto EMIT_RESTART;
else if (!handler->block_count && (!handler->detail || handler->detail == detail))
{
G_UNLOCK (g_signal_mutex);
- if (accumulator)
- {
- if (accu_used)
- g_value_reset (&accu);
- g_closure_invoke (handler->closure,
- &accu,
- node->n_params + 1,
- instance_and_params,
- &ihint);
- if (!accumulator (&ihint, return_value, &accu) &&
- emission_state == EMISSION_RUN)
- emission_state = EMISSION_STOP;
- accu_used = TRUE;
- }
- else
- g_closure_invoke (handler->closure,
- return_value,
- node->n_params + 1,
- instance_and_params,
- &ihint);
+ g_closure_invoke (handler->closure,
+ return_accu,
+ node->n_params + 1,
+ instance_and_params,
+ &ihint);
+ if (!accumulate (&ihint, emission_return, &accu, accumulator) &&
+ emission_state == EMISSION_RUN)
+ emission_state = EMISSION_STOP;
G_LOCK (g_signal_mutex);
return_value_altered = TRUE;
emission_state = EMISSION_RUN;
G_UNLOCK (g_signal_mutex);
- if (accumulator)
- {
- if (accu_used)
- g_value_reset (&accu);
- g_closure_invoke (class_closure,
- &accu,
- node->n_params + 1,
- instance_and_params,
- &ihint);
- if (!accumulator (&ihint, return_value, &accu) &&
- emission_state == EMISSION_RUN)
- emission_state = EMISSION_STOP;
- accu_used = TRUE;
- }
- else
- g_closure_invoke (class_closure,
- return_value,
- node->n_params + 1,
- instance_and_params,
- &ihint);
+ g_closure_invoke (class_closure,
+ return_accu,
+ node->n_params + 1,
+ instance_and_params,
+ &ihint);
+ if (!accumulate (&ihint, emission_return, &accu, accumulator) &&
+ emission_state == EMISSION_RUN)
+ emission_state = EMISSION_STOP;
G_LOCK (g_signal_mutex);
return_value_altered = TRUE;
if (handler->after && !handler->block_count && (!handler->detail || handler->detail == detail))
{
G_UNLOCK (g_signal_mutex);
- if (accumulator)
- {
- if (accu_used)
- g_value_reset (&accu);
- g_closure_invoke (handler->closure,
- &accu,
- node->n_params + 1,
- instance_and_params,
- &ihint);
- if (!accumulator (&ihint, return_value, &accu) &&
- emission_state == EMISSION_RUN)
- emission_state = EMISSION_STOP;
- accu_used = TRUE;
- }
- else
- g_closure_invoke (handler->closure,
- return_value,
- node->n_params + 1,
- instance_and_params,
- &ihint);
+ g_closure_invoke (handler->closure,
+ return_accu,
+ node->n_params + 1,
+ instance_and_params,
+ &ihint);
+ if (!accumulate (&ihint, emission_return, &accu, accumulator) &&
+ emission_state == EMISSION_RUN)
+ emission_state = EMISSION_STOP;
G_LOCK (g_signal_mutex);
return_value_altered = TRUE;
emission_state = EMISSION_STOP;
G_UNLOCK (g_signal_mutex);
- if (node->return_type != G_TYPE_NONE)
+ if (node->return_type != G_TYPE_NONE && !accumulator)
{
- if (!accumulator)
- {
- g_value_init (&accu, node->return_type & ~G_SIGNAL_TYPE_STATIC_SCOPE);
- need_unset = TRUE;
- }
- else if (accu_used)
- g_value_reset (&accu);
+ g_value_init (&accu, node->return_type & ~G_SIGNAL_TYPE_STATIC_SCOPE);
+ need_unset = TRUE;
}
g_closure_invoke (class_closure,
node->return_type != G_TYPE_NONE ? &accu : NULL,
emission_pop ((node->flags & G_SIGNAL_NO_RECURSE) ? &g_restart_emissions : &g_recursive_emissions, &emission_state);
if (accumulator)
g_value_unset (&accu);
-
+
return return_value_altered;
}
/* --- compile standard marshallers --- */
-#include "gvaluetypes.h"
#include "gobject.h"
#include "genums.h"
-#include "gboxed.h"
#include "gmarshal.c"
typedef GClosureMarshal GSignalCMarshaller;
typedef gboolean (*GSignalEmissionHook) (GSignalInvocationHint *ihint,
guint n_param_values,
- const GValue *param_values);
+ const GValue *param_values,
+ gpointer data);
typedef gboolean (*GSignalAccumulator) (GSignalInvocationHint *ihint,
GValue *return_accu,
- const GValue *return_value);
+ const GValue *handler_return,
+ gpointer data);
/* --- run & match types --- */
GType itype,
GSignalFlags signal_flags,
GClosure *class_closure,
- GSignalAccumulator accumulator,
+ GSignalAccumulator accumulator,
+ gpointer accu_data,
GSignalCMarshaller c_marshaller,
GType return_type,
guint n_params,
GType itype,
GSignalFlags signal_flags,
GClosure *class_closure,
- GSignalAccumulator accumulator,
+ GSignalAccumulator accumulator,
+ gpointer accu_data,
GSignalCMarshaller c_marshaller,
GType return_type,
guint n_params,
GType itype,
GSignalFlags signal_flags,
guint class_offset,
- GSignalAccumulator accumulator,
+ GSignalAccumulator accumulator,
+ gpointer accu_data,
GSignalCMarshaller c_marshaller,
GType return_type,
guint n_params,
GSignalQuery *query);
guint* g_signal_list_ids (GType itype,
guint *n_ids);
+gboolean g_signal_parse_name (const gchar *detailed_signal,
+ GType itype,
+ guint *signal_id_p,
+ GQuark *detail_p,
+ gboolean force_detail_quark);
/* --- signal emissions --- */
-void g_signal_stop_emission (gpointer instance,
- guint signal_id,
- GQuark detail);
-guint g_signal_add_emission_hook_full (guint signal_id,
- GClosure *closure);
-void g_signal_remove_emission_hook (guint signal_id,
- guint hook_id);
+void g_signal_stop_emission (gpointer instance,
+ guint signal_id,
+ GQuark detail);
+guint g_signal_add_emission_hook (guint signal_id,
+ GQuark quark,
+ GSignalEmissionHook hook_func,
+ gpointer hook_data,
+ GDestroyNotify data_destroy);
+void g_signal_remove_emission_hook (guint signal_id,
+ guint hook_id);
/* --- signal handlers --- */
guint signal_id,
GQuark detail,
gboolean may_be_blocked);
-#define g_signal_connect(instance, detailed_signal, c_handler, data) \
- g_signal_connect_data (instance, detailed_signal, c_handler, data, NULL, FALSE, FALSE)
guint g_signal_connect_closure_by_id (gpointer instance,
guint signal_id,
GQuark detail,
GClosure *closure,
gpointer func,
gpointer data);
-gboolean g_signal_parse_name (const gchar *detailed_signal,
- GType itype,
- guint *signal_id_p,
- GQuark *detail_p,
- gboolean force_detail_quark);
+/* --- convenience --- */
+#define g_signal_connectc(instance, detailed_signal, c_handler, data, swapped) \
+ g_signal_connect_data ((instance), (detailed_signal), (c_handler), (data), NULL, (swapped), FALSE)
+
/*< private >*/
void g_signal_handlers_destroy (gpointer instance);
void _g_signals_destroy (GType itype);
/* derived type ids */
G_TYPE_CLOSURE = G_TYPE_DERIVE_ID (G_TYPE_BOXED, 1),
- G_TYPE_VALUE_ARRAY = G_TYPE_DERIVE_ID (G_TYPE_BOXED, 2),
+ G_TYPE_VALUE = G_TYPE_DERIVE_ID (G_TYPE_BOXED, 2),
+ G_TYPE_VALUE_ARRAY = G_TYPE_DERIVE_ID (G_TYPE_BOXED, 3),
G_TYPE_PARAM_CHAR = G_TYPE_DERIVE_ID (G_TYPE_PARAM, 1),
G_TYPE_PARAM_UCHAR = G_TYPE_DERIVE_ID (G_TYPE_PARAM, 2),
G_TYPE_PARAM_BOOLEAN = G_TYPE_DERIVE_ID (G_TYPE_PARAM, 3),