+2008-04-15 Matthew Allum <mallum@openedhand.com>
+
+ 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 <neil@o-hand.com>
Added support for foreign windows to the Win32 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;
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
{
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;
#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
{
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_init (ClutterGLXTexturePixmap *self);
+
+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_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_realize (ClutterActor *actor);
-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_unrealize (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_paint (ClutterActor *actor);
-static void clutter_glx_texture_pixmap_create_glx_pixmap (ClutterGLXTexturePixmap *texture);
+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);
+G_DEFINE_TYPE (ClutterGLXTexturePixmap, \
+ clutter_glx_texture_pixmap, \
+ CLUTTER_X11_TYPE_TEXTURE_PIXMAP);
static void
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;
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
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;
}
if (g_str_equal (pspec->name, "pixmap"))
{
ClutterGLXTexturePixmap *texture = CLUTTER_GLX_TEXTURE_PIXMAP (object);
-
clutter_glx_texture_pixmap_create_glx_pixmap (texture);
}
}
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;
-
- if (!backend->t_f_p)
+ ClutterGLXTexturePixmapPrivate *priv;
+ COGLenum pixel_type, pixel_format,filter_quality;
+ gboolean repeat_x, repeat_y;
+ guint width, height;
+
+ 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;
}
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;
+
+ priv = CLUTTER_GLX_TEXTURE_PIXMAP (actor)->priv;
+ dpy = clutter_x11_get_default_display();
- if (!backend->t_f_p)
+ if (!_have_tex_from_pixmap_ext)
{
CLUTTER_ACTOR_CLASS (clutter_glx_texture_pixmap_parent_class)->
unrealize (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);
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);
{
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;
fbconfigs[i],
GLX_BIND_TO_TEXTURE_RGBA_EXT,
&value);
-
if (value)
rgba = 1;
}
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);
{
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 ();
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;
}
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;
}
* 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;
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
GSList *tmp_list, *this;
ClutterX11EventFilter *filter;
- g_return_if_fail (func == NULL);
+ g_return_if_fail (func != NULL);
tmp_list = backend_singleton->event_filters;
#include "cogl.h"
+/* FIXME: Check exts exist in autogen */
+#include <X11/extensions/Xdamage.h>
+#include <X11/extensions/Xcomposite.h>
+
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
XImage *image;
+ gboolean automatic_updates;
+ Damage damage;
+
};
-static ClutterBackendX11 *backend = NULL;
-
-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);
-
-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 int _damage_event_base = 0;
-static void
-clutter_x11_texture_pixmap_class_init (ClutterX11TexturePixmapClass *klass)
+/* FIXME: Ultimatly with current cogl we should subclass clutter actor */
+G_DEFINE_TYPE (ClutterX11TexturePixmap, \
+ clutter_x11_texture_pixmap, \
+ CLUTTER_TYPE_TEXTURE);
+
+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;
+ if (!XCompositeQueryExtension (dpy, &event_base, &error_base))
+ {
+ g_warning ("No composite extension\n");
+ return FALSE;
+ }
- 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);
+ if (!XDamageQueryExtension (dpy,
+ &_damage_event_base, &damage_error))
+ {
+ g_warning ("No Damage extension\n");
+ return FALSE;
+ }
- g_object_class_install_property (object_class,
- PROP_PIXMAP,
- pspec);
+ return TRUE;
+}
- 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);
+static ClutterX11FilterReturn
+on_x_event_filter (XEvent *xev, ClutterEvent *cev, gpointer data)
+{
+ ClutterX11TexturePixmap *texture;
+ ClutterX11TexturePixmapPrivate *priv;
+ Display *dpy;
- g_object_class_install_property (object_class,
- PROP_PIXMAP_WIDTH,
- pspec);
+ texture = CLUTTER_X11_TEXTURE_PIXMAP (data);
+
+ g_return_val_if_fail (CLUTTER_X11_IS_TEXTURE_PIXMAP (texture), \
+ CLUTTER_X11_FILTER_CONTINUE);
- 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);
+ 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);
+ }
- g_object_class_install_property (object_class,
- PROP_PIXMAP_HEIGHT,
- pspec);
+ XFixesDestroyRegion (dpy, parts);
+ }
- 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);
+ return CLUTTER_X11_FILTER_CONTINUE;
+}
- 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))
+static void
+free_damage_resources (ClutterX11TexturePixmap *texture)
+{
+ ClutterX11TexturePixmapPrivate *priv;
+ Display *dpy;
+
+ priv = texture->priv;
+ dpy = clutter_x11_get_default_display();
+
+ if (priv->damage)
{
- g_critical ("ClutterX11TexturePixmap instanciated with a "
- "non-X11 backend");
- return;
+ XDamageDestroy (dpy, priv->damage);
+ priv->damage = None;
}
- backend = (ClutterBackendX11 *)default_backend;
-
+ clutter_x11_remove_filter (on_x_event_filter, (gpointer)texture);
}
+
static void
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,
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);
}
G_OBJECT_CLASS (clutter_x11_texture_pixmap_parent_class)->dispose (object);
-
}
static void
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;
}
}
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;
}
}
}
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,
gint y,
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,
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;
* 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;
**/
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);
}
/**
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;
+
+}
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,
gint width,
gint height);
+void
+clutter_x11_texture_pixmap_set_automatic (ClutterX11TexturePixmap *texture,
+ gboolean setting);
G_END_DECLS
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
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}"
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
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
--- /dev/null
+#include <config.h>
+#include <clutter/clutter.h>
+#include <clutter/x11/clutter-x11.h>
+#include <clutter/x11/clutter-x11-texture-pixmap.h>
+
+#if HAVE_CLUTTER_GLX
+#include <clutter/glx/clutter-glx.h>
+#include <clutter/glx/clutter-glx-texture-pixmap.h>
+#endif
+
+#include <X11/Xlib.h>
+#include <X11/extensions/Xcomposite.h>
+#include <string.h>
+
+#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 <window id>", 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 ();
+
+}