From 181b875a3d73860b5568768658d82b7dd7492107 Mon Sep 17 00:00:00 2001 From: Neil Roberts Date: Fri, 16 Dec 2011 18:50:49 +0000 Subject: [PATCH] xlib: Internally retrieve XEvents Previously we relied on the application to send all X events through Cogl using cogl_xlib_renderer_handle_event. This breaks the abstraction that an application shouldn't need to know what winsys Cogl is using. Now that we have main loop integreation in Cogl, the Xlib-based winsys's can report that Cogl needs to block on the file descriptor of the X connection and it can manually handle the events. The event retrieval can be disabled by an application if it calls the new cogl_xlib_renderer_set_event_retrieval_enabled() function. The event retrieval will also automatically be disabled if the application sets a foreign display. Reviewed-by: Robert Bragg --- cogl/cogl-renderer-private.h | 1 + cogl/cogl-renderer.c | 19 +++++++++++++ cogl/cogl-xlib-renderer-private.h | 15 +++++++++++ cogl/cogl-xlib-renderer.c | 45 +++++++++++++++++++++++++++++++ cogl/cogl-xlib-renderer.h | 27 +++++++++++++++++++ cogl/winsys/cogl-winsys-egl-x11.c | 25 +++++++++++++++++ cogl/winsys/cogl-winsys-glx.c | 24 +++++++++++++++++ 7 files changed, 156 insertions(+) diff --git a/cogl/cogl-renderer-private.h b/cogl/cogl-renderer-private.h index 2f7aaf102..47c0667e1 100644 --- a/cogl/cogl-renderer-private.h +++ b/cogl/cogl-renderer-private.h @@ -46,6 +46,7 @@ struct _CoglRenderer CoglWinsysID winsys_id_override; #ifdef COGL_HAS_XLIB_SUPPORT Display *foreign_xdpy; + gboolean xlib_enable_event_retrieval; #endif CoglDriver driver; diff --git a/cogl/cogl-renderer.c b/cogl/cogl-renderer.c index fe4e2251f..1a01b5940 100644 --- a/cogl/cogl-renderer.c +++ b/cogl/cogl-renderer.c @@ -169,6 +169,10 @@ cogl_renderer_new (void) renderer->connected = FALSE; renderer->event_filters = NULL; +#ifdef COGL_HAS_XLIB_SUPPORT + renderer->xlib_enable_event_retrieval = TRUE; +#endif + return _cogl_renderer_object_new (renderer); } @@ -183,6 +187,10 @@ cogl_xlib_renderer_set_foreign_display (CoglRenderer *renderer, _COGL_RETURN_IF_FAIL (!renderer->connected); renderer->foreign_xdpy = xdisplay; + + /* If the application is using a foreign display then we can assume + it will also do its own event retrieval */ + cogl_xlib_renderer_set_event_retrieval_enabled (renderer, FALSE); } Display * @@ -192,6 +200,17 @@ cogl_xlib_renderer_get_foreign_display (CoglRenderer *renderer) return renderer->foreign_xdpy; } + +void +cogl_xlib_renderer_set_event_retrieval_enabled (CoglRenderer *renderer, + gboolean enable) +{ + _COGL_RETURN_IF_FAIL (cogl_is_renderer (renderer)); + /* NB: Renderers are considered immutable once connected */ + _COGL_RETURN_IF_FAIL (!renderer->connected); + + renderer->xlib_enable_event_retrieval = enable; +} #endif /* COGL_HAS_XLIB_SUPPORT */ gboolean diff --git a/cogl/cogl-xlib-renderer-private.h b/cogl/cogl-xlib-renderer-private.h index bad70babb..d0715c192 100644 --- a/cogl/cogl-xlib-renderer-private.h +++ b/cogl/cogl-xlib-renderer-private.h @@ -27,6 +27,7 @@ #include "cogl-object-private.h" #include "cogl-xlib-private.h" #include "cogl-x11-renderer-private.h" +#include "cogl-context.h" typedef struct _CoglXlibRenderer { @@ -37,6 +38,9 @@ typedef struct _CoglXlibRenderer /* Current top of the XError trap state stack. The actual memory for these is expected to be allocated on the stack by the caller */ CoglXlibTrapState *trap_state; + + /* A poll FD for handling event retrieval within Cogl */ + CoglPollFD poll_fd; } CoglXlibRenderer; gboolean @@ -77,4 +81,15 @@ _cogl_xlib_renderer_untrap_errors (CoglRenderer *renderer, CoglXlibRenderer * _cogl_xlib_renderer_get_data (CoglRenderer *renderer); +void +_cogl_xlib_renderer_poll_get_info (CoglRenderer *renderer, + CoglPollFD **poll_fds, + int *n_poll_fds, + gint64 *timeout); + +void +_cogl_xlib_renderer_poll_dispatch (CoglRenderer *renderer, + const CoglPollFD *poll_fds, + int n_poll_fds); + #endif /* __COGL_RENDERER_XLIB_PRIVATE_H */ diff --git a/cogl/cogl-xlib-renderer.c b/cogl/cogl-xlib-renderer.c index 3a96b5170..1bbbe1406 100644 --- a/cogl/cogl-xlib-renderer.c +++ b/cogl/cogl-xlib-renderer.c @@ -213,6 +213,9 @@ _cogl_xlib_renderer_connect (CoglRenderer *renderer, GError **error) xlib_renderer->trap_state = NULL; + xlib_renderer->poll_fd.fd = ConnectionNumber (xlib_renderer->xdpy); + xlib_renderer->poll_fd.events = COGL_POLL_FD_EVENT_IN; + register_xlib_renderer (renderer); return TRUE; @@ -267,3 +270,45 @@ cogl_xlib_renderer_remove_filter (CoglRenderer *renderer, (CoglNativeFilterFunc)func, data); } +void +_cogl_xlib_renderer_poll_get_info (CoglRenderer *renderer, + CoglPollFD **poll_fds, + int *n_poll_fds, + gint64 *timeout) +{ + CoglXlibRenderer *xlib_renderer = _cogl_xlib_renderer_get_data (renderer); + + if (renderer->xlib_enable_event_retrieval) + { + *n_poll_fds = 1; + *poll_fds = &xlib_renderer->poll_fd; + if (XPending (xlib_renderer->xdpy)) + *timeout = 0; + else + *timeout = -1; + } + else + { + *n_poll_fds = 0; + *poll_fds = NULL; + *timeout = -1; + } +} + +void +_cogl_xlib_renderer_poll_dispatch (CoglRenderer *renderer, + const CoglPollFD *poll_fds, + int n_poll_fds) +{ + CoglXlibRenderer *xlib_renderer = _cogl_xlib_renderer_get_data (renderer); + + if (renderer->xlib_enable_event_retrieval) + while (XPending (xlib_renderer->xdpy)) + { + XEvent xevent; + + XNextEvent (xlib_renderer->xdpy, &xevent); + + cogl_xlib_renderer_handle_event (renderer, &xevent); + } +} diff --git a/cogl/cogl-xlib-renderer.h b/cogl/cogl-xlib-renderer.h index 0afd568f4..8c8b75226 100644 --- a/cogl/cogl-xlib-renderer.h +++ b/cogl/cogl-xlib-renderer.h @@ -112,11 +112,38 @@ cogl_xlib_renderer_get_foreign_display (CoglRenderer *renderer); * * Sets a foreign Xlib display that Cogl will use for and Xlib based winsys * backend. + * + * Note that calling this function will automatically call + * cogl_xlib_renderer_set_event_retrieval_enabled() to disable Cogl's + * event retrieval. Cogl still needs to see all of the X events so the + * application should also use cogl_xlib_renderer_handle_event() if it + * uses this function. */ void cogl_xlib_renderer_set_foreign_display (CoglRenderer *renderer, Display *display); +/** + * cogl_xlib_renderer_set_event_retrieval_enabled: + * @renderer: A #CoglRenderer + * @enable: The new value + * + * Sets whether Cogl should automatically retrieve events from the X + * display. This defaults to %TRUE unless + * cogl_xlib_renderer_set_foreign_display() is called. It can be set + * to %FALSE if the application wants to handle its own event + * retrieval. Note that Cogl still needs to see all of the X events to + * function properly so the application should call + * cogl_xlib_renderer_handle_event() for each event if it disables + * automatic event retrieval. + * + * Since: 1.10 + * Stability: unstable + */ +void +cogl_xlib_renderer_set_event_retrieval_enabled (CoglRenderer *renderer, + gboolean enable); + #define cogl_xlib_renderer_get_display cogl_xlib_renderer_get_display_EXP Display * cogl_xlib_renderer_get_display (CoglRenderer *renderer); diff --git a/cogl/winsys/cogl-winsys-egl-x11.c b/cogl/winsys/cogl-winsys-egl-x11.c index 3506ba964..e4fc6de88 100644 --- a/cogl/winsys/cogl-winsys-egl-x11.c +++ b/cogl/winsys/cogl-winsys-egl-x11.c @@ -564,6 +564,28 @@ _cogl_winsys_xlib_get_visual_info (void) return get_visual_info (ctx->display, egl_display->egl_config); } +static void +_cogl_winsys_poll_get_info (CoglContext *context, + CoglPollFD **poll_fds, + int *n_poll_fds, + gint64 *timeout) +{ + _cogl_xlib_renderer_poll_get_info (context->display->renderer, + poll_fds, + n_poll_fds, + timeout); +} + +static void +_cogl_winsys_poll_dispatch (CoglContext *context, + const CoglPollFD *poll_fds, + int n_poll_fds) +{ + _cogl_xlib_renderer_poll_dispatch (context->display->renderer, + poll_fds, + n_poll_fds); +} + #ifdef EGL_KHR_image_pixmap static gboolean @@ -710,6 +732,9 @@ _cogl_winsys_egl_xlib_get_vtable (void) vtable.xlib_get_visual_info = _cogl_winsys_xlib_get_visual_info; + vtable.poll_get_info = _cogl_winsys_poll_get_info; + vtable.poll_dispatch = _cogl_winsys_poll_dispatch; + #ifdef EGL_KHR_image_pixmap /* X11 tfp support... */ /* XXX: instead of having a rather monolithic winsys vtable we could diff --git a/cogl/winsys/cogl-winsys-glx.c b/cogl/winsys/cogl-winsys-glx.c index 66252de2d..8779af696 100644 --- a/cogl/winsys/cogl-winsys-glx.c +++ b/cogl/winsys/cogl-winsys-glx.c @@ -2051,6 +2051,27 @@ _cogl_winsys_texture_pixmap_x11_get_texture (CoglTexturePixmapX11 *tex_pixmap) return glx_tex_pixmap->glx_tex; } +static void +_cogl_winsys_poll_get_info (CoglContext *context, + CoglPollFD **poll_fds, + int *n_poll_fds, + gint64 *timeout) +{ + _cogl_xlib_renderer_poll_get_info (context->display->renderer, + poll_fds, + n_poll_fds, + timeout); +} + +static void +_cogl_winsys_poll_dispatch (CoglContext *context, + const CoglPollFD *poll_fds, + int n_poll_fds) +{ + _cogl_xlib_renderer_poll_dispatch (context->display->renderer, + poll_fds, + n_poll_fds); +} static CoglWinsysVtable _cogl_winsys_vtable = { @@ -2082,6 +2103,9 @@ static CoglWinsysVtable _cogl_winsys_vtable = _cogl_winsys_onscreen_remove_swap_buffers_callback, .onscreen_set_visibility = _cogl_winsys_onscreen_set_visibility, + .poll_get_info = _cogl_winsys_poll_get_info, + .poll_dispatch = _cogl_winsys_poll_dispatch, + /* X11 tfp support... */ /* XXX: instead of having a rather monolithic winsys vtable we could * perhaps look for a way to separate these... */