diff --git a/cogl/Makefile.am b/cogl/Makefile.am
index 4629b4949..2734dca40 100644
--- a/cogl/Makefile.am
+++ b/cogl/Makefile.am
@@ -435,6 +435,8 @@ cogl_sources_c = \
$(srcdir)/cogl-gles2-context.c \
$(srcdir)/cogl-error-private.h \
$(srcdir)/cogl-error.c \
+ $(srcdir)/cogl-closure-list-private.h \
+ $(srcdir)/cogl-closure-list.c \
$(NULL)
if USE_GLIB
diff --git a/cogl/cogl-closure-list-private.h b/cogl/cogl-closure-list-private.h
new file mode 100644
index 000000000..ef53ca366
--- /dev/null
+++ b/cogl/cogl-closure-list-private.h
@@ -0,0 +1,104 @@
+/*
+ * Cogl
+ *
+ * An object oriented GL/GLES Abstraction/Utility Layer
+ *
+ * Copyright (C) 2012,2013 Intel Corporation.
+ *
+ * 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, see
+ * .
+ *
+ */
+
+#ifndef _COGL_CLOSURE_LIST_PRIVATE_H_
+#define _COGL_CLOSURE_LIST_PRIVATE_H_
+
+#include "cogl-object.h"
+#include "cogl-queue.h"
+
+/*
+ * This implements a list of callbacks that can be used a bit like
+ * signals in GObject, but that don't have any marshalling overhead.
+ *
+ * The idea is that any Cogl code that wants to provide a callback
+ * point will provide api to add a callback for that particular point.
+ * The function can take a function pointer with the correct
+ * signature. Internally the Cogl code can use _cogl_closure_list_add,
+ * _cogl_closure_disconnect and _cogl_closure_list_disconnect_all
+ *
+ * In the future we could consider exposing the CoglClosure type which
+ * would allow applications to use _cogl_closure_disconnect() directly
+ * so we don't need to expose new disconnect apis for each callback
+ * point.
+ */
+
+typedef struct _CoglClosure CoglClosure;
+
+COGL_LIST_HEAD (CoglClosureList, CoglClosure);
+
+struct _CoglClosure
+{
+ COGL_LIST_ENTRY (CoglClosure) list_node;
+
+ void *function;
+ void *user_data;
+ CoglUserDataDestroyCallback destroy_cb;
+};
+
+/*
+ * _cogl_closure_disconnect:
+ * @closure: A closure connected to a Cogl closure list
+ *
+ * Removes the given closure from the callback list it is connected to
+ * and destroys it. If the closure was created with a destroy function
+ * then it will be invoked. */
+void
+_cogl_closure_disconnect (CoglClosure *closure);
+
+void
+_cogl_closure_list_disconnect_all (CoglClosureList *list);
+
+CoglClosure *
+_cogl_closure_list_add (CoglClosureList *list,
+ void *function,
+ void *user_data,
+ CoglUserDataDestroyCallback destroy_cb);
+
+/*
+ * _cogl_closure_list_invoke:
+ * @list: A pointer to a CoglList containing CoglClosures
+ * @cb_type: The name of a typedef for the closure callback function signature
+ * @...: The the arguments to pass to the callback
+ *
+ * A convenience macro to invoke a closure list.
+ *
+ * Note that the arguments will be evaluated multiple times so it is
+ * not safe to pass expressions that have side-effects.
+ *
+ * Note also that this function ignores the return value from the
+ * callbacks. If you want to handle the return value you should
+ * manually iterate the list and invoke the callbacks yourself.
+ */
+#define _cogl_closure_list_invoke(list, cb_type, ...) \
+ G_STMT_START { \
+ CoglClosure *_c, *_tmp; \
+ \
+ COGL_LIST_FOREACH_SAFE (_c, (list), list_node, _tmp) \
+ { \
+ cb_type _cb = _c->function; \
+ _cb (__VA_ARGS__, _c->user_data); \
+ } \
+ } G_STMT_END
+
+#endif /* _COGL_CLOSURE_LIST_PRIVATE_H_ */
diff --git a/cogl/cogl-closure-list.c b/cogl/cogl-closure-list.c
new file mode 100644
index 000000000..60b26b444
--- /dev/null
+++ b/cogl/cogl-closure-list.c
@@ -0,0 +1,65 @@
+/*
+ * Cogl
+ *
+ * An object oriented GL/GLES Abstraction/Utility Layer
+ *
+ * Copyright (C) 2012,2013 Intel Corporation.
+ *
+ * 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, see
+ * .
+ *
+ */
+
+#include
+
+#include
+
+#include "cogl-closure-list-private.h"
+
+void
+_cogl_closure_disconnect (CoglClosure *closure)
+{
+ COGL_LIST_REMOVE (closure, list_node);
+
+ if (closure->destroy_cb)
+ closure->destroy_cb (closure->user_data);
+
+ g_slice_free (CoglClosure, closure);
+}
+
+void
+_cogl_closure_list_disconnect_all (CoglClosureList *list)
+{
+ CoglClosure *closure, *next;
+
+ COGL_LIST_FOREACH_SAFE (closure, list, list_node, next)
+ _cogl_closure_disconnect (closure);
+}
+
+CoglClosure *
+_cogl_closure_list_add (CoglClosureList *list,
+ void *function,
+ void *user_data,
+ CoglUserDataDestroyCallback destroy_cb)
+{
+ CoglClosure *closure = g_slice_new (CoglClosure);
+
+ closure->function = function;
+ closure->user_data = user_data;
+ closure->destroy_cb = destroy_cb;
+
+ COGL_LIST_INSERT_HEAD (list, closure, list_node);
+
+ return closure;
+}
diff --git a/cogl/cogl-onscreen-private.h b/cogl/cogl-onscreen-private.h
index 2ac89911f..a6425fc76 100644
--- a/cogl/cogl-onscreen-private.h
+++ b/cogl/cogl-onscreen-private.h
@@ -27,6 +27,7 @@
#include "cogl-onscreen.h"
#include "cogl-framebuffer-private.h"
#include "cogl-queue.h"
+#include "cogl-closure-list-private.h"
#include
@@ -34,30 +35,6 @@
#include
#endif
-COGL_TAILQ_HEAD (CoglFrameCallbackList, CoglFrameClosure);
-
-struct _CoglFrameClosure
-{
- COGL_TAILQ_ENTRY (CoglFrameClosure) list_node;
-
- CoglFrameCallback callback;
-
- void *user_data;
- CoglUserDataDestroyCallback destroy;
-};
-
-COGL_TAILQ_HEAD (CoglOnscreenResizeCallbackList, CoglOnscreenResizeClosure);
-
-struct _CoglOnscreenResizeClosure
-{
- COGL_TAILQ_ENTRY (CoglOnscreenResizeClosure) list_node;
-
- CoglOnscreenResizeCallback callback;
-
- void *user_data;
- CoglUserDataDestroyCallback destroy;
-};
-
typedef struct _CoglOnscreenEvent CoglOnscreenEvent;
COGL_TAILQ_HEAD (CoglOnscreenEventList, CoglOnscreenEvent);
@@ -91,10 +68,10 @@ struct _CoglOnscreen
CoglBool swap_throttled;
- CoglFrameCallbackList frame_closures;
+ CoglClosureList frame_closures;
CoglBool resizable;
- CoglOnscreenResizeCallbackList resize_closures;
+ CoglClosureList resize_closures;
int64_t frame_counter;
int64_t swap_frame_counter; /* frame counter at last all to
diff --git a/cogl/cogl-onscreen.c b/cogl/cogl-onscreen.c
index 6175db70f..9ce1457df 100644
--- a/cogl/cogl-onscreen.c
+++ b/cogl/cogl-onscreen.c
@@ -33,6 +33,7 @@
#include "cogl-context-private.h"
#include "cogl-object-private.h"
#include "cogl1-context.h"
+#include "cogl-closure-list-private.h"
static void _cogl_onscreen_free (CoglOnscreen *onscreen);
@@ -46,8 +47,8 @@ _cogl_onscreen_init_from_template (CoglOnscreen *onscreen,
{
CoglFramebuffer *framebuffer = COGL_FRAMEBUFFER (onscreen);
- COGL_TAILQ_INIT (&onscreen->frame_closures);
- COGL_TAILQ_INIT (&onscreen->resize_closures);
+ COGL_LIST_INIT (&onscreen->frame_closures);
+ COGL_LIST_INIT (&onscreen->resize_closures);
framebuffer->config = onscreen_template->config;
cogl_object_ref (framebuffer->config.swap_chain);
@@ -117,19 +118,8 @@ _cogl_onscreen_free (CoglOnscreen *onscreen)
const CoglWinsysVtable *winsys = _cogl_framebuffer_get_winsys (framebuffer);
CoglFrameInfo *frame_info;
- while (!COGL_TAILQ_EMPTY (&onscreen->resize_closures))
- {
- CoglOnscreenResizeClosure *resize_closure =
- COGL_TAILQ_FIRST (&onscreen->resize_closures);
- cogl_onscreen_remove_resize_callback (onscreen, resize_closure);
- }
-
- while (!COGL_TAILQ_EMPTY (&onscreen->frame_closures))
- {
- CoglFrameClosure *frame_closure =
- COGL_TAILQ_FIRST (&onscreen->frame_closures);
- cogl_onscreen_remove_frame_callback (onscreen, frame_closure);
- }
+ _cogl_closure_list_disconnect_all (&onscreen->resize_closures);
+ _cogl_closure_list_disconnect_all (&onscreen->frame_closures);
while ((frame_info = g_queue_pop_tail (&onscreen->pending_frame_infos)))
cogl_object_unref (frame_info);
@@ -357,15 +347,10 @@ cogl_onscreen_add_frame_callback (CoglOnscreen *onscreen,
void *user_data,
CoglUserDataDestroyCallback destroy)
{
- CoglFrameClosure *closure = g_slice_new0 (CoglFrameClosure);
-
- closure->callback = callback;
- closure->user_data = user_data;
- closure->destroy = destroy;
-
- COGL_TAILQ_INSERT_TAIL (&onscreen->frame_closures, closure, list_node);
-
- return closure;
+ return _cogl_closure_list_add (&onscreen->frame_closures,
+ callback,
+ user_data,
+ destroy);
}
void
@@ -374,12 +359,7 @@ cogl_onscreen_remove_frame_callback (CoglOnscreen *onscreen,
{
_COGL_RETURN_IF_FAIL (closure);
- if (closure->destroy)
- closure->destroy (closure->user_data);
-
- COGL_TAILQ_REMOVE (&onscreen->frame_closures, closure, list_node);
-
- g_slice_free (CoglFrameClosure, closure);
+ _cogl_closure_disconnect (closure);
}
typedef struct _SwapBufferCallbackState
@@ -504,16 +484,9 @@ notify_event (CoglOnscreen *onscreen,
CoglFrameEvent event,
CoglFrameInfo *info)
{
- CoglFrameClosure *entry, *tmp;
-
- COGL_TAILQ_FOREACH_SAFE (entry,
- &onscreen->frame_closures,
- list_node,
- tmp)
- {
- entry->callback (onscreen, event, info,
- entry->user_data);
- }
+ _cogl_closure_list_invoke (&onscreen->frame_closures,
+ CoglFrameCallback,
+ onscreen, event, info);
}
void
@@ -562,17 +535,13 @@ _cogl_onscreen_notify_complete (CoglOnscreen *onscreen, CoglFrameInfo *info)
void
_cogl_onscreen_notify_resize (CoglOnscreen *onscreen)
{
- CoglOnscreenResizeClosure *closure, *tmp;
CoglFramebuffer *framebuffer = COGL_FRAMEBUFFER (onscreen);
- COGL_TAILQ_FOREACH_SAFE (closure,
- &onscreen->resize_closures,
- list_node,
- tmp)
- closure->callback (onscreen,
- framebuffer->width,
- framebuffer->height,
- closure->user_data);
+ _cogl_closure_list_invoke (&onscreen->resize_closures,
+ CoglOnscreenResizeCallback,
+ onscreen,
+ framebuffer->width,
+ framebuffer->height);
}
void
@@ -622,27 +591,17 @@ cogl_onscreen_add_resize_callback (CoglOnscreen *onscreen,
void *user_data,
CoglUserDataDestroyCallback destroy)
{
- CoglOnscreenResizeClosure *closure = g_slice_new (CoglOnscreenResizeClosure);
-
- closure->callback = callback;
- closure->user_data = user_data;
- closure->destroy = destroy;
-
- COGL_TAILQ_INSERT_TAIL (&onscreen->resize_closures, closure, list_node);
-
- return closure;
+ return _cogl_closure_list_add (&onscreen->resize_closures,
+ callback,
+ user_data,
+ destroy);
}
void
cogl_onscreen_remove_resize_callback (CoglOnscreen *onscreen,
CoglOnscreenResizeClosure *closure)
{
- if (closure->destroy)
- closure->destroy (closure->user_data);
-
- COGL_TAILQ_REMOVE (&onscreen->resize_closures, closure, list_node);
-
- g_slice_free (CoglOnscreenResizeClosure, closure);
+ _cogl_closure_disconnect (closure);
}
int64_t
diff --git a/cogl/cogl-onscreen.h b/cogl/cogl-onscreen.h
index 52fa4d1fb..4389a43a3 100644
--- a/cogl/cogl-onscreen.h
+++ b/cogl/cogl-onscreen.h
@@ -474,7 +474,7 @@ typedef void (*CoglFrameCallback) (CoglOnscreen *onscreen,
* Since: 1.14
* Stability: unstable
*/
-typedef struct _CoglFrameClosure CoglFrameClosure;
+typedef struct _CoglClosure CoglFrameClosure;
/**
* cogl_onscreen_add_frame_callback:
@@ -690,7 +690,7 @@ typedef void (*CoglOnscreenResizeCallback) (CoglOnscreen *onscreen,
* Since: 2.0
* Stability: unstable
*/
-typedef struct _CoglOnscreenResizeClosure CoglOnscreenResizeClosure;
+typedef struct _CoglClosure CoglOnscreenResizeClosure;
/**
* cogl_onscreen_add_resize_callback: