From 4d3bf09e60af216774d5b1ec118f420ee0b7137b Mon Sep 17 00:00:00 2001 From: Robert Bragg Date: Wed, 4 May 2011 17:02:04 +0100 Subject: [PATCH] Adds a way for Cogl to control event_mask of foreign wins This extends cogl_onscreen_x11_set_foreign_xid to take a callback to a function that details the event mask the Cogl requires the application to select on foreign windows. This is required because Cogl, for example, needs to track size changes of a window and may also in the future want other notifications such as map/unmap. Most applications wont need to use the foreign xwindow apis, but those that do are required to pass a valid callback and update the event mask of their window according to Cogl's requirements. --- clutter/cogl/cogl/cogl-framebuffer-private.h | 2 + clutter/cogl/cogl/cogl-framebuffer.c | 10 +++- clutter/cogl/cogl/cogl-framebuffer.h | 58 +++++++++++++++++++- clutter/cogl/cogl/winsys/cogl-winsys-egl.c | 11 +++- clutter/cogl/cogl/winsys/cogl-winsys-glx.c | 11 +++- clutter/cogl/examples/x11-foreign.c | 22 +++++++- clutter/glx/clutter-stage-glx.c | 9 ++- clutter/x11/clutter-stage-x11.c | 29 ++++++---- clutter/x11/clutter-stage-x11.h | 17 ++++++ 9 files changed, 151 insertions(+), 18 deletions(-) diff --git a/clutter/cogl/cogl/cogl-framebuffer-private.h b/clutter/cogl/cogl/cogl-framebuffer-private.h index 278cd1564..f48938f18 100644 --- a/clutter/cogl/cogl/cogl-framebuffer-private.h +++ b/clutter/cogl/cogl/cogl-framebuffer-private.h @@ -118,6 +118,8 @@ struct _CoglOnscreen #ifdef COGL_HAS_X11_SUPPORT guint32 foreign_xid; + CoglOnscreenX11MaskCallback foreign_update_mask_callback; + void *foreign_update_mask_data; #endif gboolean swap_throttled; diff --git a/clutter/cogl/cogl/cogl-framebuffer.c b/clutter/cogl/cogl/cogl-framebuffer.c index 071b9ec88..daf817ab2 100644 --- a/clutter/cogl/cogl/cogl-framebuffer.c +++ b/clutter/cogl/cogl/cogl-framebuffer.c @@ -1624,9 +1624,17 @@ cogl_framebuffer_swap_region (CoglFramebuffer *framebuffer, #ifdef COGL_HAS_X11_SUPPORT void cogl_onscreen_x11_set_foreign_window_xid (CoglOnscreen *onscreen, - guint32 xid) + guint32 xid, + CoglOnscreenX11MaskCallback update, + void *user_data) { + /* We don't wan't applications to get away with being lazy here and not + * passing an update callback... */ + g_return_if_fail (update); + onscreen->foreign_xid = xid; + onscreen->foreign_update_mask_callback = update; + onscreen->foreign_update_mask_data = user_data; } guint32 diff --git a/clutter/cogl/cogl/cogl-framebuffer.h b/clutter/cogl/cogl/cogl-framebuffer.h index 3f4ecb8a5..b685031ac 100644 --- a/clutter/cogl/cogl/cogl-framebuffer.h +++ b/clutter/cogl/cogl/cogl-framebuffer.h @@ -86,11 +86,67 @@ CoglOnscreen * cogl_onscreen_new (CoglContext *context, int width, int height); #ifdef COGL_HAS_X11 +typedef void (*CoglOnscreenX11MaskCallback) (CoglOnscreen *onscreen, + guint32 event_mask, + void *user_data); + +/** + * cogl_onscreen_x11_set_foreign_window_xid: + * @onscreen: The unallocated framebuffer to associated with an X + * window. + * @xid: The XID of an existing X window + * @update: A callback that notifies of updates to what Cogl requires + * to be in the core X protocol event mask. + * + * Ideally we would recommend that you let Cogl be responsible for + * creating any X window required to back an onscreen framebuffer but + * if you really need to target a window created manually this + * function can be called before @onscreen has been allocated to set a + * foreign XID for your existing X window. + * + * Since Cogl needs, for example, to track changes to the size of an X + * window it requires that certain events be selected for via the core + * X protocol. This requirement may also be changed asynchronously so + * you must pass in an @update callback to inform you of Cogl's + * required event mask. + * + * For example if you are using Xlib you could use this API roughly + * as follows: + * [{ + * static void + * my_update_cogl_x11_event_mask (CoglOnscreen *onscreen, + * guint32 event_mask, + * void *user_data) + * { + * XSetWindowAttributes attrs; + * MyData *data = user_data; + * attrs.event_mask = event_mask | data->my_event_mask; + * XChangeWindowAttributes (data->xdpy, + * data->xwin, + * CWEventMask, + * &attrs); + * } + * + * { + * *snip* + * cogl_onscreen_x11_set_foreign_window_xid (onscreen, + * data->xwin, + * my_update_cogl_x11_event_mask, + * data); + * *snip* + * } + * }] + * + * Since: 2.0 + * Stability: Unstable + */ #define cogl_onscreen_x11_set_foreign_window_xid \ cogl_onscreen_x11_set_foreign_window_xid_EXP void cogl_onscreen_x11_set_foreign_window_xid (CoglOnscreen *onscreen, - guint32 xid); + guint32 xid, + CoglOnscreenX11MaskCallback update, + void *user_data); #define cogl_onscreen_x11_get_window_xid cogl_onscreen_x11_get_window_xid_EXP guint32 diff --git a/clutter/cogl/cogl/winsys/cogl-winsys-egl.c b/clutter/cogl/cogl/winsys/cogl-winsys-egl.c index 0ffd48b40..22fd611db 100644 --- a/clutter/cogl/cogl/winsys/cogl-winsys-egl.c +++ b/clutter/cogl/cogl/winsys/cogl-winsys-egl.c @@ -68,6 +68,8 @@ #ifdef COGL_HAS_EGL_PLATFORM_POWERVR_X11_SUPPORT #include + +#define COGL_ONSCREEN_X11_EVENT_MASK StructureNotifyMask #endif typedef struct _CoglRendererEGL @@ -922,6 +924,11 @@ _cogl_winsys_onscreen_init (CoglOnscreen *onscreen, _cogl_framebuffer_winsys_update_size (framebuffer, attr.width, attr.height); + + /* Make sure the app selects for the events we require... */ + onscreen->foreign_update_mask_callback (onscreen, + COGL_ONSCREEN_X11_EVENT_MASK, + onscreen->foreign_update_mask_data); } else { @@ -957,7 +964,9 @@ _cogl_winsys_onscreen_init (CoglOnscreen *onscreen, DefaultRootWindow (xlib_renderer->xdpy), xvisinfo->visual, AllocNone); - mask = CWBorderPixel | CWColormap; + attr.event_mask = COGL_ONSCREEN_X11_EVENT_MASK; + + mask = CWBorderPixel | CWColormap | CWEventMask; xwin = XCreateWindow (xlib_renderer->xdpy, DefaultRootWindow (xlib_renderer->xdpy), diff --git a/clutter/cogl/cogl/winsys/cogl-winsys-glx.c b/clutter/cogl/cogl/winsys/cogl-winsys-glx.c index 47a207f2b..5948dde27 100644 --- a/clutter/cogl/cogl/winsys/cogl-winsys-glx.c +++ b/clutter/cogl/cogl/winsys/cogl-winsys-glx.c @@ -64,6 +64,8 @@ typedef CoglFuncPtr (*GLXGetProcAddressProc) (const GLubyte *procName); #include #endif +#define COGL_ONSCREEN_X11_EVENT_MASK StructureNotifyMask + typedef struct _CoglContextGLX { GLXDrawable current_drawable; @@ -756,6 +758,11 @@ _cogl_winsys_onscreen_init (CoglOnscreen *onscreen, _cogl_framebuffer_winsys_update_size (framebuffer, attr.width, attr.height); + + /* Make sure the app selects for the events we require... */ + onscreen->foreign_update_mask_callback (onscreen, + COGL_ONSCREEN_X11_EVENT_MASK, + onscreen->foreign_update_mask_data); } else { @@ -792,7 +799,9 @@ _cogl_winsys_onscreen_init (CoglOnscreen *onscreen, DefaultRootWindow (xlib_renderer->xdpy), xvisinfo->visual, AllocNone); - mask = CWBorderPixel | CWColormap; + xattr.event_mask = COGL_ONSCREEN_X11_EVENT_MASK; + + mask = CWBorderPixel | CWColormap | CWEventMask; xwin = XCreateWindow (xlib_renderer->xdpy, DefaultRootWindow (xlib_renderer->xdpy), diff --git a/clutter/cogl/examples/x11-foreign.c b/clutter/cogl/examples/x11-foreign.c index d82e8388d..701256263 100644 --- a/clutter/cogl/examples/x11-foreign.c +++ b/clutter/cogl/examples/x11-foreign.c @@ -5,6 +5,24 @@ #include #include +static void +update_cogl_x11_event_mask (CoglOnscreen *onscreen, + guint32 event_mask, + void *user_data) +{ + XDisplay *xdpy = user_data; + XSetWindowAttributes attrs; + guint32 xwin; + + attrs.event_mask = event_mask; + xwin = cogl_onscreen_x11_get_window_xid (onscreen); + + XChangeWindowAttributes (xdpy, + (Window)xwin, + CWEventMask, + &attrs); +} + int main (int argc, char **argv) { @@ -110,7 +128,9 @@ main (int argc, char **argv) XFree (xvisinfo); - cogl_onscreen_x11_set_foreign_window_xid (onscreen, xwin); + cogl_onscreen_x11_set_foreign_window_xid (onscreen, xwin, + update_cogl_x11_event_mask, + xdpy); fb = COGL_FRAMEBUFFER (onscreen); /* Eventually there will be an implicit allocate on first use so this diff --git a/clutter/glx/clutter-stage-glx.c b/clutter/glx/clutter-stage-glx.c index 0c0ab015d..8a7a41461 100644 --- a/clutter/glx/clutter-stage-glx.c +++ b/clutter/glx/clutter-stage-glx.c @@ -121,8 +121,13 @@ clutter_stage_glx_realize (ClutterStageWindow *stage_window) stage_glx->onscreen = cogl_onscreen_new (backend->cogl_context, width, height); if (stage_x11->xwin != None) - cogl_onscreen_x11_set_foreign_window_xid (stage_glx->onscreen, - stage_x11->xwin); + { + cogl_onscreen_x11_set_foreign_window_xid ( + stage_glx->onscreen, + stage_x11->xwin, + _clutter_stage_x11_update_foreign_event_mask, + stage_x11); + } clutter_vblank = _clutter_backend_glx_get_vblank (); if (clutter_vblank && strcmp (clutter_vblank, "none") == 0) diff --git a/clutter/x11/clutter-stage-x11.c b/clutter/x11/clutter-stage-x11.c index d0553b0be..ab877b906 100644 --- a/clutter/x11/clutter-stage-x11.c +++ b/clutter/x11/clutter-stage-x11.c @@ -387,6 +387,23 @@ clutter_stage_x11_unrealize (ClutterStageWindow *stage_window) } } +void +_clutter_stage_x11_update_foreign_event_mask (CoglOnscreen *onscreen, + guint32 event_mask, + void *user_data) +{ + ClutterStageX11 *stage_x11 = user_data; + ClutterBackendX11 *backend_x11 = stage_x11->backend; + XSetWindowAttributes attrs; + + attrs.event_mask = event_mask | CLUTTER_STAGE_X11_EVENT_MASK; + + XChangeWindowAttributes (backend_x11->xdpy, + stage_x11->xwin, + CWEventMask, + &attrs); +} + static gboolean clutter_stage_x11_realize (ClutterStageWindow *stage_window) { @@ -412,17 +429,7 @@ clutter_stage_x11_realize (ClutterStageWindow *stage_window) * because key events are broken with that extension, and will * be fixed by XI2 */ - event_flags = StructureNotifyMask - | FocusChangeMask - | ExposureMask - | PropertyChangeMask - | EnterWindowMask - | LeaveWindowMask - | KeyPressMask - | KeyReleaseMask - | ButtonPressMask - | ButtonReleaseMask - | PointerMotionMask; + event_flags = CLUTTER_STAGE_X11_EVENT_MASK; /* we unconditionally select input events even with event retrieval * disabled because we need to guarantee that the Clutter internal diff --git a/clutter/x11/clutter-stage-x11.h b/clutter/x11/clutter-stage-x11.h index 71732f5b7..a070c589f 100644 --- a/clutter/x11/clutter-stage-x11.h +++ b/clutter/x11/clutter-stage-x11.h @@ -78,8 +78,25 @@ struct _ClutterStageX11Class GObjectClass parent_class; }; +#define CLUTTER_STAGE_X11_EVENT_MASK \ + StructureNotifyMask | \ + FocusChangeMask | \ + ExposureMask | \ + PropertyChangeMask | \ + EnterWindowMask | \ + LeaveWindowMask | \ + KeyPressMask | \ + KeyReleaseMask | \ + ButtonPressMask | \ + ButtonReleaseMask | \ + PointerMotionMask; + GType _clutter_stage_x11_get_type (void) G_GNUC_CONST; +void _clutter_stage_x11_update_foreign_event_mask (CoglOnscreen *onscreen, + guint32 event_mask, + void *user_data); + /* Private to subclasses */ void _clutter_stage_x11_set_user_time (ClutterStageX11 *stage_x11, guint32 user_time);