static Handler* handler_find (gpointer instance,
GSignalMatchType mask,
guint signal_id,
+ GQuark detail,
GClosure *closure,
gpointer func,
gpointer data);
Handler *handler);
static inline void emission_push (Emission **emission_list_p,
guint signal_id,
+ GQuark detail,
gpointer instance,
EmissionState *state_p);
-static inline void emission_pop (Emission **emission_list_p);
+static inline void emission_pop (Emission **emission_list_p,
+ EmissionState *state_p);
static inline Emission* emission_find (Emission *emission_list,
guint signal_id,
+ GQuark detail,
gpointer instance);
static void signal_emit_R (SignalNode *node,
+ GQuark detail,
gpointer instance,
GValue *return_value,
const GValue *instance_and_params);
{
Emission *next;
guint signal_id;
+ GQuark detail;
gpointer instance;
EmissionState *state_p;
};
guint id;
Handler *next;
Handler *prev;
+ GQuark detail;
guint ref_count : 16;
#define HANDLER_MAX_REF_COUNT (1 << 16)
guint block_count : 12;
handler_find (gpointer instance,
GSignalMatchType mask,
guint signal_id,
+ GQuark detail,
GClosure *closure,
gpointer func,
gpointer data)
mask = ~mask;
for (handler = hlist ? hlist->handlers : NULL; handler; handler = handler->next)
- if (((mask & G_SIGNAL_MATCH_CLOSURE) || handler->closure == closure) &&
- ((mask & G_SIGNAL_MATCH_UNBLOCKED) || handler->block_count == 0) &&
+ if (((mask & G_SIGNAL_MATCH_DETAIL) || handler->detail == detail) &&
+ ((mask & G_SIGNAL_MATCH_CLOSURE) || handler->closure == closure) &&
((mask & G_SIGNAL_MATCH_DATA) || handler->closure->data == data) &&
+ ((mask & G_SIGNAL_MATCH_UNBLOCKED) || handler->block_count == 0) &&
((mask & G_SIGNAL_MATCH_FUNC) || (handler->closure->marshal == node->c_marshaller &&
handler->closure->meta_marshal == 0 &&
((GCClosure*) handler->closure)->callback == func)))
}
for (handler = hlist->handlers; handler; handler = handler->next)
- if (((mask & G_SIGNAL_MATCH_CLOSURE) || handler->closure == closure) &&
- ((mask & G_SIGNAL_MATCH_UNBLOCKED) || handler->block_count == 0) &&
+ if (((mask & G_SIGNAL_MATCH_DETAIL) || handler->detail == detail) &&
+ ((mask & G_SIGNAL_MATCH_CLOSURE) || handler->closure == closure) &&
((mask & G_SIGNAL_MATCH_DATA) || handler->closure->data == data) &&
+ ((mask & G_SIGNAL_MATCH_UNBLOCKED) || handler->block_count == 0) &&
((mask & G_SIGNAL_MATCH_FUNC) || (handler->closure->marshal == node->c_marshaller &&
handler->closure->meta_marshal == 0 &&
((GCClosure*) handler->closure)->callback == func)))
handler->id = handler_id++;
handler->prev = NULL;
handler->next = NULL;
+ handler->detail = 0;
handler->ref_count = 1;
handler->block_count = 0;
handler->after = after != FALSE;
static inline void
emission_push (Emission **emission_list_p,
guint signal_id,
+ GQuark detail,
gpointer instance,
EmissionState *state_p)
{
EMISSION_PRE_ALLOC);
emission->next = *emission_list_p;
emission->signal_id = signal_id;
+ emission->detail = detail;
emission->instance = instance;
emission->state_p = state_p;
*emission_list_p = emission;
}
static inline void
-emission_pop (Emission **emission_list_p)
+emission_pop (Emission **emission_list_p,
+ EmissionState *state_p)
{
- Emission *emission = *emission_list_p;
-
- *emission_list_p = emission->next;
+ Emission **loc = emission_list_p, *emission = *loc;
+
+ while (emission->state_p != state_p)
+ {
+ loc = &emission->next;
+ emission = *loc;
+ }
+ *loc = emission->next;
g_generic_node_free (&g_emission_ts, emission);
}
static inline Emission*
emission_find (Emission *emission_list,
guint signal_id,
+ GQuark detail,
gpointer instance)
{
Emission *emission;
for (emission = emission_list; emission; emission = emission->next)
- if (emission->instance == instance && emission->signal_id == signal_id)
+ if (emission->instance == instance &&
+ emission->signal_id == signal_id &&
+ emission->detail == detail)
return emission;
return NULL;
}
void
g_signal_stop_emission (gpointer instance,
- guint signal_id)
+ guint signal_id,
+ GQuark detail)
{
SignalNode *node;
G_LOCK (g_signal_mutex);
node = LOOKUP_SIGNAL_NODE (signal_id);
+ if (node && 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;
+ }
if (node && g_type_conforms_to (G_TYPE_FROM_INSTANCE (instance), node->itype))
{
Emission *emission_list = node->flags & G_SIGNAL_NO_RECURSE ? g_restart_emissions : g_recursive_emissions;
- Emission *emission = emission_find (emission_list, signal_id, instance);
+ Emission *emission = emission_find (emission_list, signal_id, detail, instance);
if (emission)
{
guint
g_signal_newv (const gchar *signal_name,
GType itype,
- GSignalType signal_flags,
+ GSignalFlags signal_flags,
GClosure *class_closure,
GSignalAccumulator accumulator,
GSignalCMarshaller c_marshaller,
node->destroyed = FALSE;
/* setup reinitializable portion */
- node->flags = signal_flags & (G_SIGNAL_RUN_FIRST |
- G_SIGNAL_RUN_LAST |
- G_SIGNAL_RUN_CLEANUP |
- G_SIGNAL_NO_RECURSE |
- G_SIGNAL_ACTION |
- G_SIGNAL_NO_HOOKS);
+ node->flags = signal_flags & G_SIGNAL_FLAGS_MASK;
node->n_params = n_params;
node->param_types = g_memdup (param_types, sizeof (GType) * n_params);
node->return_type = return_type;
guint
g_signal_connect_closure (gpointer instance,
guint signal_id,
+ GQuark detail,
GClosure *closure,
gboolean after)
{
G_LOCK (g_signal_mutex);
node = LOOKUP_SIGNAL_NODE (signal_id);
+ if (node && 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 && g_type_conforms_to (G_TYPE_FROM_INSTANCE (instance), node->itype))
{
Handler *handler = handler_new (after);
handler_id = handler->id;
+ handler->detail = detail;
handler->closure = g_closure_ref (closure);
handler_insert (signal_id, instance, handler);
if (node->c_marshaller && G_CLOSURE_NEEDS_MARSHAL (closure))
g_signal_handler_find (gpointer instance,
GSignalMatchType mask,
guint signal_id,
+ GQuark detail,
GClosure *closure,
gpointer func,
gpointer data)
guint handler_id;
g_return_val_if_fail (G_TYPE_CHECK_INSTANCE (instance), 0);
+ g_return_val_if_fail ((mask & ~G_SIGNAL_MATCH_MASK) == 0, 0);
G_LOCK (g_signal_mutex);
- handler = handler_find (instance, mask, signal_id, closure, func, data);
+ handler = handler_find (instance, mask, signal_id, detail, closure, func, data);
handler_id = handler ? handler->id : 0;
G_UNLOCK (g_signal_mutex);
gboolean
g_signal_handler_pending (gpointer instance,
guint signal_id,
+ GQuark detail,
gboolean may_be_blocked)
{
Handler *handler = NULL;
g_return_val_if_fail (signal_id > 0, FALSE);
G_LOCK (g_signal_mutex);
- handler = handler_find (instance, G_SIGNAL_MATCH_ID, signal_id, NULL, NULL, NULL);
- if (!may_be_blocked)
- for (; handler; handler = handler->next)
- if (!handler->block_count)
- break;
+ if (detail)
+ {
+ SignalNode *node = LOOKUP_SIGNAL_NODE (signal_id);
+
+ if (!(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 FALSE;
+ }
+ }
+ handler = handler_find (instance,
+ (G_SIGNAL_MATCH_ID | G_SIGNAL_MATCH_DETAIL |
+ (may_be_blocked ? 0 : G_SIGNAL_MATCH_UNBLOCKED)),
+ signal_id, detail, NULL, NULL, NULL);
G_UNLOCK (g_signal_mutex);
return handler != NULL;
void
g_signal_emitv (const GValue *instance_and_params,
guint signal_id,
+ GQuark detail,
GValue *return_value)
{
SignalNode *node;
#ifndef G_DISABLE_CHECKS
if (!node || !g_type_conforms_to (G_TYPE_FROM_INSTANCE (instance), node->itype))
g_warning ("%s: signal id `%u' is invalid for instance `%p'", G_STRLOC, signal_id, instance);
+ 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;
+ }
for (i = 0; i < node->n_params; i++)
if (!G_VALUE_HOLDS (param_values + i, node->param_types[i]))
{
return_value = NULL;
#endif /* !G_DISABLE_CHECKS */
- signal_emit_R (node, instance, return_value, instance_and_params);
+ signal_emit_R (node, detail, instance, return_value, instance_and_params);
G_UNLOCK (g_signal_mutex);
}
static void
signal_emit_R (SignalNode *node,
+ GQuark detail,
gpointer instance,
GValue *return_value,
const GValue *instance_and_params)
{
EmissionState emission_state = 0;
GSignalAccumulator accumulator;
+ GSignalInvocationHint ihint;
GClosure *class_closure;
HandlerList *hlist;
- Handler *handlers;
+ Handler *handler_list = NULL;
GValue accu;
gboolean accu_used = FALSE;
guint signal_id = node->signal_id;
if (node->flags & G_SIGNAL_NO_RECURSE)
{
- Emission *emission = emission_find (g_restart_emissions, signal_id, instance);
+ Emission *emission = emission_find (g_restart_emissions, signal_id, detail, instance);
if (emission)
{
return;
}
}
+ ihint.signal_id = node->signal_id;
+ ihint.detail = detail;
accumulator = node->accumulator;
if (accumulator)
{
G_LOCK (g_signal_mutex);
}
emission_push ((node->flags & G_SIGNAL_NO_RECURSE) ? &g_restart_emissions : &g_recursive_emissions,
- signal_id, instance, &emission_state);
+ signal_id, detail, instance, &emission_state);
class_closure = node->class_closure;
- hlist = handler_list_lookup (signal_id, instance);
- handlers = hlist ? hlist->handlers : NULL;
- if (handlers)
- handler_ref (handlers);
EMIT_RESTART:
+ if (handler_list)
+ handler_unref_R (signal_id, instance, handler_list);
+ hlist = handler_list_lookup (signal_id, instance);
+ handler_list = hlist ? hlist->handlers : NULL;
+ if (handler_list)
+ handler_ref (handler_list);
+
+ ihint.run_type = G_SIGNAL_RUN_FIRST;
+
if ((node->flags & G_SIGNAL_RUN_FIRST) && class_closure)
{
emission_state = EMISSION_RUN;
if (accu_used)
g_value_reset (&accu);
g_closure_invoke (class_closure,
- (signal_id << 8) | G_SIGNAL_RUN_FIRST,
&accu,
node->n_params + 1,
- instance_and_params);
- if (!accumulator (signal_id, return_value, &accu) &&
+ 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,
- (signal_id << 8) | G_SIGNAL_RUN_FIRST,
return_value,
node->n_params + 1,
- instance_and_params);
+ instance_and_params,
+ &ihint);
G_LOCK (g_signal_mutex);
if (emission_state == EMISSION_STOP)
goto EMIT_RESTART;
}
- if (handlers)
+ if (handler_list)
{
- Handler *handler = handlers;
+ Handler *handler = handler_list;
emission_state = EMISSION_RUN;
-
handler_ref (handler);
do
{
Handler *tmp;
- if (!handler->after && !handler->block_count)
+ if (handler->after)
+ {
+ handler_unref_R (signal_id, instance, handler_list);
+ handler_list = handler;
+ break;
+ }
+ 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,
- (signal_id << 8) | G_SIGNAL_RUN_FIRST,
&accu,
node->n_params + 1,
- instance_and_params);
- if (!accumulator (signal_id, return_value, &accu) &&
+ 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,
- (signal_id << 8) | G_SIGNAL_RUN_FIRST,
return_value,
node->n_params + 1,
- instance_and_params);
+ instance_and_params,
+ &ihint);
G_LOCK (g_signal_mutex);
tmp = emission_state == EMISSION_RUN ? handler->next : NULL;
if (tmp)
handler_ref (tmp);
- handler_unref_R (signal_id, instance, handler);
+ handler_unref_R (signal_id, instance, handler_list);
+ handler_list = handler;
handler = tmp;
}
while (handler);
goto EMIT_RESTART;
}
+ ihint.run_type = G_SIGNAL_RUN_LAST;
+
if ((node->flags & G_SIGNAL_RUN_LAST) && class_closure)
{
emission_state = EMISSION_RUN;
if (accu_used)
g_value_reset (&accu);
g_closure_invoke (class_closure,
- (signal_id << 8) | G_SIGNAL_RUN_LAST,
&accu,
node->n_params + 1,
- instance_and_params);
- if (!accumulator (signal_id, return_value, &accu) &&
+ 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,
- (signal_id << 8) | G_SIGNAL_RUN_LAST,
return_value,
node->n_params + 1,
- instance_and_params);
+ instance_and_params,
+ &ihint);
G_LOCK (g_signal_mutex);
if (emission_state == EMISSION_STOP)
goto EMIT_RESTART;
}
- if (handlers)
+ if (handler_list)
{
- Handler *handler = handlers;
+ Handler *handler = handler_list;
emission_state = EMISSION_RUN;
-
handler_ref (handler);
do
{
Handler *tmp;
- if (handler->after && !handler->block_count)
+ 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,
- (signal_id << 8) | G_SIGNAL_RUN_LAST,
&accu,
node->n_params + 1,
- instance_and_params);
- if (!accumulator (signal_id, return_value, &accu) &&
+ 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,
- (signal_id << 8) | G_SIGNAL_RUN_LAST,
return_value,
node->n_params + 1,
- instance_and_params);
+ instance_and_params,
+ &ihint);
G_LOCK (g_signal_mutex);
tmp = emission_state == EMISSION_RUN ? handler->next : NULL;
EMIT_CLEANUP:
+ ihint.run_type = G_SIGNAL_RUN_CLEANUP;
+
if ((node->flags & G_SIGNAL_RUN_CLEANUP) && class_closure)
{
+ gboolean need_unset = FALSE;
+
emission_state = EMISSION_STOP;
G_UNLOCK (g_signal_mutex);
if (node->return_type != G_TYPE_NONE)
{
if (!accumulator)
- g_value_init (&accu, node->return_type);
+ {
+ g_value_init (&accu, node->return_type);
+ need_unset = TRUE;
+ }
else if (accu_used)
g_value_reset (&accu);
- accu_used = TRUE;
}
g_closure_invoke (class_closure,
- (signal_id << 8) | G_SIGNAL_RUN_CLEANUP,
node->return_type != G_TYPE_NONE ? &accu : NULL,
node->n_params + 1,
- instance_and_params);
- if (node->return_type != G_TYPE_NONE && !accumulator)
+ instance_and_params,
+ &ihint);
+ if (need_unset)
g_value_unset (&accu);
G_LOCK (g_signal_mutex);
-
+
if (emission_state == EMISSION_RESTART)
goto EMIT_RESTART;
}
- if (handlers)
- handler_unref_R (signal_id, instance, handlers);
+ if (handler_list)
+ handler_unref_R (signal_id, instance, handler_list);
- emission_pop ((node->flags & G_SIGNAL_NO_RECURSE) ? &g_restart_emissions : &g_recursive_emissions);
+ emission_pop ((node->flags & G_SIGNAL_NO_RECURSE) ? &g_restart_emissions : &g_recursive_emissions, &emission_state);
if (accumulator)
{
G_UNLOCK (g_signal_mutex);
#endif /* __cplusplus */
-/* --- macros --- */
-#define G_SIGNAL_HINT_ID(hint) ((hint) >> 8)
-#define G_SIGNAL_HINT_RUN_TYPE(hint) ((hint) & 0xff)
+/* --- typedefs --- */
+typedef struct _GSignalQuery GSignalQuery;
+typedef struct _GSignalInvocationHint GSignalInvocationHint;
+typedef GClosureMarshal GSignalCMarshaller;
+typedef gboolean (*GSignalEmissionHook) (GSignalInvocationHint *ihint,
+ guint n_param_values,
+ const GValue *param_values);
+typedef gboolean (*GSignalAccumulator) (GSignalInvocationHint *ihint,
+ GValue *return_accu,
+ const GValue *return_value);
/* --- run & match types --- */
G_SIGNAL_RUN_LAST = 1 << 1,
G_SIGNAL_RUN_CLEANUP = 1 << 2,
G_SIGNAL_NO_RECURSE = 1 << 3,
- G_SIGNAL_ACTION = 1 << 4,
- G_SIGNAL_NO_HOOKS = 1 << 5
-} GSignalType;
+ G_SIGNAL_DETAILED = 1 << 4,
+ G_SIGNAL_ACTION = 1 << 5,
+ G_SIGNAL_NO_HOOKS = 1 << 6
+#define G_SIGNAL_FLAGS_MASK 0x7f
+} GSignalFlags;
typedef enum
{
G_SIGNAL_MATCH_ID = 1 << 0,
- G_SIGNAL_MATCH_CLOSURE = 1 << 1,
- G_SIGNAL_MATCH_FUNC = 1 << 2,
- G_SIGNAL_MATCH_DATA = 1 << 3,
- G_SIGNAL_MATCH_UNBLOCKED = 1 << 4,
- G_SIGNAL_MATCH_MASK = 0x1f
+ G_SIGNAL_MATCH_DETAIL = 1 << 1,
+ G_SIGNAL_MATCH_CLOSURE = 1 << 2,
+ G_SIGNAL_MATCH_FUNC = 1 << 3,
+ G_SIGNAL_MATCH_DATA = 1 << 4,
+ G_SIGNAL_MATCH_UNBLOCKED = 1 << 5
+#define G_SIGNAL_MATCH_MASK 0x3f
} GSignalMatchType;
-/* --- signal queries --- */
-typedef struct _GSignalQuery GSignalQuery;
-struct _GSignalQuery
+/* --- signal information --- */
+struct _GSignalInvocationHint
+{
+ guint signal_id;
+ GQuark detail;
+ GSignalFlags run_type;
+};
+struct _GSignalQuery
{
guint signal_id;
const gchar *signal_name;
GType itype;
- GSignalType signal_flags;
+ GSignalFlags signal_flags;
GType return_type;
guint n_params;
const GType *param_types;
};
-/* --- function types --- */
-typedef gboolean (*GSignalEmissionHook) (guint signal_id,
- guint n_values,
- const GValue *values);
-typedef gboolean (*GSignalAccumulator) (guint signal_id,
- GValue *return_accu,
- const GValue *return_value);
-typedef GClosureMarshal GSignalCMarshaller;
-
-
/* --- signals --- */
guint g_signal_newv (const gchar *signal_name,
GType itype,
- GSignalType signal_flags,
+ GSignalFlags signal_flags,
GClosure *class_closure,
GSignalAccumulator accumulator,
GSignalCMarshaller c_marshaller,
GType *param_types);
void g_signal_emitv (const GValue *instance_and_params,
guint signal_id,
+ GQuark detail,
GValue *return_value);
guint g_signal_lookup (const gchar *name,
GType itype);
/* --- signal handlers --- */
guint g_signal_connect_closure (gpointer instance,
guint signal_id,
+ GQuark detail,
GClosure *closure,
gboolean after);
void g_signal_handler_disconnect (gpointer instance,
guint g_signal_handler_find (gpointer instance,
GSignalMatchType mask,
guint signal_id,
+ GQuark detail,
GClosure *closure,
gpointer func,
gpointer data);
gboolean g_signal_has_handler_pending (gpointer instance,
guint signal_id,
+ GQuark detail,
gboolean may_be_blocked);
/* --- signal emissions --- */
void g_signal_stop_emission (gpointer instance,
- guint signal_id);
+ 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,