diff --git a/ChangeLog b/ChangeLog index e2d13a809..e1249fc3b 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,14 @@ +2008-02-20 Emmanuele Bassi + + * clutter/clutter-marshal.list: + * clutter/glx/Makefile.am: + * clutter/glx/clutter-backend-glx.c: + * clutter/glx/clutter-backend-glx.h: + * clutter/glx/clutter-glx.h: + * clutter/x11/Makefile.am: + ClutterX11TexturePixmap and ClutterGLXTexturePixmap actors (#713; + patch by Johan Bilien). + 2008-02-20 Emmanuele Bassi * clutter/clutter-actor.h: @@ -66,7 +77,7 @@ 2008-02-15 Matthew Allum * clutter/pango/pangoclutter-render.c: (draw_glyph): - More safety checks (#796, Tero Saarni) + More safety checks (#796, Tero Saarni) 2008-02-15 Chris Lord diff --git a/clutter/clutter-marshal.list b/clutter/clutter-marshal.list index 7feb52bae..96c611ac5 100644 --- a/clutter/clutter-marshal.list +++ b/clutter/clutter-marshal.list @@ -2,6 +2,7 @@ VOID:INT64,INT64,FLOAT,BOOLEAN VOID:STRING,BOOLEAN,BOOLEAN VOID:INT VOID:INT,INT +VOID:INT,INT,INT,INT VOID:BOXED VOID:OBJECT VOID:VOID diff --git a/clutter/glx/Makefile.am b/clutter/glx/Makefile.am index 3cfc57266..b07263971 100644 --- a/clutter/glx/Makefile.am +++ b/clutter/glx/Makefile.am @@ -1,5 +1,5 @@ libclutterincludedir = $(includedir)/clutter-@CLUTTER_API_VERSION@/clutter -libclutterinclude_HEADERS = clutter-glx.h +libclutterinclude_HEADERS = clutter-glx.h clutter-glx-texture-pixmap.h INCLUDES = \ -DG_LOG_DOMAIN=\"ClutterGLX\" \ @@ -19,4 +19,6 @@ libclutter_glx_la_SOURCES = \ clutter-backend-glx.c \ clutter-stage-glx.h \ clutter-stage-glx.c \ + clutter-glx-texture-pixmap.h \ + clutter-glx-texture-pixmap.c \ clutter-glx.h diff --git a/clutter/glx/clutter-backend-glx.c b/clutter/glx/clutter-backend-glx.c index 2de7f45ac..99264b232 100644 --- a/clutter/glx/clutter-backend-glx.c +++ b/clutter/glx/clutter-backend-glx.c @@ -325,6 +325,18 @@ 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|clutter_backend_x11_get_features (backend); diff --git a/clutter/glx/clutter-backend-glx.h b/clutter/glx/clutter-backend-glx.h index 995b2014a..6e14c0618 100644 --- a/clutter/glx/clutter-backend-glx.h +++ b/clutter/glx/clutter-backend-glx.h @@ -59,6 +59,14 @@ 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 { @@ -70,6 +78,15 @@ struct _ClutterBackendGLX SwapIntervalProc swap_interval; 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; }; struct _ClutterBackendGLXClass diff --git a/clutter/glx/clutter-glx-texture-pixmap.c b/clutter/glx/clutter-glx-texture-pixmap.c new file mode 100644 index 000000000..9f6e15ef2 --- /dev/null +++ b/clutter/glx/clutter-glx-texture-pixmap.c @@ -0,0 +1,624 @@ +/* + * Clutter. + * + * An OpenGL based 'interactive canvas' library. + * + * Authored By Johan Bilien + * + * Copyright (C) 2007 OpenedHand + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the + * Free Software Foundation, Inc., 59 Temple Place - Suite 330, + * Boston, MA 02111-1307, USA. + */ + +/** + * SECTION:clutter-glx-texture-pixmap + * @short_description: A texture which displays the content of an X Pixmap. + * + * #ClutterGLXTexturePixmap is a class for displaying the content of an + * X Pixmap as a ClutterActor. Used together with the X Composite extension, + * it allows to display the content of X Windows inside Clutter. + * + * The class requires the GLX_EXT_texture_from_pixmap OpenGL extension + * (http://people.freedesktop.org/~davidr/GLX_EXT_texture_from_pixmap.txt) + */ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include "../x11/clutter-x11-texture-pixmap.h" +#include "clutter-glx-texture-pixmap.h" +#include "clutter-glx.h" +#include "clutter-backend-glx.h" + +#include "../clutter-util.h" + +#include "cogl.h" + +enum +{ + PROP_PIXMAP = 1, + PROP_PIXMAP_WIDTH, + PROP_PIXMAP_HEIGHT, + PROP_DEPTH +}; + +struct _ClutterGLXTexturePixmapPrivate +{ + COGLenum target_type; + 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 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_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 *texture); + +G_DEFINE_TYPE (ClutterGLXTexturePixmap, clutter_glx_texture_pixmap, CLUTTER_X11_TYPE_TEXTURE_PIXMAP); + +static void +clutter_glx_texture_pixmap_class_init (ClutterGLXTexturePixmapClass *klass) +{ + GObjectClass *object_class = G_OBJECT_CLASS (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; + + actor_class->realize = clutter_glx_texture_pixmap_realize; + actor_class->unrealize = clutter_glx_texture_pixmap_unrealize; + actor_class->paint = clutter_glx_texture_pixmap_paint; + + x11_texture_class->update_area = clutter_glx_texture_pixmap_update_area; + + default_backend = clutter_get_default_backend (); + if (!CLUTTER_IS_BACKEND_GLX (default_backend)) + { + g_critical ("ClutterGLXTexturePixmap instanciated with a " + "non-GLX backend"); + return; + } + + backend = (ClutterBackendGLX *)default_backend; +/* backend->t_f_p = FALSE;*/ + +} + +static void +clutter_glx_texture_pixmap_init (ClutterGLXTexturePixmap *self) +{ + ClutterGLXTexturePixmapPrivate *priv; + + priv = self->priv = + G_TYPE_INSTANCE_GET_PRIVATE (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; + + if (priv->glx_pixmap != None) + { + glXDestroyGLXPixmap (((ClutterBackendX11 *)backend)->xdpy, + priv->glx_pixmap); + priv->glx_pixmap = None; + } + + G_OBJECT_CLASS (clutter_glx_texture_pixmap_parent_class)->dispose (object); +} + +static void +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); + } +} + +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) + { + CLUTTER_ACTOR_CLASS (clutter_glx_texture_pixmap_parent_class)-> + realize (actor); + return; + } + + g_object_get (actor, + "pixel-type", &pixel_type, + "pixel-format", &pixel_format, + "repeat-x", &repeat_x, + "repeat-y", &repeat_y, + "filter-quality", &filter_quality, + "pixmap-width", &width, + "pixmap-height", &height, + NULL); + + cogl_textures_create (1, &priv->texture_id); + + clutter_glx_texture_pixmap_update_area (CLUTTER_X11_TEXTURE_PIXMAP (actor), + 0, 0, + width, height); + + cogl_texture_set_alignment (priv->target_type, 4, width); + + cogl_texture_set_filters (priv->target_type, + filter_quality ? CGL_LINEAR : CGL_NEAREST, + filter_quality ? CGL_LINEAR : CGL_NEAREST); + + cogl_texture_set_wrap (priv->target_type, + repeat_x ? CGL_REPEAT : CGL_CLAMP_TO_EDGE, + repeat_y ? CGL_REPEAT : CGL_CLAMP_TO_EDGE); + + CLUTTER_ACTOR_SET_FLAGS (actor, CLUTTER_ACTOR_REALIZED); +} + +static void +clutter_glx_texture_pixmap_unrealize (ClutterActor *actor) +{ + ClutterGLXTexturePixmapPrivate *priv = + CLUTTER_GLX_TEXTURE_PIXMAP (actor)->priv; + Display *dpy = ((ClutterBackendX11 *)backend)->xdpy; + + if (!backend->t_f_p) + { + CLUTTER_ACTOR_CLASS (clutter_glx_texture_pixmap_parent_class)-> + unrealize (actor); + return; + } + + if (!CLUTTER_ACTOR_IS_REALIZED (actor)) + return; + + if (priv->bound && priv->glx_pixmap) + { + (backend->release_tex_image) (dpy, + priv->glx_pixmap, + GLX_FRONT_LEFT_EXT); + } + + cogl_textures_destroy (1, &priv->texture_id); + + CLUTTER_ACTOR_UNSET_FLAGS (actor, CLUTTER_ACTOR_REALIZED); +} + +static void +texture_render_to_gl_quad (ClutterGLXTexturePixmap *texture, + int x_1, + int y_1, + int x_2, + int y_2) +{ + ClutterGLXTexturePixmapPrivate *priv = texture->priv; + + int qx1 = 0, qx2 = 0, qy1 = 0, qy2 = 0; + int qwidth = 0, qheight = 0; + float tx, ty; + guint width, height; + + g_object_get (texture, + "pixmap-width", &width, + "pixmap-height", &height, + NULL); + + qwidth = x_2 - x_1; + qheight = y_2 - y_1; + + cogl_texture_bind (priv->target_type, priv->texture_id); + + if (priv->target_type == CGL_TEXTURE_2D) /* POT */ + { + tx = (float) width / clutter_util_next_p2 (width); + ty = (float) height / clutter_util_next_p2 (height); + } + else + { + tx = (float) width; + ty = (float) height; + + } + + qx1 = x_1; qx2 = x_2; + qy1 = y_1; qy2 = y_2; + + cogl_texture_quad (x_1, x_2, y_1, y_2, + 0, + 0, + CLUTTER_FLOAT_TO_FIXED (tx), + CLUTTER_FLOAT_TO_FIXED (ty)); +} + +static void +clutter_glx_texture_pixmap_paint (ClutterActor *actor) +{ + ClutterGLXTexturePixmap *texture = CLUTTER_GLX_TEXTURE_PIXMAP (actor); + ClutterGLXTexturePixmapPrivate *priv = texture->priv; + + gint x_1, y_1, x_2, y_2; + ClutterColor col = { 0xff, 0xff, 0xff, 0xff }; + + if (!backend->t_f_p) + { + CLUTTER_ACTOR_CLASS (clutter_glx_texture_pixmap_parent_class)-> + paint (actor); + return; + } + + if (!CLUTTER_ACTOR_IS_REALIZED (actor)) + clutter_actor_realize (actor); + + cogl_push_matrix (); + + switch (priv->target_type) + { + case CGL_TEXTURE_2D: + cogl_enable (CGL_ENABLE_TEXTURE_2D|CGL_ENABLE_BLEND); + break; + case CGL_TEXTURE_RECTANGLE_ARB: + cogl_enable (CGL_ENABLE_TEXTURE_RECT|CGL_ENABLE_BLEND); + break; + default: + break; + } + + col.alpha = clutter_actor_get_opacity (actor); + + cogl_color (&col); + + clutter_actor_get_coords (actor, &x_1, &y_1, &x_2, &y_2); + + texture_render_to_gl_quad (texture, 0, 0, x_2 - x_1, y_2 - y_1); + + cogl_pop_matrix (); +} + +static GLXFBConfig * +get_fbconfig_for_depth (guint depth) +{ + GLXFBConfig *fbconfigs, *ret = NULL; + int n_elements, i, found; + Display *dpy = ((ClutterBackendX11 *)backend)->xdpy; + int db, stencil, alpha, mipmap, rgba, value; + + fbconfigs = glXGetFBConfigs (dpy, + ((ClutterBackendX11 *)backend)->xscreen_num, + &n_elements); + + db = G_MAXSHORT; + stencil = G_MAXSHORT; + mipmap = 0; + rgba = 0; + + found = n_elements; + + + for (i = 0; i < n_elements; i++) + { + XVisualInfo *vi; + int visual_depth; + + vi = glXGetVisualFromFBConfig (dpy, + fbconfigs[i]); + if (vi == NULL) + continue; + + visual_depth = vi->depth; + + XFree (vi); + + if (visual_depth != depth) + continue; + + glXGetFBConfigAttrib (dpy, + fbconfigs[i], + GLX_ALPHA_SIZE, + &alpha); + glXGetFBConfigAttrib (dpy, + fbconfigs[i], + GLX_BUFFER_SIZE, + &value); + if (value != depth && (value - alpha) != depth) + continue; + + value = 0; + if (depth == 32) + { + glXGetFBConfigAttrib (dpy, + fbconfigs[i], + GLX_BIND_TO_TEXTURE_RGBA_EXT, + &value); + + if (value) + rgba = 1; + } + + if (!value) + { + if (rgba) + continue; + + glXGetFBConfigAttrib (dpy, + fbconfigs[i], + GLX_BIND_TO_TEXTURE_RGB_EXT, + &value); + if (!value) + continue; + } + + glXGetFBConfigAttrib (dpy, + fbconfigs[i], + GLX_DOUBLEBUFFER, + &value); + if (value > db) + continue; + + db = value; + + glXGetFBConfigAttrib (dpy, + fbconfigs[i], + GLX_STENCIL_SIZE, + &value); + if (value > stencil) + continue; + + stencil = value; + + found = i; + } + + if (found != n_elements) + { + ret = g_malloc (sizeof (GLXFBConfig)); + *ret = fbconfigs[found]; + } + + if (n_elements) + XFree (fbconfigs); + + return ret; +} + +static void +clutter_glx_texture_pixmap_create_glx_pixmap (ClutterGLXTexturePixmap *texture) +{ + ClutterGLXTexturePixmapPrivate *priv = texture->priv; + GLXPixmap glx_pixmap; + int attribs[7], i = 0; + GLXFBConfig *fbconfig; + Display *dpy = ((ClutterBackendX11 *)backend)->xdpy; + guint depth; + Pixmap pixmap; + + g_object_get (texture, + "depth", &depth, + "pixmap", &pixmap, + NULL); + + fbconfig = get_fbconfig_for_depth (depth); + + if (!fbconfig) + { + g_critical ("Could not find an FBConfig for selected pixmap"); + return; + } + + attribs[i++] = GLX_TEXTURE_FORMAT_EXT; + + if (depth == 24) + { + attribs[i++] = GLX_TEXTURE_FORMAT_RGB_EXT; + } + else if (depth == 32) + { + attribs[i++] = GLX_TEXTURE_FORMAT_RGBA_EXT; + } + else + { + g_critical ("Pixmap with depth bellow 24 are not supported"); + return; + } + + attribs[i++] = GLX_MIPMAP_TEXTURE_EXT; + attribs[i++] = 0; + + attribs[i++] = GLX_TEXTURE_TARGET_EXT; + + if (priv->target_type == CGL_TEXTURE_RECTANGLE_ARB) + attribs[i++] = GLX_TEXTURE_RECTANGLE_EXT; + else + attribs[i++] = GLX_TEXTURE_2D_EXT; + + attribs[i++] = None; + + + clutter_x11_trap_x_errors (); + glx_pixmap = glXCreatePixmap (dpy, + *fbconfig, + pixmap, + attribs); + XSync (dpy, FALSE); + clutter_x11_untrap_x_errors (); + + g_free (fbconfig); + + if (glx_pixmap != None) + { + if (priv->glx_pixmap) + { + if (backend->t_f_p && + 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 (); + glXDestroyGLXPixmap (dpy, priv->glx_pixmap); + XSync (dpy, FALSE); + clutter_x11_untrap_x_errors (); + } + + priv->glx_pixmap = glx_pixmap; + } +} + +static void +clutter_glx_texture_pixmap_update_area (ClutterX11TexturePixmap *texture, + gint x, + gint y, + gint width, + gint height) +{ + ClutterGLXTexturePixmapPrivate *priv; + Display *dpy = + ((ClutterBackendX11 *)backend)->xdpy; + + priv = CLUTTER_GLX_TEXTURE_PIXMAP (texture)->priv; + + if (!backend->t_f_p) + { + CLUTTER_X11_TEXTURE_PIXMAP_CLASS (texture)->update_area (texture, + x, y, + width, height); + return; + } + + if (!CLUTTER_ACTOR_IS_REALIZED (texture)) + return; + + cogl_texture_bind (priv->target_type, priv->texture_id); + + if (backend->t_f_p) + { + (backend->bind_tex_image) (dpy, + priv->glx_pixmap, + GLX_FRONT_LEFT_EXT, + NULL); + + priv->bound = TRUE; + } +} + +/** + * clutter_glx_texture_pixmap_new_with_pixmap: + * @pixmap: the X Pixmap to which this texture should be bound + * @width: the width of the X pixmap + * @height: the height of the X pixmap + * @depth: the depth of the X pixmap + * + * Return value: A new #ClutterGLXTexturePixmap bound to the given X Pixmap + * + * Since: 0.8 + **/ +ClutterActor * +clutter_glx_texture_pixmap_new_with_pixmap (Pixmap pixmap, + guint width, + guint height, + guint depth) +{ + ClutterActor *actor; + + actor = g_object_new (CLUTTER_GLX_TYPE_TEXTURE_PIXMAP, + "pixmap", pixmap, + "pixmap-width", width, + "pixmap-height", height, + "depth", depth, + NULL); + + return actor; +} + +/** + * clutter_glx_texture_pixmap_new: + * + * Return value: A new #ClutterGLXTexturePixmap + * + * Since: 0.8 + **/ +ClutterActor * +clutter_glx_texture_pixmap_new (void) +{ + ClutterActor *actor; + + actor = g_object_new (CLUTTER_GLX_TYPE_TEXTURE_PIXMAP, NULL); + + return actor; +} diff --git a/clutter/glx/clutter-glx-texture-pixmap.h b/clutter/glx/clutter-glx-texture-pixmap.h new file mode 100644 index 000000000..a24ebe6c2 --- /dev/null +++ b/clutter/glx/clutter-glx-texture-pixmap.h @@ -0,0 +1,70 @@ +/* + * Clutter. + * + * An OpenGL based 'interactive canvas' library. + * + * Authored By Johan Bilien + * + * Copyright (C) 2007 OpenedHand + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the + * Free Software Foundation, Inc., 59 Temple Place - Suite 330, + * Boston, MA 02111-1307, USA. + */ + +#ifndef __CLUTTER_GLX_TEXTURE_PIXMAP_H__ +#define __CLUTTER_GLX_TEXTURE_PIXMAP_H__ + +#include +#include + +#include + +G_BEGIN_DECLS + +#define CLUTTER_GLX_TYPE_TEXTURE_PIXMAP (clutter_glx_texture_pixmap_get_type ()) +#define CLUTTER_GLX_TEXTURE_PIXMAP(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), CLUTTER_GLX_TYPE_TEXTURE_PIXMAP, ClutterGLXTexturePixmap)) +#define CLUTTER_GLX_TEXTURE_PIXMAP_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), CLUTTER_GLX_TYPE_TEXTURE_PIXMAP, ClutterGLXTexturePixmapClass)) +#define CLUTTER_GLX_IS_TEXTURE_PIXMAP(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), CLUTTER_GLX_TYPE_TEXTURE_PIXMAP)) +#define CLUTTER_GLX_IS_TEXTURE_PIXMAP_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), CLUTTER_GLX_TYPE_TEXTURE_PIXMAP)) +#define CLUTTER_GLX_TEXTURE_PIXMAP_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), CLUTTER_GLX_TYPE_TEXTURE_PIXMAP, ClutterGLXTexturePixmapClass)) + +typedef struct _ClutterGLXTexturePixmap ClutterGLXTexturePixmap; +typedef struct _ClutterGLXTexturePixmapClass ClutterGLXTexturePixmapClass; +typedef struct _ClutterGLXTexturePixmapPrivate ClutterGLXTexturePixmapPrivate; + +struct _ClutterGLXTexturePixmapClass +{ + ClutterX11TexturePixmapClass parent_class; +}; + +struct _ClutterGLXTexturePixmap +{ + ClutterX11TexturePixmap parent; + + ClutterGLXTexturePixmapPrivate *priv; +}; + +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); + +G_END_DECLS + +#endif diff --git a/clutter/glx/clutter-glx.h b/clutter/glx/clutter-glx.h index 516054e39..f31436e00 100644 --- a/clutter/glx/clutter-glx.h +++ b/clutter/glx/clutter-glx.h @@ -38,6 +38,7 @@ #include #include +#include #include #include diff --git a/clutter/x11/Makefile.am b/clutter/x11/Makefile.am index 35b846ac0..d1ab34bf0 100644 --- a/clutter/x11/Makefile.am +++ b/clutter/x11/Makefile.am @@ -1,5 +1,6 @@ libclutterincludedir = $(includedir)/clutter-@CLUTTER_API_VERSION@/clutter -libclutterinclude_HEADERS = clutter-x11.h +libclutterinclude_HEADERS = clutter-x11.h \ + clutter-x11-texture-pixmap.h clutter-x11-$(CLUTTER_API_VERSION).pc: clutter-x11.pc @cp -f $< $(@F) @@ -26,6 +27,8 @@ libclutter_x11_la_SOURCES = \ clutter-event-x11.c \ clutter-stage-x11.h \ clutter-stage-x11.c \ + clutter-x11-texture-pixmap.h \ + clutter-x11-texture-pixmap.c \ clutter-x11.h CLEANFILES = clutter-x11-$(CLUTTER_API_VERSION).pc diff --git a/clutter/x11/clutter-x11-texture-pixmap.c b/clutter/x11/clutter-x11-texture-pixmap.c new file mode 100644 index 000000000..af17d508a --- /dev/null +++ b/clutter/x11/clutter-x11-texture-pixmap.c @@ -0,0 +1,611 @@ +/* + * Clutter. + * + * An OpenGL based 'interactive canvas' library. + * + * Authored By Johan Bilien + * + * Copyright (C) 2007 OpenedHand + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the + * Free Software Foundation, Inc., 59 Temple Place - Suite 330, + * Boston, MA 02111-1307, USA. + */ + +/** + * SECTION:clutter-x11-texture-pixmap + * @short_description: A texture which displays the content of an X Pixmap. + * + * #ClutterX11TexturePixmap is a class for displaying the content of an + * X Pixmap as a ClutterActor. Used together with the X Composite extension, + * it allows to display the content of X Windows inside Clutter. + * + * The class uses the GLX_EXT_texture_from_pixmap OpenGL extension + * (http://people.freedesktop.org/~davidr/GLX_EXT_texture_from_pixmap.txt) + * if available + */ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include "../clutter-marshal.h" +#include "clutter-x11-texture-pixmap.h" +#include "clutter-x11.h" +#include "clutter-backend-x11.h" + +#include "cogl.h" + +enum +{ + PROP_PIXMAP = 1, + PROP_PIXMAP_WIDTH, + PROP_PIXMAP_HEIGHT, + PROP_DEPTH +}; + +enum +{ + UPDATE_AREA, + + LAST_SIGNAL +}; + +static guint signals[LAST_SIGNAL] = { 0, }; + +struct _ClutterX11TexturePixmapPrivate +{ + Pixmap pixmap; + guint pixmap_width, pixmap_height; + guint depth; + + XImage *image; + +}; + +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 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 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)) + { + g_critical ("ClutterX11TexturePixmap instanciated with a " + "non-X11 backend"); + return; + } + + backend = (ClutterBackendX11 *)default_backend; + +} + +static void +clutter_x11_texture_pixmap_init (ClutterX11TexturePixmap *self) +{ + self->priv = + G_TYPE_INSTANCE_GET_PRIVATE (self, + CLUTTER_X11_TYPE_TEXTURE_PIXMAP, + ClutterX11TexturePixmapPrivate); + +} + +static GObject * +clutter_x11_texture_pixmap_constructor (GType type, + guint n_construct_properties, + GObjectConstructParam *construct_properties) +{ + GObject *object = G_OBJECT_CLASS (clutter_x11_texture_pixmap_parent_class)-> + constructor (type, n_construct_properties, construct_properties); + + g_object_set (object, + "sync-size", FALSE, + NULL); + + return object; +} + +static void +clutter_x11_texture_pixmap_dispose (GObject *object) +{ + ClutterX11TexturePixmap *texture = CLUTTER_X11_TEXTURE_PIXMAP (object); + ClutterX11TexturePixmapPrivate *priv = texture->priv; + + if (priv->image) + { + XDestroyImage (priv->image); + priv->image = NULL; + } + + G_OBJECT_CLASS (clutter_x11_texture_pixmap_parent_class)->dispose (object); + +} + +static void +clutter_x11_texture_pixmap_set_property (GObject *object, + guint prop_id, + const GValue *value, + GParamSpec *pspec) +{ + ClutterX11TexturePixmap *texture = CLUTTER_X11_TEXTURE_PIXMAP (object); + ClutterX11TexturePixmapPrivate *priv = texture->priv; + + 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; + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); + break; + } +} + +static void +clutter_x11_texture_pixmap_get_property (GObject *object, + guint prop_id, + GValue *value, + GParamSpec *pspec) +{ + 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; + case PROP_PIXMAP_WIDTH: + g_value_set_uint (value, priv->pixmap_width); + break; + case PROP_PIXMAP_HEIGHT: + g_value_set_uint (value, priv->pixmap_height); + break; + case PROP_DEPTH: + g_value_set_uint (value, priv->depth); + break; + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); + break; + } +} + +static void +clutter_x11_texture_pixmap_realize (ClutterActor *actor) +{ + ClutterX11TexturePixmap *texture = CLUTTER_X11_TEXTURE_PIXMAP (actor); + ClutterX11TexturePixmapPrivate *priv = texture->priv; + + CLUTTER_ACTOR_CLASS (clutter_x11_texture_pixmap_parent_class)-> + realize (actor); + + CLUTTER_ACTOR_SET_FLAGS (actor, CLUTTER_ACTOR_REALIZED); + + clutter_x11_texture_pixmap_update_area_real (texture, + 0, 0, + priv->pixmap_width, + priv->pixmap_height); +} + +static void +clutter_x11_texture_pixmap_update_area_real (ClutterX11TexturePixmap *texture, + gint x, + gint y, + gint width, + gint height) +{ + ClutterX11TexturePixmapPrivate *priv; + Display *dpy; + XImage *image; + guint *pixel, *l; + GError *error = NULL; + guint bytes_per_line; + guint8 *data; + gboolean data_allocated = FALSE; + int err_code; + + if (!CLUTTER_ACTOR_IS_REALIZED (texture)) + return; + + priv = texture->priv; + dpy = ((ClutterBackendX11 *)backend)->xdpy; + + clutter_x11_trap_x_errors (); + if (!priv->image) + priv->image = XGetImage (dpy, + priv->pixmap, + 0, 0, + priv->pixmap_width, priv->pixmap_height, + AllPlanes, + ZPixmap); + else + XGetSubImage (dpy, + priv->pixmap, + x, y, + width, height, + AllPlanes, + ZPixmap, + priv->image, + x, y); + + XSync (dpy, FALSE); + if ((err_code = clutter_x11_untrap_x_errors ())) + return; + + image = priv->image; + + if (priv->depth == 24) + { + guint *first_line = (guint *)image->data + y * image->bytes_per_line / 4; + + for (l = first_line; + l != (first_line + height * image->bytes_per_line / 4); + l = l + image->bytes_per_line / 4) + { + for (pixel = l + x; pixel != l + x + width; pixel ++) + { + ((guint8 *)pixel)[3] = 0xFF; + } + } + + data = (guint8 *)first_line + x * 4; + bytes_per_line = image->bytes_per_line; + } + + else if (priv->depth == 16) + { + guint16 *p, *lp; + + data = g_malloc (height * width * 4); + data_allocated = TRUE; + bytes_per_line = priv->pixmap_width * 4; + + for (l = (guint *)data, + lp = (guint16 *)image->data + y * image->bytes_per_line / 2; + l != ((guint *)data + height * width); + l = l + width, lp = lp + image->bytes_per_line / 2) + { + for (pixel = l, p = lp + x; pixel != l + width; pixel ++, p++) + { + *pixel = 0xFF000000 | + (guint)((*p) & 0xf800) << 8 | + (guint)((*p) & 0x07e0) << 5 | + (guint)((*p) & 0x001f) << 3; + } + } + + } + else if (priv->depth == 32) + { + bytes_per_line = image->bytes_per_line; + data = (guint8 *)image->data + y * bytes_per_line + x * 4; + } + else + return; + + if (x != 0 || y != 0 || + width != priv->pixmap_width || height != priv->pixmap_height) + clutter_texture_set_area_from_rgb_data (CLUTTER_TEXTURE (texture), + data, + TRUE, + x, y, + width, height, + bytes_per_line, + 4, + CLUTTER_TEXTURE_RGB_FLAG_BGR, + &error); + else + clutter_texture_set_from_rgb_data (CLUTTER_TEXTURE (texture), + data, + TRUE, + width, height, + bytes_per_line, + 4, + CLUTTER_TEXTURE_RGB_FLAG_BGR, + &error); + + + + if (error) + { + g_warning ("Error when uploading from pixbuf: %s", + error->message); + g_error_free (error); + } + + if (data_allocated) + g_free (data); +} + +/** + * clutter_x11_texture_pixmap_new: + * + * Return value: A new #ClutterX11TexturePixmap + * + * Since: 0.8 + **/ +ClutterActor * +clutter_x11_texture_pixmap_new (void) +{ + ClutterActor *actor; + + actor = g_object_new (CLUTTER_X11_TYPE_TEXTURE_PIXMAP, NULL); + + return actor; +} + +/** + * clutter_x11_texture_pixmap_new_with_pixmap: + * @pixmap: the X Pixmap to which this texture should be bound + * @width: the width of the X pixmap + * @height: the height of the X pixmap + * @depth: the depth of the X pixmap + * + * Return value: A new #ClutterX11TexturePixmap bound to the given X Pixmap + * + * Since 0.8 + **/ +ClutterActor * +clutter_x11_texture_pixmap_new_with_pixmap (Pixmap pixmap, + guint width, + guint height, + guint depth) +{ + ClutterActor *actor; + + actor = g_object_new (CLUTTER_X11_TYPE_TEXTURE_PIXMAP, + "pixmap", pixmap, + "pixmap-width", width, + "pixmap-height", height, + "depth", depth, + NULL); + + return actor; +} + +/** + * clutter_x11_texture_pixmap_set_pixmap: + * @texture: the texture to bind + * @pixmap: the X Pixmap to which the texture should be bound + * @width: the Pixmap width + * @height: the Pixmap height + * @depth: the Pixmap depth, in number of bits + * + * Sets the X Pixmap to which the texture should be bound. + * + * Since: 0.8 + **/ +void +clutter_x11_texture_pixmap_set_pixmap (ClutterX11TexturePixmap *texture, + Pixmap pixmap, + guint width, + guint height, + guint depth) +{ + ClutterX11TexturePixmapPrivate *priv; + + g_return_if_fail (CLUTTER_X11_IS_TEXTURE_PIXMAP (texture)); + + priv = texture->priv; + + 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"); + + } + + 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_x11_texture_pixmap_update_area: + * @texture: The texture whose content shall be updated. + * @x: the X coordinate of the area to update + * @y: the Y coordinate of the area to update + * @width: the width of the area to update + * @height: the height of the area to update + * + * Performs the actual binding of texture to the current content of + * the pixmap. Can be called to update the texture if the pixmap + * content has changed. + * + * Since: 0.8 + **/ +void +clutter_x11_texture_pixmap_update_area (ClutterX11TexturePixmap *texture, + gint x, + gint y, + gint width, + gint height) +{ + g_return_if_fail (CLUTTER_X11_IS_TEXTURE_PIXMAP (texture)); + + g_signal_emit (texture, signals[UPDATE_AREA], 0, x, y, width, height); +} diff --git a/clutter/x11/clutter-x11-texture-pixmap.h b/clutter/x11/clutter-x11-texture-pixmap.h new file mode 100644 index 000000000..77f87310f --- /dev/null +++ b/clutter/x11/clutter-x11-texture-pixmap.h @@ -0,0 +1,90 @@ +/* + * Clutter. + * + * An OpenGL based 'interactive canvas' library. + * + * Authored By Johan Bilien + * + * Copyright (C) 2007 OpenedHand + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the + * Free Software Foundation, Inc., 59 Temple Place - Suite 330, + * Boston, MA 02111-1307, USA. + */ + +#ifndef __CLUTTER_X11_TEXTURE_PIXMAP_H__ +#define __CLUTTER_X11_TEXTURE_PIXMAP_H__ + +#include +#include + + +#include +#include + +G_BEGIN_DECLS + +#define CLUTTER_X11_TYPE_TEXTURE_PIXMAP (clutter_x11_texture_pixmap_get_type ()) +#define CLUTTER_X11_TEXTURE_PIXMAP(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), CLUTTER_X11_TYPE_TEXTURE_PIXMAP, ClutterX11TexturePixmap)) +#define CLUTTER_X11_TEXTURE_PIXMAP_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), CLUTTER_X11_TYPE_TEXTURE_PIXMAP, ClutterX11TexturePixmapClass)) +#define CLUTTER_X11_IS_TEXTURE_PIXMAP(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), CLUTTER_X11_TYPE_TEXTURE_PIXMAP)) +#define CLUTTER_X11_IS_TEXTURE_PIXMAP_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), CLUTTER_X11_TYPE_TEXTURE_PIXMAP)) +#define CLUTTER_X11_TEXTURE_PIXMAP_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), CLUTTER_X11_TYPE_TEXTURE_PIXMAP, ClutterX11TexturePixmapClass)) + +typedef struct _ClutterX11TexturePixmap ClutterX11TexturePixmap; +typedef struct _ClutterX11TexturePixmapClass ClutterX11TexturePixmapClass; +typedef struct _ClutterX11TexturePixmapPrivate ClutterX11TexturePixmapPrivate; + +struct _ClutterX11TexturePixmapClass +{ + ClutterTextureClass parent_class; + + void (*update_area) (ClutterX11TexturePixmap *texture, + gint x, + gint y, + gint width, + gint height); +}; + +struct _ClutterX11TexturePixmap +{ + ClutterTexture parent; + + ClutterX11TexturePixmapPrivate *priv; +}; + +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); + +void clutter_x11_texture_pixmap_set_pixmap (ClutterX11TexturePixmap *texture, + Pixmap pixmap, + guint width, + guint height, + guint depth); + +void clutter_x11_texture_pixmap_update_area (ClutterX11TexturePixmap *texture, + gint x, + gint y, + gint width, + gint height); + + +G_END_DECLS + +#endif