+ c = &g_array_index(h, LttvHookClosure, i);
+ if(c->hook == f) {
+ hook_data = c->hook_data;
+ lttv_hooks_remove_by_position(h, i);
+ return hook_data;
+ }
+ }
+ return NULL;
+}
+
+
+void lttv_hooks_remove_data(LttvHooks *h, LttvHook f, void *hook_data)
+{
+ unsigned i;
+
+ LttvHookClosure *c;
+
+ for(i = 0 ; i < h->len ; i++) {
+ c = &g_array_index(h, LttvHookClosure, i);
+ if(c->hook == f && c->hook_data == hook_data) {
+ lttv_hooks_remove_by_position(h, i);
+ return;
+ }
+ }
+}
+
+
+void lttv_hooks_remove_list(LttvHooks *h, LttvHooks *list)
+{
+ guint i, j;
+
+ LttvHookClosure *c, *c_list;
+
+ if(list == NULL) return;
+ for(i = 0, j = 0 ; i < h->len && j < list->len ;) {
+ c = &g_array_index(h, LttvHookClosure, i);
+ c_list = &g_array_index(list, LttvHookClosure, j);
+ if(c->hook == c_list->hook && c->hook_data == c_list->hook_data) {
+ lttv_hooks_remove_by_position(h, i);
+ j++;
+ }
+ else i++;
+ }
+
+ /* Normally the hooks in h are ordered as in list. If this is not the case,
+ try harder here. */
+
+ if(j < list->len) {
+ for(; j < list->len ; j++) {
+ c_list = &g_array_index(list, LttvHookClosure, j);
+ lttv_hooks_remove_data(h, c_list->hook, c_list->hook_data);
+ }
+ }
+}
+
+
+unsigned lttv_hooks_number(LttvHooks *h)
+{
+ return h->len;
+}
+
+
+void lttv_hooks_get(LttvHooks *h, unsigned i, LttvHook *f, void **hook_data)
+{
+ LttvHookClosure *c;
+
+ c = &g_array_index(h, LttvHookClosure, i);
+ *f = c->hook;
+ *hook_data = c->hook_data;
+}
+
+
+void lttv_hooks_remove_by_position(LttvHooks *h, unsigned i)
+{
+ g_array_remove_index(h, i);
+}
+
+
+gboolean lttv_hooks_call(LttvHooks *h, void *call_data)
+{
+ gboolean ret = FALSE;
+
+ LttvHookClosure *c;
+
+ guint i;
+
+ if(h != NULL) {
+ for(i = 0 ; i < h->len ; i++) {
+ c = &g_array_index(h, LttvHookClosure, i);
+ ret = ret || c->hook(c->hook_data,call_data);
+ }