[Cogl] [PATCH 1/2] Add a callback to get expose events from a CoglOnscreen

Neil Roberts neil at linux.intel.com
Tue May 14 06:34:46 PDT 2013


This adds a callback that can be registered with
cogl_onscreen_add_expose_callback which will get called whenever the
window system determines that the contents of the window is damaged
and needs to be redrawn. Under the two X-based winsys's, this is
reported off the back of the Expose events, and under SDL it is reported
from SDL_VIDEOEXPOSE or SDL_WINDOWEVENT_EXPOSED.

There is a private feature flag to specify whether expose events are
supported. If the winsys does not set this then Cogl will simulate
expose events by emitting one whenever the window is shown or resized.
The assumption is that under these winsys's the window can't get
damaged any other way.

In theory we could also get this to work on Win32 by listening to the
WM_PAINT message. However Cogl doesn't actually currently listen for
Windows messages and instead it relies on the application to do it so
it can't be done without the application being aware that is running
on Windows. We can't get Cogl to query windows messages using the
current poll mechanism because you need to call
MsgWaitForMultipleObjects instead of WaitForMultipleObjects to be
woken up on messages and there is no way to report this via
cogl_poll_renderer_get_info.
---
 cogl/cogl-context-private.h            |   3 +-
 cogl/cogl-context.c                    |   3 +-
 cogl/cogl-onscreen-private.h           |  19 +++-
 cogl/cogl-onscreen.c                   | 190 ++++++++++++++++++++++++---------
 cogl/cogl-onscreen.h                   | 113 +++++++++++++++++++-
 cogl/cogl-private.h                    |   9 +-
 cogl/winsys/cogl-winsys-egl-x11.c      |  25 ++++-
 cogl/winsys/cogl-winsys-glx.c          |  26 ++++-
 cogl/winsys/cogl-winsys-sdl.c          |  37 +++++--
 cogl/winsys/cogl-winsys-sdl2.c         |  70 ++++++++----
 doc/reference/cogl2/cogl2-sections.txt |   7 ++
 11 files changed, 410 insertions(+), 92 deletions(-)

diff --git a/cogl/cogl-context-private.h b/cogl/cogl-context-private.h
index cf41c88..f73c024 100644
--- a/cogl/cogl-context-private.h
+++ b/cogl/cogl-context-private.h
@@ -3,7 +3,7 @@
  *
  * An object oriented GL/GLES Abstraction/Utility Layer
  *
- * Copyright (C) 2007,2008,2009 Intel Corporation.
+ * Copyright (C) 2007,2008,2009,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
@@ -174,6 +174,7 @@ struct _CoglContext
   CoglOffscreenAllocateFlags last_offscreen_allocate_flags;
 
   CoglOnscreenEventList onscreen_events_queue;
+  CoglOnscreenQueuedExposeList onscreen_expose_queue;
   CoglClosure *onscreen_dispatch_idle;
 
   CoglGLES2Context *current_gles2_context;
diff --git a/cogl/cogl-context.c b/cogl/cogl-context.c
index e4714be..b4720d4 100644
--- a/cogl/cogl-context.c
+++ b/cogl/cogl-context.c
@@ -3,7 +3,7 @@
  *
  * An object oriented GL/GLES Abstraction/Utility Layer
  *
- * Copyright (C) 2007,2008,2009 Intel Corporation.
+ * Copyright (C) 2007,2008,2009,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
@@ -288,6 +288,7 @@ cogl_context_new (CoglDisplay *display,
   context->current_draw_buffer_changes = COGL_FRAMEBUFFER_STATE_ALL;
 
   COGL_TAILQ_INIT (&context->onscreen_events_queue);
+  COGL_TAILQ_INIT (&context->onscreen_expose_queue);
 
   g_queue_init (&context->gles2_context_stack);
 
diff --git a/cogl/cogl-onscreen-private.h b/cogl/cogl-onscreen-private.h
index 4c2ce94..8f3073c 100644
--- a/cogl/cogl-onscreen-private.h
+++ b/cogl/cogl-onscreen-private.h
@@ -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
@@ -48,6 +48,18 @@ struct _CoglOnscreenEvent
   CoglFrameEvent type;
 };
 
+typedef struct _CoglOnscreenQueuedExpose CoglOnscreenQueuedExpose;
+
+COGL_TAILQ_HEAD (CoglOnscreenQueuedExposeList, CoglOnscreenQueuedExpose);
+
+struct _CoglOnscreenQueuedExpose
+{
+  COGL_TAILQ_ENTRY (CoglOnscreenQueuedExpose) list_node;
+
+  CoglOnscreen *onscreen;
+  CoglOnscreenExposeInfo info;
+};
+
 struct _CoglOnscreen
 {
   CoglFramebuffer  _parent;
@@ -73,6 +85,8 @@ struct _CoglOnscreen
   CoglBool resizable;
   CoglClosureList resize_closures;
 
+  CoglClosureList expose_closures;
+
   int64_t frame_counter;
   int64_t swap_frame_counter; /* frame counter at last all to
                                * cogl_onscreen_swap_region() or
@@ -96,6 +110,7 @@ void
 _cogl_onscreen_notify_resize (CoglOnscreen *onscreen);
 
 void
-_cogl_dispatch_onscreen_events (CoglContext *context);
+_cogl_onscreen_queue_expose (CoglOnscreen *onscreen,
+                             const CoglOnscreenExposeInfo *info);
 
 #endif /* __COGL_ONSCREEN_PRIVATE_H */
diff --git a/cogl/cogl-onscreen.c b/cogl/cogl-onscreen.c
index 03c4849..804f3b5 100644
--- a/cogl/cogl-onscreen.c
+++ b/cogl/cogl-onscreen.c
@@ -49,6 +49,7 @@ _cogl_onscreen_init_from_template (CoglOnscreen *onscreen,
 
   COGL_LIST_INIT (&onscreen->frame_closures);
   COGL_LIST_INIT (&onscreen->resize_closures);
+  COGL_LIST_INIT (&onscreen->expose_closures);
 
   framebuffer->config = onscreen_template->config;
   cogl_object_ref (framebuffer->config.swap_chain);
@@ -92,6 +93,7 @@ _cogl_onscreen_free (CoglOnscreen *onscreen)
 
   _cogl_closure_list_disconnect_all (&onscreen->resize_closures);
   _cogl_closure_list_disconnect_all (&onscreen->frame_closures);
+  _cogl_closure_list_disconnect_all (&onscreen->expose_closures);
 
   while ((frame_info = g_queue_pop_tail (&onscreen->pending_frame_infos)))
     cogl_object_unref (frame_info);
@@ -107,6 +109,111 @@ _cogl_onscreen_free (CoglOnscreen *onscreen)
 }
 
 static void
+notify_event (CoglOnscreen *onscreen,
+              CoglFrameEvent event,
+              CoglFrameInfo *info)
+{
+  _cogl_closure_list_invoke (&onscreen->frame_closures,
+                             CoglFrameCallback,
+                             onscreen, event, info);
+}
+
+static void
+_cogl_dispatch_onscreen_cb (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_closure_disconnect (context->onscreen_dispatch_idle);
+  context->onscreen_dispatch_idle = NULL;
+
+  COGL_TAILQ_FOREACH_SAFE (event,
+                           &queue,
+                           list_node,
+                           tmp)
+    {
+      CoglOnscreen *onscreen = event->onscreen;
+      CoglFrameInfo *info = event->info;
+
+      notify_event (onscreen, event->type, info);
+
+      cogl_object_unref (onscreen);
+      cogl_object_unref (info);
+
+      g_slice_free (CoglOnscreenEvent, event);
+    }
+
+  while (!COGL_TAILQ_EMPTY (&context->onscreen_expose_queue))
+    {
+      CoglOnscreenQueuedExpose *qe =
+        COGL_TAILQ_FIRST (&context->onscreen_expose_queue);
+
+      COGL_TAILQ_REMOVE (&context->onscreen_expose_queue, qe, list_node);
+
+      _cogl_closure_list_invoke (&qe->onscreen->expose_closures,
+                                 CoglOnscreenExposeCallback,
+                                 qe->onscreen,
+                                 &qe->info);
+
+      cogl_object_unref (qe->onscreen);
+
+      g_slice_free (CoglOnscreenQueuedExpose, qe);
+    }
+}
+
+static void
+_cogl_onscreen_queue_dispatch_idle (CoglOnscreen *onscreen)
+{
+  CoglContext *ctx = COGL_FRAMEBUFFER (onscreen)->context;
+
+  if (!ctx->onscreen_dispatch_idle)
+    {
+      ctx->onscreen_dispatch_idle =
+        _cogl_poll_renderer_add_idle (ctx->display->renderer,
+                                      (CoglIdleCallback)
+                                      _cogl_dispatch_onscreen_cb,
+                                      ctx,
+                                      NULL);
+    }
+}
+
+void
+_cogl_onscreen_queue_expose (CoglOnscreen *onscreen,
+                             const CoglOnscreenExposeInfo *info)
+{
+  CoglContext *ctx = COGL_FRAMEBUFFER (onscreen)->context;
+  CoglOnscreenQueuedExpose *qe = g_slice_new (CoglOnscreenQueuedExpose);
+
+  qe->onscreen = cogl_object_ref (onscreen);
+  qe->info = *info;
+  COGL_TAILQ_INSERT_TAIL (&ctx->onscreen_expose_queue, qe, list_node);
+
+  _cogl_onscreen_queue_dispatch_idle (onscreen);
+}
+
+static void
+_cogl_onscreen_queue_full_expose (CoglOnscreen *onscreen)
+{
+  CoglFramebuffer *framebuffer = COGL_FRAMEBUFFER (onscreen);
+  CoglOnscreenExposeInfo info;
+
+  info.x = 0;
+  info.y = 0;
+  info.width = framebuffer->width;
+  info.height = framebuffer->height;
+
+  _cogl_onscreen_queue_expose (onscreen, &info);
+}
+
+static void
 _cogl_onscreen_queue_event (CoglOnscreen *onscreen,
                             CoglFrameEvent type,
                             CoglFrameInfo *info)
@@ -121,15 +228,7 @@ _cogl_onscreen_queue_event (CoglOnscreen *onscreen,
 
   COGL_TAILQ_INSERT_TAIL (&ctx->onscreen_events_queue, event, list_node);
 
-  if (!ctx->onscreen_dispatch_idle)
-    {
-      ctx->onscreen_dispatch_idle =
-        _cogl_poll_renderer_add_idle (ctx->display->renderer,
-                                      (CoglIdleCallback)
-                                      _cogl_dispatch_onscreen_events,
-                                      ctx,
-                                      NULL);
-    }
+  _cogl_onscreen_queue_dispatch_idle (onscreen);
 }
 
 void
@@ -366,6 +465,7 @@ void
 cogl_onscreen_show (CoglOnscreen *onscreen)
 {
   CoglFramebuffer *framebuffer = COGL_FRAMEBUFFER (onscreen);
+  CoglContext *context = framebuffer->context;
   const CoglWinsysVtable *winsys;
 
   if (!framebuffer->allocated)
@@ -377,6 +477,9 @@ cogl_onscreen_show (CoglOnscreen *onscreen)
   winsys = _cogl_framebuffer_get_winsys (framebuffer);
   if (winsys->onscreen_set_visibility)
     winsys->onscreen_set_visibility (onscreen, TRUE);
+
+  if (!(context->private_feature_flags & COGL_PRIVATE_FEATURE_EXPOSE_EVENTS))
+    _cogl_onscreen_queue_full_expose (onscreen);
 }
 
 void
@@ -393,50 +496,6 @@ cogl_onscreen_hide (CoglOnscreen *onscreen)
     }
 }
 
-static void
-notify_event (CoglOnscreen *onscreen,
-              CoglFrameEvent event,
-              CoglFrameInfo *info)
-{
-  _cogl_closure_list_invoke (&onscreen->frame_closures,
-                             CoglFrameCallback,
-                             onscreen, event, info);
-}
-
-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_closure_disconnect (context->onscreen_dispatch_idle);
-  context->onscreen_dispatch_idle = NULL;
-
-  COGL_TAILQ_FOREACH_SAFE (event,
-                           &queue,
-                           list_node,
-                           tmp)
-    {
-      CoglOnscreen *onscreen = event->onscreen;
-      CoglFrameInfo *info = event->info;
-
-      notify_event (onscreen, event->type, info);
-
-      cogl_object_unref (onscreen);
-      cogl_object_unref (info);
-
-      g_slice_free (CoglOnscreenEvent, event);
-    }
-}
-
 void
 _cogl_onscreen_notify_frame_sync (CoglOnscreen *onscreen, CoglFrameInfo *info)
 {
@@ -472,6 +531,10 @@ _cogl_framebuffer_winsys_update_size (CoglFramebuffer *framebuffer,
   framebuffer->height = height;
 
   cogl_framebuffer_set_viewport (framebuffer, 0, 0, width, height);
+
+  if (!(framebuffer->context->private_feature_flags &
+        COGL_PRIVATE_FEATURE_EXPOSE_EVENTS))
+    _cogl_onscreen_queue_full_expose (COGL_ONSCREEN (framebuffer));
 }
 
 void
@@ -521,6 +584,27 @@ cogl_onscreen_remove_resize_callback (CoglOnscreen *onscreen,
   _cogl_closure_disconnect (closure);
 }
 
+CoglOnscreenExposeClosure *
+cogl_onscreen_add_expose_callback (CoglOnscreen *onscreen,
+                                   CoglOnscreenExposeCallback callback,
+                                   void *user_data,
+                                   CoglUserDataDestroyCallback destroy)
+{
+  return _cogl_closure_list_add (&onscreen->expose_closures,
+                                 callback,
+                                 user_data,
+                                 destroy);
+}
+
+void
+cogl_onscreen_remove_expose_callback (CoglOnscreen *onscreen,
+                                      CoglOnscreenExposeClosure *closure)
+{
+  _COGL_RETURN_IF_FAIL (closure);
+
+  _cogl_closure_disconnect (closure);
+}
+
 int64_t
 cogl_onscreen_get_frame_counter (CoglOnscreen *onscreen)
 {
diff --git a/cogl/cogl-onscreen.h b/cogl/cogl-onscreen.h
index 54881a8..2ca539d 100644
--- a/cogl/cogl-onscreen.h
+++ b/cogl/cogl-onscreen.h
@@ -3,7 +3,7 @@
  *
  * An object oriented GL/GLES Abstraction/Utility Layer
  *
- * Copyright (C) 2011,2012 Intel Corporation.
+ * Copyright (C) 2011,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
@@ -776,6 +776,117 @@ cogl_onscreen_remove_resize_callback (CoglOnscreen *onscreen,
                                       CoglOnscreenResizeClosure *closure);
 
 /**
+ * CoglOnscreenExposeInfo:
+ * @x: Left edge of the exposed rectangle
+ * @y: Top edge of the exposed rectangle, measured from the top of the window
+ * @width: Width of the exposed rectangle
+ * @height: Height of the exposed rectangle
+ *
+ * A structure passed to callbacks registered using
+ * cogl_onscreen_add_expose_callback(). The members describe a
+ * rectangle within the onscreen buffer that should be redrawn.
+ *
+ * Since: 1.16
+ * Stability: unstable
+ */
+typedef struct _CoglOnscreenExposeInfo CoglOnscreenExposeInfo;
+
+struct _CoglOnscreenExposeInfo
+{
+  int x, y;
+  int width, height;
+};
+
+/**
+ * CoglOnscreenExposeCallback:
+ * @onscreen: The onscreen that the frame is associated with
+ * @info: A #CoglOnscreenExposeInfo struct containing the details of the
+ *   exposed area
+ * @user_data: The user pointer passed to
+ *             cogl_onscreen_add_frame_callback()
+ *
+ * Is a callback that can be registered via
+ * cogl_onscreen_add_expose_callback() to be called when the windowing
+ * system determines that a region of the onscreen window has been
+ * lost and the application should redraw it.
+ *
+ * Since: 1.16
+ * Stability: unstable
+ */
+typedef void (*CoglOnscreenExposeCallback) (CoglOnscreen *onscreen,
+                                            const CoglOnscreenExposeInfo *info,
+                                            void *user_data);
+
+/**
+ * CoglOnscreenExposeClosure:
+ *
+ * An opaque type that tracks a #CoglOnscreenExposeCallback and associated
+ * user data. A #CoglOnscreenExposeClosure pointer will be returned from
+ * cogl_onscreen_add_expose_callback() and it allows you to remove a
+ * callback later using cogl_onscreen_remove_expose_callback().
+ *
+ * Since: 1.16
+ * Stability: unstable
+ */
+typedef struct _CoglClosure CoglOnscreenExposeClosure;
+
+/**
+ * cogl_onscreen_add_expose_callback:
+ * @onscreen: A #CoglOnscreen framebuffer
+ * @callback: A callback function to call for frame events
+ * @user_data: A private pointer to be passed to @callback
+ * @destroy: An optional callback to destroy @user_data when the
+ *           @callback is removed or @onscreen is freed.
+ *
+ * Installs a @callback function that will be called whenever the
+ * window system has lost the contents of a region of the onscreen
+ * buffer and the application should redraw it to repair the buffer.
+ * For example this may happen in a window system without a compositor
+ * if a window that was previously covering up the onscreen window has
+ * been moved causing a region of the onscreen to be exposed.
+ *
+ * The @callback will be passed a #CoglOnscreenExposeInfo struct which
+ * decribes a rectangle containing the newly exposed region. Note that
+ * this may be called multiple times to describe a non-rectangular
+ * composed of multiple smaller rectangles.
+ *
+ * The expose events are separate from %COGL_FRAME_EVENT_SYNC events
+ * so the application should also listen for this event before
+ * rendering the exposed region to ensure that the framebuffer is
+ * actually ready for rendering.
+ *
+ * Return value: a #CoglOnscreenExposeClosure pointer that can be used to
+ *               remove the callback and associated @user_data later.
+ * Since: 1.16
+ * Stability: unstable
+ */
+CoglOnscreenExposeClosure *
+cogl_onscreen_add_expose_callback (CoglOnscreen *onscreen,
+                                   CoglOnscreenExposeCallback callback,
+                                   void *user_data,
+                                   CoglUserDataDestroyCallback destroy);
+
+/**
+ * cogl_onscreen_remove_expose_callback:
+ * @onscreen: A #CoglOnscreen
+ * @closure: A #CoglOnscreenExposeClosure returned from
+ *           cogl_onscreen_add_expose_callback()
+ *
+ * Removes a callback and associated user data that were previously
+ * registered using cogl_onscreen_add_expose_callback().
+ *
+ * If a destroy callback was passed to
+ * cogl_onscreen_add_expose_callback() to destroy the user data then
+ * this will also get called.
+ *
+ * Since: 1.16
+ * Stability: unstable
+ */
+void
+cogl_onscreen_remove_expose_callback (CoglOnscreen *onscreen,
+                                      CoglOnscreenExposeClosure *closure);
+
+/**
  * cogl_is_onscreen:
  * @object: A #CoglObject pointer
  *
diff --git a/cogl/cogl-private.h b/cogl/cogl-private.h
index 08ee775..e5367f0 100644
--- a/cogl/cogl-private.h
+++ b/cogl/cogl-private.h
@@ -3,7 +3,7 @@
  *
  * An object oriented GL/GLES Abstraction/Utility Layer
  *
- * Copyright (C) 2010 Intel Corporation.
+ * Copyright (C) 2010,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
@@ -57,7 +57,12 @@ typedef enum
   COGL_PRIVATE_FEATURE_ALPHA_TEXTURES = 1L<<21,
   COGL_PRIVATE_FEATURE_TEXTURE_SWIZZLE = 1L<<22,
   COGL_PRIVATE_FEATURE_TEXTURE_MAX_LEVEL = 1L<<23,
-  COGL_PRIVATE_FEATURE_ARBFP = 1L<<24
+  COGL_PRIVATE_FEATURE_ARBFP = 1L<<24,
+
+  /* If this is set then the winsys is responsible for queueing expose
+   * events. Otherwise an expose event will be queued whenever the
+   * window is shown or resized */
+  COGL_PRIVATE_FEATURE_EXPOSE_EVENTS = 1L<<25
 } CoglPrivateFeatureFlags;
 
 /* Sometimes when evaluating pipelines, either during comparisons or
diff --git a/cogl/winsys/cogl-winsys-egl-x11.c b/cogl/winsys/cogl-winsys-egl-x11.c
index 5bc1d9f..cb80d14 100644
--- a/cogl/winsys/cogl-winsys-egl-x11.c
+++ b/cogl/winsys/cogl-winsys-egl-x11.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
@@ -45,7 +45,7 @@
 #include "cogl-error-private.h"
 #include "cogl-poll-private.h"
 
-#define COGL_ONSCREEN_X11_EVENT_MASK StructureNotifyMask
+#define COGL_ONSCREEN_X11_EVENT_MASK (StructureNotifyMask | ExposureMask)
 
 static const CoglWinsysEGLVtable _cogl_winsys_egl_vtable;
 
@@ -173,6 +173,23 @@ event_filter_cb (XEvent *xevent, void *data)
                      xevent->xconfigure.width,
                      xevent->xconfigure.height);
     }
+  else if (xevent->type == Expose)
+    {
+      CoglOnscreen *onscreen =
+        find_onscreen_for_xid (context, xevent->xexpose.window);
+
+      if (onscreen)
+        {
+          CoglOnscreenExposeInfo info;
+
+          info.x = xevent->xexpose.x;
+          info.y = xevent->xexpose.y;
+          info.width = xevent->xexpose.width;
+          info.height = xevent->xexpose.height;
+
+          _cogl_onscreen_queue_expose (onscreen, &info);
+        }
+    }
 
   return COGL_FILTER_CONTINUE;
 }
@@ -302,6 +319,10 @@ _cogl_winsys_egl_context_init (CoglContext *context,
                   COGL_WINSYS_FEATURE_MULTIPLE_ONSCREEN,
                   TRUE);
 
+  /* We'll manually handle queueing expose events in response to
+   * Expose events from X */
+  context->private_feature_flags |= COGL_PRIVATE_FEATURE_EXPOSE_EVENTS;
+
   return TRUE;
 }
 
diff --git a/cogl/winsys/cogl-winsys-glx.c b/cogl/winsys/cogl-winsys-glx.c
index d800cdd..d0d4e3a 100644
--- a/cogl/winsys/cogl-winsys-glx.c
+++ b/cogl/winsys/cogl-winsys-glx.c
@@ -64,7 +64,7 @@
 #include <GL/glx.h>
 #include <X11/Xlib.h>
 
-#define COGL_ONSCREEN_X11_EVENT_MASK StructureNotifyMask
+#define COGL_ONSCREEN_X11_EVENT_MASK (StructureNotifyMask | ExposureMask)
 #define MAX_GLX_CONFIG_ATTRIBS 30
 
 typedef struct _CoglContextGLX
@@ -555,6 +555,26 @@ glx_event_filter_cb (XEvent *xevent, void *data)
     }
 #endif /* GLX_INTEL_swap_event */
 
+  if (xevent->type == Expose)
+    {
+      CoglOnscreen *onscreen =
+        find_onscreen_for_xid (context, xevent->xexpose.window);
+
+      if (onscreen)
+        {
+          CoglOnscreenExposeInfo info;
+
+          info.x = xevent->xexpose.x;
+          info.y = xevent->xexpose.y;
+          info.width = xevent->xexpose.width;
+          info.height = xevent->xexpose.height;
+
+          _cogl_onscreen_queue_expose (onscreen, &info);
+        }
+
+      return COGL_FILTER_CONTINUE;
+    }
+
   return COGL_FILTER_CONTINUE;
 }
 
@@ -824,6 +844,10 @@ update_winsys_features (CoglContext *context, CoglError **error)
                       TRUE);
     }
 
+  /* We'll manually handle queueing expose events in response to
+   * Expose events from X */
+  context->private_feature_flags |= COGL_PRIVATE_FEATURE_EXPOSE_EVENTS;
+
   return TRUE;
 }
 
diff --git a/cogl/winsys/cogl-winsys-sdl.c b/cogl/winsys/cogl-winsys-sdl.c
index ed8212e..7803d42 100644
--- a/cogl/winsys/cogl-winsys-sdl.c
+++ b/cogl/winsys/cogl-winsys-sdl.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
@@ -230,25 +230,27 @@ flush_pending_resize_notification_idle (void *user_data)
 static CoglFilterReturn
 sdl_event_filter_cb (SDL_Event *event, void *data)
 {
+  CoglContext *context = data;
+  CoglDisplay *display = context->display;
+  CoglDisplaySdl *sdl_display = display->winsys;
+  CoglFramebuffer *framebuffer;
+
+  if (!sdl_display->onscreen)
+    return COGL_FILTER_CONTINUE;
+
+  framebuffer = COGL_FRAMEBUFFER (sdl_display->onscreen);
+
   if (event->type == SDL_VIDEORESIZE)
     {
-      CoglContext *context = data;
-      CoglDisplay *display = context->display;
-      CoglDisplaySdl *sdl_display = display->winsys;
       CoglRenderer *renderer = display->renderer;
       CoglRendererSdl *sdl_renderer = renderer->winsys;
       float width = event->resize.w;
       float height = event->resize.h;
-      CoglFramebuffer *framebuffer;
-
-      if (!sdl_display->onscreen)
-        return COGL_FILTER_CONTINUE;
 
       sdl_display->surface = SDL_SetVideoMode (width, height,
                                                0, /* bitsperpixel */
                                                sdl_display->video_mode_flags);
 
-      framebuffer = COGL_FRAMEBUFFER (sdl_display->onscreen);
       _cogl_framebuffer_winsys_update_size (framebuffer, width, height);
 
       /* We only want to notify that a resize happened when the
@@ -265,6 +267,19 @@ sdl_event_filter_cb (SDL_Event *event, void *data)
 
       return COGL_FILTER_CONTINUE;
     }
+  else if (event->type == SDL_VIDEOEXPOSE)
+    {
+      CoglOnscreenExposeInfo info;
+
+      /* Sadly SDL doesn't seem to report the rectangle of the expose
+       * event so we'll just queue the whole window */
+      info.x = 0;
+      info.y = 0;
+      info.width = framebuffer->width;
+      info.height = framebuffer->height;
+
+      _cogl_onscreen_queue_expose (COGL_ONSCREEN (framebuffer), &info);
+    }
 
   return COGL_FILTER_CONTINUE;
 }
@@ -282,6 +297,10 @@ _cogl_winsys_context_init (CoglContext *context, CoglError **error)
                                     (CoglNativeFilterFunc)sdl_event_filter_cb,
                                     context);
 
+  /* We'll manually handle queueing expose events in response to
+   * SDL_VIDEOEXPOSE events */
+  context->private_feature_flags |= COGL_PRIVATE_FEATURE_EXPOSE_EVENTS;
+
   return _cogl_context_update_features (context, error);
 }
 
diff --git a/cogl/winsys/cogl-winsys-sdl2.c b/cogl/winsys/cogl-winsys-sdl2.c
index 5595f46..9eab1b5 100644
--- a/cogl/winsys/cogl-winsys-sdl2.c
+++ b/cogl/winsys/cogl-winsys-sdl2.c
@@ -3,7 +3,7 @@
  *
  * An object oriented GL/GLES Abstraction/Utility Layer
  *
- * Copyright (C) 2011, 2012 Intel Corporation.
+ * Copyright (C) 2011, 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
@@ -303,30 +303,30 @@ flush_pending_resize_notifications_idle (void *user_data)
 }
 
 static CoglFilterReturn
-sdl_event_filter_cb (SDL_Event *event, void *data)
+sdl_window_event_filter (SDL_WindowEvent *event,
+                         CoglContext *context)
 {
-  if (event->type == SDL_WINDOWEVENT &&
-      event->window.event == SDL_WINDOWEVENT_SIZE_CHANGED)
+  SDL_Window *window;
+  CoglFramebuffer *framebuffer;
+
+  window = SDL_GetWindowFromID (event->windowID);
+
+  if (window == NULL)
+    return COGL_FILTER_CONTINUE;
+
+  framebuffer = SDL_GetWindowData (window, COGL_SDL_WINDOW_DATA_KEY);
+
+  if (framebuffer == NULL || framebuffer->context != context)
+    return COGL_FILTER_CONTINUE;
+
+  if (event->event == SDL_WINDOWEVENT_SIZE_CHANGED)
     {
-      CoglContext *context = data;
       CoglDisplay *display = context->display;
       CoglRenderer *renderer = display->renderer;
       CoglRendererSdl2 *sdl_renderer = renderer->winsys;
-      float width = event->window.data1;
-      float height = event->window.data2;
-      CoglFramebuffer *framebuffer;
+      float width = event->data1;
+      float height = event->data2;
       CoglOnscreenSdl2 *sdl_onscreen;
-      SDL_Window *window;
-
-      window = SDL_GetWindowFromID (event->window.windowID);
-
-      if (window == NULL)
-        return COGL_FILTER_CONTINUE;
-
-      framebuffer = SDL_GetWindowData (window, COGL_SDL_WINDOW_DATA_KEY);
-
-      if (framebuffer == NULL || framebuffer->context != context)
-        return COGL_FILTER_CONTINUE;
 
       _cogl_framebuffer_winsys_update_size (framebuffer, width, height);
 
@@ -344,13 +344,39 @@ sdl_event_filter_cb (SDL_Event *event, void *data)
 
       sdl_onscreen = COGL_ONSCREEN (framebuffer)->winsys;
       sdl_onscreen->pending_resize_notify = TRUE;
+    }
+  else if (event->event == SDL_WINDOWEVENT_EXPOSED)
+    {
+      CoglOnscreenExposeInfo info;
 
-      return COGL_FILTER_CONTINUE;
+      /* Sadly SDL doesn't seem to report the rectangle of the expose
+       * event so we'll just queue the whole window */
+      info.x = 0;
+      info.y = 0;
+      info.width = framebuffer->width;
+      info.height = framebuffer->height;
+
+      _cogl_onscreen_queue_expose (COGL_ONSCREEN (framebuffer), &info);
     }
 
   return COGL_FILTER_CONTINUE;
 }
 
+static CoglFilterReturn
+sdl_event_filter_cb (SDL_Event *event, void *data)
+{
+  CoglContext *context = data;
+
+  switch (event->type)
+    {
+    case SDL_WINDOWEVENT:
+      return sdl_window_event_filter (&event->window, context);
+
+    default:
+      return COGL_FILTER_CONTINUE;
+    }
+}
+
 static CoglBool
 _cogl_winsys_context_init (CoglContext *context, CoglError **error)
 {
@@ -370,6 +396,10 @@ _cogl_winsys_context_init (CoglContext *context, CoglError **error)
                     COGL_WINSYS_FEATURE_SWAP_REGION_THROTTLE,
                     TRUE);
 
+  /* We'll manually handle queueing expose events in response to
+   * SDL_WINDOWEVENT_EXPOSED events */
+  context->private_feature_flags |= COGL_PRIVATE_FEATURE_EXPOSE_EVENTS;
+
   _cogl_renderer_add_native_filter (renderer,
                                     (CoglNativeFilterFunc) sdl_event_filter_cb,
                                     context);
diff --git a/doc/reference/cogl2/cogl2-sections.txt b/doc/reference/cogl2/cogl2-sections.txt
index 68769bd..97aded8 100644
--- a/doc/reference/cogl2/cogl2-sections.txt
+++ b/doc/reference/cogl2/cogl2-sections.txt
@@ -555,6 +555,13 @@ cogl_onscreen_add_frame_callback
 cogl_onscreen_remove_frame_callback
 
 <SUBSECTION>
+CoglOnscreenExposeInfo
+CoglOnscreenExposeCallback
+CoglOnscreenExposeClosure
+cogl_onscreen_add_expose_callback
+cogl_onscreen_remove_expose_callback
+
+<SUBSECTION>
 CoglOnscreenResizeCallback
 CoglOnscreenResizeClosure
 cogl_onscreen_add_resize_callback
-- 
1.7.11.3.g3c3efa5



More information about the Cogl mailing list