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: