diff --git a/ChangeLog b/ChangeLog index 81b9484fc..96e4afbb7 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,32 @@ +2008-04-15 Matthew Allum + + Work related to #873; + + * clutter/glx/clutter-backend-glx.c: + * clutter/glx/clutter-backend-glx.h: + * clutter/x11/clutter-x11-texture-pixmap.c: + * clutter/x11/clutter-x11-texture-pixmap.h: + General cleanup of texture pixmap code, adding; + - Pixmap dimentions and depth now auto probed, read only props. + - More X safety traps + - Add support for optionally tracking damage and automatically + updating texture. + + * clutter/glx/clutter-glx-texture-pixmap.c: + * clutter/glx/clutter-glx-texture-pixmap.h: + General cleanup and some safety additions. Needs more work so + 'proper' subclass - dependent on new COGL. + + * clutter/x11/clutter-backend-x11.c: (clutter_x11_remove_filter): + Invert g_return_if check. + + * configure.ac: + Pull in XComposite and XDamage (at least for now) + + * tests/Makefile.am: + * tests/test-pixmap.c: + Add a modified test from Johan for above. + 2008-04-15 Neil Roberts Added support for foreign windows to the Win32 backend. diff --git a/clutter/glx/clutter-backend-glx.c b/clutter/glx/clutter-backend-glx.c index 34b9c2304..f67042e9f 100644 --- a/clutter/glx/clutter-backend-glx.c +++ b/clutter/glx/clutter-backend-glx.c @@ -342,18 +342,6 @@ clutter_backend_glx_get_features (ClutterBackend *backend) } } - /* Check for the texture from pixmap extension */ - if (cogl_check_extension ("GLX_EXT_texture_from_pixmap", glx_extensions)) - { - backend_glx->bind_tex_image = - (BindTexImage)cogl_get_proc_address ("glXBindTexImageEXT"); - backend_glx->release_tex_image = - (ReleaseTexImage)cogl_get_proc_address ("glXReleaseTexImageEXT"); - - if (backend_glx->bind_tex_image && backend_glx->release_tex_image) - backend_glx->t_f_p = TRUE; - } - CLUTTER_NOTE (MISC, "backend features checked"); return flags; diff --git a/clutter/glx/clutter-backend-glx.h b/clutter/glx/clutter-backend-glx.h index 9f0755cd3..fadffd3ad 100644 --- a/clutter/glx/clutter-backend-glx.h +++ b/clutter/glx/clutter-backend-glx.h @@ -59,14 +59,6 @@ typedef int (*WaitVideoSyncProc) (int divisor, int remainder, unsigned int *count); typedef int (*SwapIntervalProc) (int interval); -typedef void (*BindTexImage) (Display *display, - GLXDrawable drawable, - int buffer, - int *attribList); -typedef void (*ReleaseTexImage) (Display *display, - GLXDrawable drawable, - int buffer); - struct _ClutterBackendGLX { @@ -82,11 +74,6 @@ struct _ClutterBackendGLX gint dri_fd; ClutterGLXVBlankType vblank_type; - /* texture from pixmap stuff */ - gboolean t_f_p; - BindTexImage bind_tex_image; - ReleaseTexImage release_tex_image; - /* props */ Atom atom_WM_STATE; Atom atom_WM_STATE_FULLSCREEN; diff --git a/clutter/glx/clutter-glx-texture-pixmap.c b/clutter/glx/clutter-glx-texture-pixmap.c index d5b267f00..420e551f1 100644 --- a/clutter/glx/clutter-glx-texture-pixmap.c +++ b/clutter/glx/clutter-glx-texture-pixmap.c @@ -48,13 +48,18 @@ #include "cogl.h" -enum -{ - PROP_PIXMAP = 1, - PROP_PIXMAP_WIDTH, - PROP_PIXMAP_HEIGHT, - PROP_DEPTH -}; +typedef void (*BindTexImage) (Display *display, + GLXDrawable drawable, + int buffer, + int *attribList); +typedef void (*ReleaseTexImage) (Display *display, + GLXDrawable drawable, + int buffer); + +static BindTexImage _gl_bind_tex_image = NULL; +static ReleaseTexImage _gl_release_tex_image = NULL; +static gboolean _have_tex_from_pixmap_ext = FALSE; +static gboolean _ext_check_done = FALSE; struct _ClutterGLXTexturePixmapPrivate { @@ -62,32 +67,44 @@ struct _ClutterGLXTexturePixmapPrivate guint texture_id; GLXPixmap glx_pixmap; gboolean bound; + }; -static ClutterBackendGLX *backend = NULL; +static void +clutter_glx_texture_pixmap_class_init (ClutterGLXTexturePixmapClass *klass); -static void clutter_glx_texture_pixmap_class_init (ClutterGLXTexturePixmapClass *klass); -static void clutter_glx_texture_pixmap_init (ClutterGLXTexturePixmap *self); -static GObject *clutter_glx_texture_pixmap_constructor (GType type, - guint n_construct_properties, - GObjectConstructParam *construct_properties); -static void clutter_glx_texture_pixmap_dispose (GObject *object); -static void clutter_glx_texture_pixmap_notify (GObject *object, - GParamSpec *pspec); +static void +clutter_glx_texture_pixmap_init (ClutterGLXTexturePixmap *self); -static void clutter_glx_texture_pixmap_realize (ClutterActor *actor); -static void clutter_glx_texture_pixmap_unrealize (ClutterActor *actor); -static void clutter_glx_texture_pixmap_paint (ClutterActor *actor); +static void +clutter_glx_texture_pixmap_dispose (GObject *object); -static void clutter_glx_texture_pixmap_update_area (ClutterX11TexturePixmap *texture, - gint x, - gint y, - gint width, - gint height); +static void +clutter_glx_texture_pixmap_notify (GObject *object, + GParamSpec *pspec); -static void clutter_glx_texture_pixmap_create_glx_pixmap (ClutterGLXTexturePixmap *texture); +static void +clutter_glx_texture_pixmap_realize (ClutterActor *actor); -G_DEFINE_TYPE (ClutterGLXTexturePixmap, clutter_glx_texture_pixmap, CLUTTER_X11_TYPE_TEXTURE_PIXMAP); +static void +clutter_glx_texture_pixmap_unrealize (ClutterActor *actor); + +static void +clutter_glx_texture_pixmap_paint (ClutterActor *actor); + +static void +clutter_glx_texture_pixmap_update_area (ClutterX11TexturePixmap *texture, + gint x, + gint y, + gint width, + gint height); + +static void +clutter_glx_texture_pixmap_create_glx_pixmap (ClutterGLXTexturePixmap *tex); + +G_DEFINE_TYPE (ClutterGLXTexturePixmap, \ + clutter_glx_texture_pixmap, \ + CLUTTER_X11_TYPE_TEXTURE_PIXMAP); static void clutter_glx_texture_pixmap_class_init (ClutterGLXTexturePixmapClass *klass) @@ -96,11 +113,9 @@ clutter_glx_texture_pixmap_class_init (ClutterGLXTexturePixmapClass *klass) ClutterActorClass *actor_class = CLUTTER_ACTOR_CLASS (klass); ClutterX11TexturePixmapClass *x11_texture_class = CLUTTER_X11_TEXTURE_PIXMAP_CLASS (klass); - ClutterBackend *default_backend; g_type_class_add_private (klass, sizeof (ClutterGLXTexturePixmapPrivate)); - object_class->constructor = clutter_glx_texture_pixmap_constructor; object_class->dispose = clutter_glx_texture_pixmap_dispose; object_class->notify = clutter_glx_texture_pixmap_notify; @@ -110,17 +125,28 @@ clutter_glx_texture_pixmap_class_init (ClutterGLXTexturePixmapClass *klass) x11_texture_class->update_area = clutter_glx_texture_pixmap_update_area; - default_backend = clutter_get_default_backend (); - if (!CLUTTER_IS_BACKEND_GLX (default_backend)) + if (_ext_check_done == FALSE) { - g_critical ("ClutterGLXTexturePixmap instanciated with a " - "non-GLX backend"); - return; + const gchar *glx_extensions = NULL; + + glx_extensions = + glXQueryExtensionsString (clutter_x11_get_default_display (), + clutter_x11_get_default_screen ()); + + /* Check for the texture from pixmap extension */ + if (cogl_check_extension ("GLX_EXT_texture_from_pixmap", glx_extensions)) + { + _gl_bind_tex_image = + (BindTexImage)cogl_get_proc_address ("glXBindTexImageEXT"); + _gl_release_tex_image = + (ReleaseTexImage)cogl_get_proc_address ("glXReleaseTexImageEXT"); + + if (_gl_bind_tex_image && _gl_release_tex_image) + _have_tex_from_pixmap_ext = TRUE; + } + + _ext_check_done = TRUE; } - - backend = (ClutterBackendGLX *)default_backend; -/* backend->t_f_p = FALSE;*/ - } static void @@ -133,40 +159,29 @@ clutter_glx_texture_pixmap_init (ClutterGLXTexturePixmap *self) CLUTTER_GLX_TYPE_TEXTURE_PIXMAP, ClutterGLXTexturePixmapPrivate); - if (clutter_feature_available (CLUTTER_FEATURE_TEXTURE_RECTANGLE)) priv->target_type = CGL_TEXTURE_RECTANGLE_ARB; else priv->target_type = CGL_TEXTURE_2D; } -static GObject * -clutter_glx_texture_pixmap_constructor (GType type, - guint n_construct_properties, - GObjectConstructParam *construct_properties) -{ - GObject *object = G_OBJECT_CLASS (clutter_glx_texture_pixmap_parent_class)-> - constructor (type, n_construct_properties, construct_properties); - - g_object_set (object, - "sync-size", FALSE, - NULL); - - return object; -} - static void clutter_glx_texture_pixmap_dispose (GObject *object) { - ClutterGLXTexturePixmapPrivate *priv = CLUTTER_GLX_TEXTURE_PIXMAP (object)->priv; + ClutterGLXTexturePixmapPrivate *priv; + + priv = CLUTTER_GLX_TEXTURE_PIXMAP (object)->priv; if (priv->glx_pixmap != None) { clutter_x11_trap_x_errors (); - glXDestroyGLXPixmap (((ClutterBackendX11 *)backend)->xdpy, + + glXDestroyGLXPixmap (clutter_x11_get_default_display(), priv->glx_pixmap); - XSync (((ClutterBackendX11 *)backend)->xdpy, FALSE); + XSync (clutter_x11_get_default_display(), FALSE); + clutter_x11_untrap_x_errors (); + priv->glx_pixmap = None; } @@ -179,7 +194,6 @@ clutter_glx_texture_pixmap_notify (GObject *object, GParamSpec *pspec) if (g_str_equal (pspec->name, "pixmap")) { ClutterGLXTexturePixmap *texture = CLUTTER_GLX_TEXTURE_PIXMAP (object); - clutter_glx_texture_pixmap_create_glx_pixmap (texture); } } @@ -187,17 +201,17 @@ clutter_glx_texture_pixmap_notify (GObject *object, GParamSpec *pspec) static void clutter_glx_texture_pixmap_realize (ClutterActor *actor) { - ClutterGLXTexturePixmapPrivate *priv = - CLUTTER_GLX_TEXTURE_PIXMAP (actor)->priv; - COGLenum pixel_type, pixel_format, - filter_quality; - gboolean repeat_x, repeat_y; - guint width, height; + ClutterGLXTexturePixmapPrivate *priv; + COGLenum pixel_type, pixel_format,filter_quality; + gboolean repeat_x, repeat_y; + guint width, height; - if (!backend->t_f_p) + priv = CLUTTER_GLX_TEXTURE_PIXMAP (actor)->priv; + + if (!_have_tex_from_pixmap_ext) { CLUTTER_ACTOR_CLASS (clutter_glx_texture_pixmap_parent_class)-> - realize (actor); + realize (actor); return; } @@ -233,11 +247,13 @@ clutter_glx_texture_pixmap_realize (ClutterActor *actor) static void clutter_glx_texture_pixmap_unrealize (ClutterActor *actor) { - ClutterGLXTexturePixmapPrivate *priv = - CLUTTER_GLX_TEXTURE_PIXMAP (actor)->priv; - Display *dpy = ((ClutterBackendX11 *)backend)->xdpy; + ClutterGLXTexturePixmapPrivate *priv; + Display *dpy; - if (!backend->t_f_p) + priv = CLUTTER_GLX_TEXTURE_PIXMAP (actor)->priv; + dpy = clutter_x11_get_default_display(); + + if (!_have_tex_from_pixmap_ext) { CLUTTER_ACTOR_CLASS (clutter_glx_texture_pixmap_parent_class)-> unrealize (actor); @@ -249,9 +265,14 @@ clutter_glx_texture_pixmap_unrealize (ClutterActor *actor) if (priv->bound && priv->glx_pixmap) { - (backend->release_tex_image) (dpy, - priv->glx_pixmap, - GLX_FRONT_LEFT_EXT); + clutter_x11_trap_x_errors (); + + (_gl_release_tex_image) (dpy, + priv->glx_pixmap, + GLX_FRONT_LEFT_EXT); + + XSync (clutter_x11_get_default_display(), FALSE); + clutter_x11_untrap_x_errors (); } cogl_textures_destroy (1, &priv->texture_id); @@ -314,7 +335,7 @@ clutter_glx_texture_pixmap_paint (ClutterActor *actor) gint x_1, y_1, x_2, y_2; ClutterColor col = { 0xff, 0xff, 0xff, 0xff }; - if (!backend->t_f_p) + if (!_have_tex_from_pixmap_ext) { CLUTTER_ACTOR_CLASS (clutter_glx_texture_pixmap_parent_class)-> paint (actor); @@ -354,11 +375,13 @@ get_fbconfig_for_depth (guint depth) { GLXFBConfig *fbconfigs, *ret = NULL; int n_elements, i, found; - Display *dpy = ((ClutterBackendX11 *)backend)->xdpy; + Display *dpy; int db, stencil, alpha, mipmap, rgba, value; + dpy = clutter_x11_get_default_display (); + fbconfigs = glXGetFBConfigs (dpy, - ((ClutterBackendX11 *)backend)->xscreen_num, + clutter_x11_get_default_screen (), &n_elements); db = G_MAXSHORT; @@ -404,7 +427,6 @@ get_fbconfig_for_depth (guint depth) fbconfigs[i], GLX_BIND_TO_TEXTURE_RGBA_EXT, &value); - if (value) rgba = 1; } @@ -462,12 +484,17 @@ clutter_glx_texture_pixmap_create_glx_pixmap (ClutterGLXTexturePixmap *texture) GLXPixmap glx_pixmap; int attribs[7], i = 0; GLXFBConfig *fbconfig; - Display *dpy = ((ClutterBackendX11 *)backend)->xdpy; + Display *dpy; guint depth; Pixmap pixmap; + ClutterBackendGLX *backend_glx; + + backend_glx = CLUTTER_BACKEND_GLX(clutter_get_default_backend ()); + + dpy = clutter_x11_get_default_display (); g_object_get (texture, - "depth", &depth, + "pixmap-depth", &depth, "pixmap", &pixmap, NULL); @@ -522,15 +549,23 @@ clutter_glx_texture_pixmap_create_glx_pixmap (ClutterGLXTexturePixmap *texture) { if (priv->glx_pixmap) { - if (backend->t_f_p && + if (_have_tex_from_pixmap_ext && CLUTTER_ACTOR_IS_REALIZED (texture) && priv->bound) { cogl_texture_bind (priv->target_type, priv->texture_id); - (backend->release_tex_image) (dpy, - priv->glx_pixmap, - GLX_FRONT_LEFT_EXT); + clutter_x11_trap_x_errors (); + + (_gl_release_tex_image) (dpy, + priv->glx_pixmap, + GLX_FRONT_LEFT_EXT); + + XSync (clutter_x11_get_default_display(), FALSE); + + if (clutter_x11_untrap_x_errors ()) + g_warning ("Failed to bind texture pixmap"); + } clutter_x11_trap_x_errors (); @@ -551,16 +586,17 @@ clutter_glx_texture_pixmap_update_area (ClutterX11TexturePixmap *texture, gint height) { ClutterGLXTexturePixmapPrivate *priv; - Display *dpy = - ((ClutterBackendX11 *)backend)->xdpy; + Display *dpy; priv = CLUTTER_GLX_TEXTURE_PIXMAP (texture)->priv; + dpy = clutter_x11_get_default_display(); - if (!backend->t_f_p) + if (!_have_tex_from_pixmap_ext) { - CLUTTER_X11_TEXTURE_PIXMAP_CLASS (texture)->update_area (texture, - x, y, - width, height); + CLUTTER_X11_TEXTURE_PIXMAP_CLASS + (texture)->update_area (texture, + x, y, + width, height); return; } @@ -569,12 +605,19 @@ clutter_glx_texture_pixmap_update_area (ClutterX11TexturePixmap *texture, cogl_texture_bind (priv->target_type, priv->texture_id); - if (backend->t_f_p) + if (_have_tex_from_pixmap_ext) { - (backend->bind_tex_image) (dpy, - priv->glx_pixmap, - GLX_FRONT_LEFT_EXT, - NULL); + clutter_x11_trap_x_errors (); + + (_gl_bind_tex_image) (dpy, + priv->glx_pixmap, + GLX_FRONT_LEFT_EXT, + NULL); + + XSync (clutter_x11_get_default_display(), FALSE); + + if (clutter_x11_untrap_x_errors ()) + g_warning ("Failed to bind texture pixmap"); priv->bound = TRUE; } @@ -592,18 +635,12 @@ clutter_glx_texture_pixmap_update_area (ClutterX11TexturePixmap *texture, * Since: 0.8 **/ ClutterActor * -clutter_glx_texture_pixmap_new_with_pixmap (Pixmap pixmap, - guint width, - guint height, - guint depth) +clutter_glx_texture_pixmap_new_with_pixmap (Pixmap pixmap) { ClutterActor *actor; actor = g_object_new (CLUTTER_GLX_TYPE_TEXTURE_PIXMAP, "pixmap", pixmap, - "pixmap-width", width, - "pixmap-height", height, - "depth", depth, NULL); return actor; diff --git a/clutter/glx/clutter-glx-texture-pixmap.h b/clutter/glx/clutter-glx-texture-pixmap.h index a24ebe6c2..f77f17f86 100644 --- a/clutter/glx/clutter-glx-texture-pixmap.h +++ b/clutter/glx/clutter-glx-texture-pixmap.h @@ -60,10 +60,7 @@ GType clutter_glx_texture_pixmap_get_type (void); ClutterActor * clutter_glx_texture_pixmap_new (void); -ClutterActor * clutter_glx_texture_pixmap_new_with_pixmap (Pixmap pixmap, - guint width, - guint height, - guint depth); +ClutterActor * clutter_glx_texture_pixmap_new_with_pixmap (Pixmap pixmap); G_END_DECLS diff --git a/clutter/x11/clutter-backend-x11.c b/clutter/x11/clutter-backend-x11.c index 908574b98..1fbf0e72e 100644 --- a/clutter/x11/clutter-backend-x11.c +++ b/clutter/x11/clutter-backend-x11.c @@ -507,7 +507,7 @@ clutter_x11_remove_filter (ClutterX11FilterFunc func, GSList *tmp_list, *this; ClutterX11EventFilter *filter; - g_return_if_fail (func == NULL); + g_return_if_fail (func != NULL); tmp_list = backend_singleton->event_filters; diff --git a/clutter/x11/clutter-x11-texture-pixmap.c b/clutter/x11/clutter-x11-texture-pixmap.c index af17d508a..32685401f 100644 --- a/clutter/x11/clutter-x11-texture-pixmap.c +++ b/clutter/x11/clutter-x11-texture-pixmap.c @@ -47,21 +47,36 @@ #include "cogl.h" +/* FIXME: Check exts exist in autogen */ +#include +#include + enum { PROP_PIXMAP = 1, PROP_PIXMAP_WIDTH, PROP_PIXMAP_HEIGHT, - PROP_DEPTH + PROP_DEPTH, + PROP_AUTO }; enum { UPDATE_AREA, - + /* FIXME: Pixmap lost signal? */ LAST_SIGNAL }; +static ClutterX11FilterReturn +on_x_event_filter (XEvent *xev, ClutterEvent *cev, gpointer data); + +static void +clutter_x11_texture_pixmap_update_area_real (ClutterX11TexturePixmap *texture, + gint x, + gint y, + gint width, + gint height); + static guint signals[LAST_SIGNAL] = { 0, }; struct _ClutterX11TexturePixmapPrivate @@ -72,133 +87,128 @@ struct _ClutterX11TexturePixmapPrivate XImage *image; + gboolean automatic_updates; + Damage damage; + }; -static ClutterBackendX11 *backend = NULL; +static int _damage_event_base = 0; -static void clutter_x11_texture_pixmap_class_init (ClutterX11TexturePixmapClass *klass); -static void clutter_x11_texture_pixmap_init (ClutterX11TexturePixmap *self); -static GObject *clutter_x11_texture_pixmap_constructor (GType type, - guint n_construct_properties, - GObjectConstructParam *construct_properties); -static void clutter_x11_texture_pixmap_dispose (GObject *object); -static void clutter_x11_texture_pixmap_set_property (GObject *object, - guint prop_id, - const GValue *value, - GParamSpec *pspec); -static void clutter_x11_texture_pixmap_get_property (GObject *object, - guint prop_id, - GValue *value, - GParamSpec *pspec); +/* FIXME: Ultimatly with current cogl we should subclass clutter actor */ +G_DEFINE_TYPE (ClutterX11TexturePixmap, \ + clutter_x11_texture_pixmap, \ + CLUTTER_TYPE_TEXTURE); -static void clutter_x11_texture_pixmap_realize (ClutterActor *actor); -static void clutter_x11_texture_pixmap_update_area_real (ClutterX11TexturePixmap *texture, - gint x, - gint y, - gint width, - gint height); - -G_DEFINE_TYPE (ClutterX11TexturePixmap, clutter_x11_texture_pixmap, CLUTTER_TYPE_TEXTURE); - -static void -clutter_x11_texture_pixmap_class_init (ClutterX11TexturePixmapClass *klass) +static gboolean +check_extensions (ClutterX11TexturePixmap *texture) { - GObjectClass *object_class = G_OBJECT_CLASS (klass); - ClutterActorClass *actor_class = CLUTTER_ACTOR_CLASS (klass); - GParamSpec *pspec; - ClutterBackend *default_backend; + int event_base, error_base; + int damage_error; + ClutterX11TexturePixmapPrivate *priv; + Display *dpy; - g_type_class_add_private (klass, sizeof (ClutterX11TexturePixmapPrivate)); + priv = texture->priv; - object_class->constructor = clutter_x11_texture_pixmap_constructor; - object_class->dispose = clutter_x11_texture_pixmap_dispose; - object_class->set_property = clutter_x11_texture_pixmap_set_property; - object_class->get_property = clutter_x11_texture_pixmap_get_property; + if (_damage_event_base) + return TRUE; - actor_class->realize = clutter_x11_texture_pixmap_realize; + dpy = clutter_x11_get_default_display(); - klass->update_area = clutter_x11_texture_pixmap_update_area_real; - - pspec = g_param_spec_uint ("pixmap", - "Pixmap", - "The X Pixmap to which this texture will be bound", - 0, G_MAXINT, - None, - G_PARAM_READWRITE | G_PARAM_CONSTRUCT); - - g_object_class_install_property (object_class, - PROP_PIXMAP, - pspec); - - pspec = g_param_spec_uint ("pixmap-width", - "Pixmap width", - "The width of the " - "pixmap bound to this texture", - 0, G_MAXUINT, - 0, - G_PARAM_READWRITE | G_PARAM_CONSTRUCT); - - g_object_class_install_property (object_class, - PROP_PIXMAP_WIDTH, - pspec); - - pspec = g_param_spec_uint ("pixmap-height", - "Pixmap height", - "The height of the " - "pixmap bound to this texture", - 0, G_MAXUINT, - 0, - G_PARAM_READWRITE | G_PARAM_CONSTRUCT); - - g_object_class_install_property (object_class, - PROP_PIXMAP_HEIGHT, - pspec); - - pspec = g_param_spec_uint ("depth", - "Depth", - "The depth (in number of bits) of the " - "pixmap bound to this texture", - 0, G_MAXUINT, - 0, - G_PARAM_READWRITE | G_PARAM_CONSTRUCT); - - g_object_class_install_property (object_class, - PROP_DEPTH, - pspec); - /** - * ClutterX11TexturePixmap::update-area: - * @texture: the object which received the signal - * - * The ::hide signal is emitted to ask the texture to update its - * content from its source pixmap. - * - * Since: 0.8 - */ - signals[UPDATE_AREA] = - g_signal_new ("update-area", - G_TYPE_FROM_CLASS (object_class), - G_SIGNAL_RUN_FIRST, - G_STRUCT_OFFSET (ClutterX11TexturePixmapClass, update_area), - NULL, NULL, - clutter_marshal_VOID__INT_INT_INT_INT, - G_TYPE_NONE, 4, - G_TYPE_INT, - G_TYPE_INT, - G_TYPE_INT, - G_TYPE_INT); - - default_backend = clutter_get_default_backend (); - if (!CLUTTER_IS_BACKEND_X11 (default_backend)) + if (!XCompositeQueryExtension (dpy, &event_base, &error_base)) { - g_critical ("ClutterX11TexturePixmap instanciated with a " - "non-X11 backend"); - return; + g_warning ("No composite extension\n"); + return FALSE; } - backend = (ClutterBackendX11 *)default_backend; + if (!XDamageQueryExtension (dpy, + &_damage_event_base, &damage_error)) + { + g_warning ("No Damage extension\n"); + return FALSE; + } + return TRUE; } +static ClutterX11FilterReturn +on_x_event_filter (XEvent *xev, ClutterEvent *cev, gpointer data) +{ + ClutterX11TexturePixmap *texture; + ClutterX11TexturePixmapPrivate *priv; + Display *dpy; + + texture = CLUTTER_X11_TEXTURE_PIXMAP (data); + + g_return_val_if_fail (CLUTTER_X11_IS_TEXTURE_PIXMAP (texture), \ + CLUTTER_X11_FILTER_CONTINUE); + + dpy = clutter_x11_get_default_display(); + priv = texture->priv; + + if (xev->type == _damage_event_base + XDamageNotify) + { + XserverRegion parts; + gint i, r_count; + XRectangle *r_damage; + XRectangle r_bounds; + XDamageNotifyEvent *dev = (XDamageNotifyEvent*)xev; + + if (dev->drawable != priv->pixmap) + return CLUTTER_X11_FILTER_CONTINUE; + + + clutter_x11_trap_x_errors (); + /* + * Retrieve the damaged region and break it down into individual + * rectangles so we do not have to update the whole shebang. + */ + parts = XFixesCreateRegion (dpy, 0, 0); + XDamageSubtract (dpy, priv->damage, None, parts); + + r_damage = XFixesFetchRegionAndBounds (dpy, + parts, + &r_count, + &r_bounds); + + clutter_x11_untrap_x_errors (); + + if (r_damage) + { + for (i = 0; i < r_count; ++i) + clutter_x11_texture_pixmap_update_area (texture, + r_damage[i].x, + r_damage[i].y, + r_damage[i].width, + r_damage[i].height); + XFree (r_damage); + } + + XFixesDestroyRegion (dpy, parts); + } + + return CLUTTER_X11_FILTER_CONTINUE; +} + + +static void +free_damage_resources (ClutterX11TexturePixmap *texture) +{ + ClutterX11TexturePixmapPrivate *priv; + Display *dpy; + + priv = texture->priv; + dpy = clutter_x11_get_default_display(); + + if (priv->damage) + { + XDamageDestroy (dpy, priv->damage); + priv->damage = None; + } + + clutter_x11_remove_filter (on_x_event_filter, (gpointer)texture); +} + + static void clutter_x11_texture_pixmap_init (ClutterX11TexturePixmap *self) { @@ -207,15 +217,21 @@ clutter_x11_texture_pixmap_init (ClutterX11TexturePixmap *self) CLUTTER_X11_TYPE_TEXTURE_PIXMAP, ClutterX11TexturePixmapPrivate); + if (!check_extensions (self)) + { + /* FIMXE: means display lacks needed extensions for at least auto. + * - a _can_autoupdate() method ? + */ + } } static GObject * clutter_x11_texture_pixmap_constructor (GType type, - guint n_construct_properties, - GObjectConstructParam *construct_properties) + guint n_props, + GObjectConstructParam *props) { GObject *object = G_OBJECT_CLASS (clutter_x11_texture_pixmap_parent_class)-> - constructor (type, n_construct_properties, construct_properties); + constructor (type, n_props, props); g_object_set (object, "sync-size", FALSE, @@ -227,9 +243,11 @@ clutter_x11_texture_pixmap_constructor (GType type, static void clutter_x11_texture_pixmap_dispose (GObject *object) { - ClutterX11TexturePixmap *texture = CLUTTER_X11_TEXTURE_PIXMAP (object); + ClutterX11TexturePixmap *texture = CLUTTER_X11_TEXTURE_PIXMAP (object); ClutterX11TexturePixmapPrivate *priv = texture->priv; + free_damage_resources (texture); + if (priv->image) { XDestroyImage (priv->image); @@ -237,7 +255,6 @@ clutter_x11_texture_pixmap_dispose (GObject *object) } G_OBJECT_CLASS (clutter_x11_texture_pixmap_parent_class)->dispose (object); - } static void @@ -246,42 +263,21 @@ clutter_x11_texture_pixmap_set_property (GObject *object, const GValue *value, GParamSpec *pspec) { - ClutterX11TexturePixmap *texture = CLUTTER_X11_TEXTURE_PIXMAP (object); - ClutterX11TexturePixmapPrivate *priv = texture->priv; + ClutterX11TexturePixmap *texture = CLUTTER_X11_TEXTURE_PIXMAP (object); switch (prop_id) { case PROP_PIXMAP: - clutter_x11_texture_pixmap_set_pixmap (texture, - g_value_get_uint (value), - priv->pixmap_width, - priv->pixmap_height, - priv->depth); - break; - case PROP_PIXMAP_WIDTH: - clutter_x11_texture_pixmap_set_pixmap (texture, - priv->pixmap, - g_value_get_uint (value), - priv->pixmap_height, - priv->depth); - break; - case PROP_PIXMAP_HEIGHT: - clutter_x11_texture_pixmap_set_pixmap (texture, - priv->pixmap, - priv->pixmap_width, - g_value_get_uint (value), - priv->depth); - break; - case PROP_DEPTH: - clutter_x11_texture_pixmap_set_pixmap (texture, - priv->pixmap, - priv->pixmap_width, - priv->pixmap_height, - g_value_get_uint (value)); - break; + clutter_x11_texture_pixmap_set_pixmap (texture, + g_value_get_uint (value)); + break; + case PROP_AUTO: + clutter_x11_texture_pixmap_set_automatic (texture, + g_value_get_boolean (value)); + break; default: - G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); - break; + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); + break; } } @@ -291,26 +287,29 @@ clutter_x11_texture_pixmap_get_property (GObject *object, GValue *value, GParamSpec *pspec) { - ClutterX11TexturePixmap *texture = CLUTTER_X11_TEXTURE_PIXMAP (object); + ClutterX11TexturePixmap *texture = CLUTTER_X11_TEXTURE_PIXMAP (object); ClutterX11TexturePixmapPrivate *priv = texture->priv; switch (prop_id) { case PROP_PIXMAP: - g_value_set_uint (value, priv->pixmap); - break; + g_value_set_uint (value, priv->pixmap); + break; case PROP_PIXMAP_WIDTH: - g_value_set_uint (value, priv->pixmap_width); - break; + g_value_set_uint (value, priv->pixmap_width); + break; case PROP_PIXMAP_HEIGHT: - g_value_set_uint (value, priv->pixmap_height); - break; + g_value_set_uint (value, priv->pixmap_height); + break; case PROP_DEPTH: - g_value_set_uint (value, priv->depth); - break; + g_value_set_uint (value, priv->depth); + break; + case PROP_AUTO: + g_value_set_boolean (value, priv->automatic_updates); + break; default: - G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); - break; + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); + break; } } @@ -331,6 +330,107 @@ clutter_x11_texture_pixmap_realize (ClutterActor *actor) priv->pixmap_height); } +static void +clutter_x11_texture_pixmap_class_init (ClutterX11TexturePixmapClass *klass) +{ + GObjectClass *object_class = G_OBJECT_CLASS (klass); + ClutterActorClass *actor_class = CLUTTER_ACTOR_CLASS (klass); + GParamSpec *pspec; + ClutterBackend *default_backend; + + g_type_class_add_private (klass, sizeof (ClutterX11TexturePixmapPrivate)); + + object_class->constructor = clutter_x11_texture_pixmap_constructor; + object_class->dispose = clutter_x11_texture_pixmap_dispose; + object_class->set_property = clutter_x11_texture_pixmap_set_property; + object_class->get_property = clutter_x11_texture_pixmap_get_property; + + actor_class->realize = clutter_x11_texture_pixmap_realize; + + klass->update_area = clutter_x11_texture_pixmap_update_area_real; + + pspec = g_param_spec_uint ("pixmap", + "Pixmap", + "The X11 Pixmap to be bound", + 0, G_MAXINT, + None, + G_PARAM_READWRITE | G_PARAM_CONSTRUCT); + + g_object_class_install_property (object_class, PROP_PIXMAP, pspec); + + pspec = g_param_spec_uint ("pixmap-width", + "Pixmap width", + "The width of the " + "pixmap bound to this texture", + 0, G_MAXUINT, + 0, + G_PARAM_READABLE); + + g_object_class_install_property (object_class, PROP_PIXMAP_WIDTH, pspec); + + pspec = g_param_spec_uint ("pixmap-height", + "Pixmap height", + "The height of the " + "pixmap bound to this texture", + 0, G_MAXUINT, + 0, + G_PARAM_READABLE); + + g_object_class_install_property (object_class, PROP_PIXMAP_HEIGHT, pspec); + + pspec = g_param_spec_uint ("pixmap-depth", + "Pixmap Depth", + "The depth (in number of bits) of the " + "pixmap bound to this texture", + 0, G_MAXUINT, + 0, + G_PARAM_READABLE); + + g_object_class_install_property (object_class, PROP_DEPTH, pspec); + + pspec = g_param_spec_boolean ("automatic-updates", + "Automatic Updates", + "If the texture should be kept in " + "sync with any pixmap changes.", + FALSE, + G_PARAM_READWRITE); + + g_object_class_install_property (object_class, PROP_AUTO, pspec); + + + /** + * ClutterX11TexturePixmap::update-area: + * @texture: the object which received the signal + * + * The ::hide signal is emitted to ask the texture to update its + * content from its source pixmap. + * + * Since: 0.8 + */ + signals[UPDATE_AREA] = + g_signal_new ("update-area", + G_TYPE_FROM_CLASS (object_class), + G_SIGNAL_RUN_FIRST, + G_STRUCT_OFFSET (ClutterX11TexturePixmapClass, \ + update_area), + NULL, NULL, + clutter_marshal_VOID__INT_INT_INT_INT, + G_TYPE_NONE, 4, + G_TYPE_INT, + G_TYPE_INT, + G_TYPE_INT, + G_TYPE_INT); + + default_backend = clutter_get_default_backend (); + + if (!CLUTTER_IS_BACKEND_X11 (default_backend)) + { + g_critical ("ClutterX11TexturePixmap instanciated with a " + "non-X11 backend"); + return; + } +} + static void clutter_x11_texture_pixmap_update_area_real (ClutterX11TexturePixmap *texture, gint x, @@ -352,9 +452,11 @@ clutter_x11_texture_pixmap_update_area_real (ClutterX11TexturePixmap *texture, return; priv = texture->priv; - dpy = ((ClutterBackendX11 *)backend)->xdpy; + dpy = clutter_x11_get_default_display(); clutter_x11_trap_x_errors (); + + /* FIXME: Use XSHM here! */ if (!priv->image) priv->image = XGetImage (dpy, priv->pixmap, @@ -373,8 +475,15 @@ clutter_x11_texture_pixmap_update_area_real (ClutterX11TexturePixmap *texture, x, y); XSync (dpy, FALSE); + if ((err_code = clutter_x11_untrap_x_errors ())) - return; + { + g_warning ("Failed to get XImage of pixmap: %lx, removing.", + priv->pixmap); + /* safe to assume pixmap has gone away? - therefor reset */ + clutter_x11_texture_pixmap_set_pixmap (texture, None); + return; + } image = priv->image; @@ -490,18 +599,12 @@ clutter_x11_texture_pixmap_new (void) * Since 0.8 **/ ClutterActor * -clutter_x11_texture_pixmap_new_with_pixmap (Pixmap pixmap, - guint width, - guint height, - guint depth) +clutter_x11_texture_pixmap_new_with_pixmap (Pixmap pixmap) { ClutterActor *actor; actor = g_object_new (CLUTTER_X11_TYPE_TEXTURE_PIXMAP, "pixmap", pixmap, - "pixmap-width", width, - "pixmap-height", height, - "depth", depth, NULL); return actor; @@ -521,67 +624,87 @@ clutter_x11_texture_pixmap_new_with_pixmap (Pixmap pixmap, **/ void clutter_x11_texture_pixmap_set_pixmap (ClutterX11TexturePixmap *texture, - Pixmap pixmap, - guint width, - guint height, - guint depth) + Pixmap pixmap) { + Window root; + int x, y; + unsigned int width, height, border_width, depth; + Status status = 0; + ClutterX11TexturePixmapPrivate *priv; g_return_if_fail (CLUTTER_X11_IS_TEXTURE_PIXMAP (texture)); priv = texture->priv; + clutter_x11_trap_x_errors (); + + status = XGetGeometry (clutter_x11_get_default_display(), + (Drawable)pixmap, + &root, + &x, + &y, + &width, + &height, + &border_width, + &depth); + + if (clutter_x11_untrap_x_errors () || status == 0) + { + if (pixmap != None) + g_warning ("Unable to query pixmap: %lx\n", pixmap); + pixmap = None; + width = height = depth = 0; + } + + if (priv->image) + { + XDestroyImage (priv->image); + priv->image = NULL; + } + + g_object_ref (texture); + if (priv->pixmap != pixmap) { priv->pixmap = pixmap; - g_object_notify (G_OBJECT (texture), "pixmap"); - } if (priv->pixmap_width != width) { priv->pixmap_width = width; - g_object_notify (G_OBJECT (texture), "pixmap-width"); - } if (priv->pixmap_height != height) { priv->pixmap_height = height; - g_object_notify (G_OBJECT (texture), "pixmap-height"); - } if (priv->depth != depth) { priv->depth = depth; - - g_object_notify (G_OBJECT (texture), "depth"); - + g_object_notify (G_OBJECT (texture), "pixmap-depth"); } + g_object_unref (texture); + if (priv->depth != 0 && priv->pixmap != None && priv->pixmap_width != 0 && priv->pixmap_height != 0) { - if (priv->image) - { - XDestroyImage (priv->image); - priv->image = NULL; - } - if (CLUTTER_ACTOR_IS_REALIZED (texture)) clutter_x11_texture_pixmap_update_area (texture, 0, 0, priv->pixmap_width, priv->pixmap_height); } - + + clutter_actor_set_size (CLUTTER_ACTOR(texture), + priv->pixmap_width, priv->pixmap_height); } /** @@ -609,3 +732,71 @@ clutter_x11_texture_pixmap_update_area (ClutterX11TexturePixmap *texture, g_signal_emit (texture, signals[UPDATE_AREA], 0, x, y, width, height); } + +/* FIXME: to implement */ +void +clutter_x11_texture_pixmap_set_from_window (ClutterX11TexturePixmap *texture, + Window win, + gboolean reflect) +{ + ClutterX11TexturePixmapPrivate *priv; + + g_return_if_fail (CLUTTER_X11_IS_TEXTURE_PIXMAP (texture)); + + /* This would mainly be used for compositing type situations + * with named pixmap (cannot be regular pixmap) and setting up + * actual window redirection. + * + * It also seems to can pass a window to texture_pixmap and it + * it works like redirectwindow automatic. + * + * Note windows do however change size, whilst pixmaps do not. + */ + + priv = texture->priv; + + /* + priv->window_pixmap = XCompositeNameWindowPixmap (dpy, win); + + XCompositeRedirectWindow(clutter_x11_get_default_display(), + win_remote, + CompositeRedirectAutomatic); + */ +} + + + +/* FIXME: Below will change, just proof of concept atm - it will not work + * 100% for named pixmaps. +*/ +void +clutter_x11_texture_pixmap_set_automatic (ClutterX11TexturePixmap *texture, + gboolean setting) +{ + ClutterX11TexturePixmapPrivate *priv; + Display *dpy; + + g_return_if_fail (CLUTTER_X11_IS_TEXTURE_PIXMAP (texture)); + + priv = texture->priv; + + if (setting == priv->automatic_updates) + return; + + dpy = clutter_x11_get_default_display(); + + if (setting == TRUE) + { + clutter_x11_add_filter (on_x_event_filter, (gpointer)texture); + + /* NOTE: Appears this will not work for a named pixmap */ + priv->damage = XDamageCreate (dpy, + priv->pixmap, + XDamageReportNonEmpty); + } + else + free_damage_resources (texture); + + priv->automatic_updates = setting; + +} diff --git a/clutter/x11/clutter-x11-texture-pixmap.h b/clutter/x11/clutter-x11-texture-pixmap.h index 77f87310f..a46000bac 100644 --- a/clutter/x11/clutter-x11-texture-pixmap.h +++ b/clutter/x11/clutter-x11-texture-pixmap.h @@ -67,16 +67,10 @@ struct _ClutterX11TexturePixmap GType clutter_x11_texture_pixmap_get_type (void); ClutterActor * clutter_x11_texture_pixmap_new (void); -ClutterActor * clutter_x11_texture_pixmap_new_with_pixmap (Pixmap pixmap, - guint width, - guint height, - guint depth); +ClutterActor * clutter_x11_texture_pixmap_new_with_pixmap (Pixmap pixmap); void clutter_x11_texture_pixmap_set_pixmap (ClutterX11TexturePixmap *texture, - Pixmap pixmap, - guint width, - guint height, - guint depth); + Pixmap pixmap); void clutter_x11_texture_pixmap_update_area (ClutterX11TexturePixmap *texture, gint x, @@ -84,6 +78,9 @@ void clutter_x11_texture_pixmap_update_area (ClutterX11TexturePixmap *texture, gint width, gint height); +void +clutter_x11_texture_pixmap_set_automatic (ClutterX11TexturePixmap *texture, + gboolean setting); G_END_DECLS diff --git a/configure.ac b/configure.ac index 6b3b8ebf8..b41a6611c 100644 --- a/configure.ac +++ b/configure.ac @@ -113,6 +113,29 @@ if test x$have_xfixes = xyes; then X11_LIBS="$X11_LIBS -lXfixes" fi +PKG_CHECK_MODULES(XDAMAGE, xdamage, [have_xdamage=yes], [have_xdamage=no]) +if test x$have_xdamage = xyes; then + AC_DEFINE(HAVE_XDAMAGE, 1, Have the XDAMAGE X extension) + X11_LIBS="$X11_LIBS -lXdamage" +fi + +# FIXME: Composite 0.3/0.4 likely needed when window redirection complete. +# though may not be needed at all +PKG_CHECK_MODULES(XCOMPOSITE, xcomposite, [have_xcomposite=yes], [have_xcomposite=no]) +if test x$have_xcomposite = xyes; then + AC_DEFINE(HAVE_XCOMPOSITE, 1, Have the XCOMPOSITE X extension) + X11_LIBS="$X11_LIBS -lXcomposite" +fi + +# Currently require all extentions, may not for actual release. +if test "x$clutterbackend" = "xglx" || test "x$clutterbackend" = "xeglx" +then + if test "x$have_xdamage" = "xno" || test "x$have_xfixes" = "xno" || test "x$have_xcomposite" = "xno" + then + AC_MSG_ERROR([[Required backend X11 Libraries not found.]]) + fi +fi + clutter_gl_header="" case $clutterbackend in @@ -458,7 +481,6 @@ echo " Flavour: ${clutterbackend}/${CLUTTER_COGL}" echo " GL Headers: ${CLUTTER_GL_HEADER}" echo " Target library: ${clutterbackendlib}" echo " Debug level: ${enable_debug}" -echo " Fast FP conversions: ${enable_fast_fp_conversions}" echo " Compiler flags: ${CPPFLAGS}" echo " API Documentation: ${enable_gtk_doc}" echo " Manual Documentation: ${enable_manual}" diff --git a/tests/Makefile.am b/tests/Makefile.am index a5186bf93..a14a5b1b6 100644 --- a/tests/Makefile.am +++ b/tests/Makefile.am @@ -7,7 +7,7 @@ noinst_PROGRAMS = test-textures test-events test-offscreen test-scale \ test-threads test-timeline test-score test-script \ test-model test-grab test-effects test-fullscreen \ test-shader test-unproject test-viewport test-fbo \ - test-opacity test-multistage + test-opacity test-multistage test-pixmap INCLUDES = -I$(top_srcdir)/ LDADD = $(top_builddir)/clutter/libclutter-@CLUTTER_FLAVOUR@-@CLUTTER_MAJORMINOR@.la @@ -44,5 +44,6 @@ test_viewport_SOURCES = test-viewport.c test_fbo_SOURCES = test-fbo.c test_opacity_SOURCES = test-opacity.c test_multistage_SOURCES = test-multistage.c +test_pixmap_SOURCES = test-pixmap.c EXTRA_DIST = redhand.png test-script.json diff --git a/tests/test-pixmap.c b/tests/test-pixmap.c new file mode 100644 index 000000000..1302a2375 --- /dev/null +++ b/tests/test-pixmap.c @@ -0,0 +1,199 @@ +#include +#include +#include +#include + +#if HAVE_CLUTTER_GLX +#include +#include +#endif + +#include +#include +#include + +#define IMAGE "redhand.png" + + + +static gboolean +stage_press_cb (ClutterActor *actor, + ClutterEvent *event, + gpointer data) +{ + Pixmap pxm = (Pixmap)data; + Display *dpy = clutter_x11_get_default_display (); + GC gc; + XGCValues gc_values = {0}; + + + gc = XCreateGC (dpy, + pxm, + 0, + &gc_values); + + XDrawLine (dpy, pxm, gc, 0, 0, 100, 100); +} + + +Pixmap +create_pixmap (guint *width, guint *height, guint *depth) +{ + Display *dpy = clutter_x11_get_default_display (); + Pixmap pixmap; + GdkPixbuf *pixbuf; + GError *error = NULL; + XImage *image; + char *data, *d; + guchar *p, *line, *endofline, *end; + guint w, h, rowstride; + GC gc; + XGCValues gc_values = {0}; + + pixbuf = gdk_pixbuf_new_from_file (IMAGE, &error); + if (error) + g_error (error->message); + + /* We assume that the image had an alpha channel */ + g_assert (gdk_pixbuf_get_has_alpha (pixbuf)); + + w = gdk_pixbuf_get_width (pixbuf); + h = gdk_pixbuf_get_height (pixbuf); + rowstride = gdk_pixbuf_get_rowstride (pixbuf); + + data = malloc (w * h * 4); + image = XCreateImage (dpy, + None, + 32, + ZPixmap, + 0, + data, + w, h, + 8, + w * 4); + + p = gdk_pixbuf_get_pixels (pixbuf); + d = data; + end = p + rowstride*h; + + /* Convert from RGBA as contained in the pixmap to ARGB as used in X */ + for (line = p; line < end ; line += rowstride) + { + p = line; + endofline = p + 4 * w; + + for (p = line; p < endofline; p += 4, d+=4) + { + +#define r ((guint32)(*(p))) +#define g ((guint32)(*(p+1))) +#define b ((guint32)(*(p+2))) +#define a ((guint32)(*(p+3))) + guint32 pixel = + ((a << 24) & 0xFF000000 ) | + ((r << 16) & 0x00FF0000 ) | + ((g << 8) & 0x0000FF00) | + ((b) & 0x000000FF ); + + *((guint32 *)d) = pixel; + + } +#undef r +#undef g +#undef b +#undef a + + } + + g_object_unref (pixbuf); + + pixmap = XCreatePixmap (dpy, + DefaultRootWindow (dpy), + w, h, + 32); + + gc = XCreateGC (dpy, + pixmap, + 0, + &gc_values); + + XPutImage (dpy, + pixmap, + gc, + image, + 0, 0, + 0, 0, + w, h); + + XFreeGC (dpy, gc); + XDestroyImage (image); + + if (width) *width = w; + if (height) *height = h; + if (depth) *depth = 32; + + return pixmap; +} + +int +main (int argc, char **argv) +{ + ClutterActor *stage, *tex; + Pixmap pixmap; + guint w, h, d; + const ClutterColor gry = { 0x99, 0x99, 0x99, 0xFF }; + Window win_remote; + + clutter_init (&argc, &argv); + + if (argc < 2) + g_error ("usage: %s ", argv[0]); + + win_remote = atol(argv[1]); + + stage = clutter_stage_get_default (); + clutter_stage_set_color (CLUTTER_STAGE (stage), &gry); + + pixmap = win_remote; + + /* + XCompositeRedirectWindow(clutter_x11_get_default_display(), + win_remote, + CompositeRedirectAutomatic); + + pixmap = XCompositeNameWindowPixmap (clutter_x11_get_default_display(), + win_remote); + */ + + tex = clutter_x11_texture_pixmap_new_with_pixmap (pixmap); + + clutter_container_add_actor (CLUTTER_CONTAINER (stage), tex); + + clutter_x11_texture_pixmap_set_automatic (CLUTTER_X11_TEXTURE_PIXMAP (tex), + TRUE); + +#ifdef HAVE_CLUTTER_GLX + pixmap = create_pixmap (&w, &h, &d); + + tex = clutter_glx_texture_pixmap_new_with_pixmap (pixmap); + + clutter_actor_set_position (tex, + clutter_actor_get_width (stage) + - clutter_actor_get_width (tex), + 0); + + clutter_x11_texture_pixmap_set_automatic (CLUTTER_X11_TEXTURE_PIXMAP (tex), + FALSE); + + clutter_container_add_actor (CLUTTER_CONTAINER (stage), + tex); +#endif + + g_signal_connect (stage, "button-press-event", + G_CALLBACK (stage_press_cb), (gpointer)pixmap); + + clutter_actor_show (stage); + + clutter_main (); + +}