diff --git a/cogl/cogl-onscreen.c b/cogl/cogl-onscreen.c index 5f72454e6..23f62bac0 100644 --- a/cogl/cogl-onscreen.c +++ b/cogl/cogl-onscreen.c @@ -3,7 +3,7 @@ * * An object oriented GL/GLES Abstraction/Utility Layer * - * Copyright (C) 2011 Intel Corporation. + * Copyright (C) 2011, 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 @@ -524,9 +524,18 @@ void _cogl_dispatch_onscreen_events (CoglContext *context) { CoglOnscreenEvent *event, *tmp; + CoglOnscreenEventList queue; + + /* Dispatching the event callback may cause another frame to be + * drawn which in may cause another event to be queued immediately. + * To make sure this loop will only dispatch one set of events we'll + * steal the queue and iterate that separately */ + COGL_TAILQ_INIT (&queue); + COGL_TAILQ_CONCAT (&queue, &context->onscreen_events_queue, list_node); + COGL_TAILQ_INIT (&context->onscreen_events_queue); COGL_TAILQ_FOREACH_SAFE (event, - &context->onscreen_events_queue, + &queue, list_node, tmp) { @@ -538,7 +547,6 @@ _cogl_dispatch_onscreen_events (CoglContext *context) cogl_object_unref (onscreen); cogl_object_unref (info); - COGL_TAILQ_REMOVE (&context->onscreen_events_queue, event, list_node); g_slice_free (CoglOnscreenEvent, event); } } diff --git a/cogl/winsys/cogl-winsys-glx.c b/cogl/winsys/cogl-winsys-glx.c index 10228cc3b..a58a6ce1b 100644 --- a/cogl/winsys/cogl-winsys-glx.c +++ b/cogl/winsys/cogl-winsys-glx.c @@ -2542,21 +2542,27 @@ flush_pending_notifications_cb (void *data, { CoglOnscreen *onscreen = COGL_ONSCREEN (framebuffer); CoglOnscreenGLX *glx_onscreen = onscreen->winsys; + CoglBool pending_sync_notify = glx_onscreen->pending_sync_notify; + CoglBool pending_complete_notify = glx_onscreen->pending_complete_notify; - if (glx_onscreen->pending_sync_notify) + /* If swap_region is called then notifying the sync event could + * potentially immediately queue a subsequent pending notify so + * we need to clear the flag before invoking the callback */ + glx_onscreen->pending_sync_notify = FALSE; + glx_onscreen->pending_complete_notify = FALSE; + + if (pending_sync_notify) { CoglFrameInfo *info = g_queue_peek_head (&onscreen->pending_frame_infos); _cogl_onscreen_notify_frame_sync (onscreen, info); - glx_onscreen->pending_sync_notify = FALSE; } - if (glx_onscreen->pending_complete_notify) + if (pending_complete_notify) { CoglFrameInfo *info = g_queue_pop_head (&onscreen->pending_frame_infos); _cogl_onscreen_notify_complete (onscreen, info); - glx_onscreen->pending_complete_notify = FALSE; cogl_object_unref (info); } @@ -2585,12 +2591,15 @@ _cogl_winsys_poll_dispatch (CoglContext *context, glx_display->pending_resize_notify || glx_display->pending_complete_notify) { - g_list_foreach (context->framebuffers, - flush_pending_notifications_cb, - NULL); + /* These need to be cleared before invoking the callbacks in + * case the callbacks cause them to be set again */ glx_display->pending_sync_notify = FALSE; glx_display->pending_resize_notify = FALSE; glx_display->pending_complete_notify = FALSE; + + g_list_foreach (context->framebuffers, + flush_pending_notifications_cb, + NULL); } }