4 * An OpenGL based 'interactive canvas' library.
6 * Copyright (C) 2007 OpenedHand
7 * Copyright (C) 2010 Intel Corporation.
9 * This library is free software; you can redistribute it and/or
10 * modify it under the terms of the GNU Lesser General Public
11 * License as published by the Free Software Foundation; either
12 * version 2 of the License, or (at your option) any later version.
14 * This library is distributed in the hope that it will be useful,
15 * but WITHOUT ANY WARRANTY; without even the implied warranty of
16 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
17 * Lesser General Public License for more details.
19 * You should have received a copy of the GNU Lesser General Public
20 * License along with this library. If not, see <http://www.gnu.org/licenses/>.
23 * Johan Bilien <johan.bilien@nokia.com>
24 * Neil Roberts <neil@linux.intel.com>
28 * SECTION:clutter-x11-texture-pixmap
29 * @Title: ClutterX11TexturePixmap
30 * @short_description: A texture which displays the content of an X Pixmap.
32 * #ClutterX11TexturePixmap is a class for displaying the content of an
33 * X Pixmap as a ClutterActor. Used together with the X Composite extension,
34 * it allows to display the content of X Windows inside Clutter.
36 * The class uses the GLX_EXT_texture_from_pixmap OpenGL extension
37 * (http://people.freedesktop.org/~davidr/GLX_EXT_texture_from_pixmap.txt)
45 #define CLUTTER_ENABLE_EXPERIMENTAL_API
47 #include "clutter-x11-texture-pixmap.h"
48 #include "clutter-x11.h"
49 #include "clutter-backend-x11.h"
51 #include "clutter-actor-private.h"
52 #include "clutter-marshal.h"
53 #include "clutter-paint-volume-private.h"
54 #include "clutter-private.h"
56 #include <cogl/cogl.h>
58 #include <cogl/cogl-texture-pixmap-x11.h>
60 #include <X11/extensions/Xdamage.h>
63 #include <X11/extensions/Xcomposite.h>
74 PROP_WINDOW_REDIRECT_AUTOMATIC,
79 PROP_WINDOW_OVERRIDE_REDIRECT
87 /* FIXME: Pixmap lost signal? */
91 static ClutterX11FilterReturn
92 on_x_event_filter (XEvent *xev, ClutterEvent *cev, gpointer data);
95 clutter_x11_texture_pixmap_update_area_real (ClutterX11TexturePixmap *texture,
101 clutter_x11_texture_pixmap_sync_window_internal (ClutterX11TexturePixmap *texture,
106 gboolean override_redirect);
108 clutter_x11_texture_pixmap_set_mapped (ClutterX11TexturePixmap *texture, gboolean mapped);
110 clutter_x11_texture_pixmap_destroyed (ClutterX11TexturePixmap *texture);
112 static guint signals[LAST_SIGNAL] = { 0, };
114 struct _ClutterX11TexturePixmapPrivate
118 guint pixmap_width, pixmap_height;
123 gint window_x, window_y;
124 gint window_width, window_height;
126 guint window_redirect_automatic : 1;
127 /* FIXME: this is inconsistently either whether the window is mapped or whether
128 * it is viewable, and isn't updated correctly. */
129 guint window_mapped : 1;
131 guint owns_pixmap : 1;
132 guint override_redirect : 1;
133 guint automatic_updates : 1;
136 static int _damage_event_base = 0;
138 G_DEFINE_TYPE (ClutterX11TexturePixmap,
139 clutter_x11_texture_pixmap,
140 CLUTTER_TYPE_TEXTURE);
143 check_extensions (ClutterX11TexturePixmap *texture)
148 if (_damage_event_base)
151 dpy = clutter_x11_get_default_display();
153 if (!XDamageQueryExtension (dpy, &_damage_event_base, &damage_error))
155 g_warning ("No Damage extension");
163 process_damage_event (ClutterX11TexturePixmap *texture,
164 XDamageNotifyEvent *damage_event)
166 /* Cogl will deal with updating the texture and subtracting from the
167 damage region so we only need to queue a redraw */
168 g_signal_emit (texture, signals[QUEUE_DAMAGE_REDRAW],
170 damage_event->area.x,
171 damage_event->area.y,
172 damage_event->area.width,
173 damage_event->area.height);
176 static ClutterX11FilterReturn
177 on_x_event_filter (XEvent *xev, ClutterEvent *cev, gpointer data)
179 ClutterX11TexturePixmap *texture;
180 ClutterX11TexturePixmapPrivate *priv;
182 texture = CLUTTER_X11_TEXTURE_PIXMAP (data);
184 g_return_val_if_fail (CLUTTER_X11_IS_TEXTURE_PIXMAP (texture), \
185 CLUTTER_X11_FILTER_CONTINUE);
187 priv = texture->priv;
189 if (xev->type == _damage_event_base + XDamageNotify)
191 XDamageNotifyEvent *dev = (XDamageNotifyEvent*)xev;
193 if (dev->damage != priv->damage)
194 return CLUTTER_X11_FILTER_CONTINUE;
196 process_damage_event (texture, dev);
199 return CLUTTER_X11_FILTER_CONTINUE;
202 static ClutterX11FilterReturn
203 on_x_event_filter_too (XEvent *xev, ClutterEvent *cev, gpointer data)
205 ClutterX11TexturePixmap *texture;
206 ClutterX11TexturePixmapPrivate *priv;
208 texture = CLUTTER_X11_TEXTURE_PIXMAP (data);
210 g_return_val_if_fail (CLUTTER_X11_IS_TEXTURE_PIXMAP (texture), \
211 CLUTTER_X11_FILTER_CONTINUE);
213 priv = texture->priv;
215 if (xev->xany.window != priv->window)
216 return CLUTTER_X11_FILTER_CONTINUE;
220 clutter_x11_texture_pixmap_sync_window_internal (texture,
225 priv->override_redirect);
227 case ConfigureNotify:
228 clutter_x11_texture_pixmap_sync_window_internal (texture,
231 xev->xconfigure.width,
232 xev->xconfigure.height,
233 xev->xconfigure.override_redirect);
236 clutter_x11_texture_pixmap_set_mapped (texture, FALSE);
239 clutter_x11_texture_pixmap_destroyed (texture);
245 return CLUTTER_X11_FILTER_CONTINUE;
249 update_pixmap_damage_object (ClutterX11TexturePixmap *texture)
251 ClutterX11TexturePixmapPrivate *priv = texture->priv;
252 CoglHandle cogl_texture;
254 /* If we already have a CoglTexturePixmapX11 then update its
257 clutter_texture_get_cogl_texture (CLUTTER_TEXTURE (texture));
259 if (cogl_texture && cogl_is_texture_pixmap_x11 (cogl_texture))
263 const CoglTexturePixmapX11ReportLevel report_level =
264 COGL_TEXTURE_PIXMAP_X11_DAMAGE_BOUNDING_BOX;
265 cogl_texture_pixmap_x11_set_damage_object (cogl_texture,
270 cogl_texture_pixmap_x11_set_damage_object (cogl_texture, 0, 0);
275 create_damage_resources (ClutterX11TexturePixmap *texture)
277 ClutterX11TexturePixmapPrivate *priv;
280 priv = texture->priv;
281 dpy = clutter_x11_get_default_display();
286 clutter_x11_trap_x_errors ();
288 priv->damage = XDamageCreate (dpy,
290 XDamageReportBoundingBox);
292 /* Errors here might occur if the window is already destroyed, we
293 * simply skip processing damage and assume that the texture pixmap
294 * will be cleaned up by the app when it gets a DestroyNotify.
297 clutter_x11_untrap_x_errors ();
301 clutter_x11_add_filter (on_x_event_filter, (gpointer)texture);
303 update_pixmap_damage_object (texture);
308 free_damage_resources (ClutterX11TexturePixmap *texture)
310 ClutterX11TexturePixmapPrivate *priv;
313 priv = texture->priv;
314 dpy = clutter_x11_get_default_display();
318 clutter_x11_trap_x_errors ();
319 XDamageDestroy (dpy, priv->damage);
321 clutter_x11_untrap_x_errors ();
324 clutter_x11_remove_filter (on_x_event_filter, (gpointer)texture);
326 update_pixmap_damage_object (texture);
331 clutter_x11_texture_pixmap_get_paint_volume (ClutterActor *self,
332 ClutterPaintVolume *volume)
334 return clutter_paint_volume_set_from_allocation (volume, self);
338 clutter_x11_texture_pixmap_real_queue_damage_redraw (
339 ClutterX11TexturePixmap *texture,
345 ClutterX11TexturePixmapPrivate *priv = texture->priv;
346 ClutterActor *self = CLUTTER_ACTOR (texture);
347 ClutterActorBox allocation;
348 float scale_x, scale_y;
349 cairo_rectangle_int_t clip;
351 /* NB: clutter_actor_queue_clipped_redraw expects a box in the actor's
352 * coordinate space so we need to convert from pixmap coordinates to
353 * actor coordinates...
356 /* Calling clutter_actor_get_allocation_box() is enormously expensive
357 * if the actor has an out-of-date allocation, since it triggers
358 * a full redraw. clutter_actor_queue_clipped_redraw() would redraw
359 * the whole stage anyways in that case, so just go ahead and do
362 if (!clutter_actor_has_allocation (self))
364 clutter_actor_queue_redraw (self);
368 if (priv->pixmap_width == 0 || priv->pixmap_height == 0)
371 clutter_actor_get_allocation_box (self, &allocation);
373 scale_x = (allocation.x2 - allocation.x1) / priv->pixmap_width;
374 scale_y = (allocation.y2 - allocation.y1) / priv->pixmap_height;
376 clip.x = x * scale_x;
377 clip.y = y * scale_y;
378 clip.width = width * scale_x;
379 clip.height = height * scale_y;
380 clutter_actor_queue_redraw_with_clip (self, &clip);
384 clutter_x11_texture_pixmap_init (ClutterX11TexturePixmap *self)
387 G_TYPE_INSTANCE_GET_PRIVATE (self,
388 CLUTTER_X11_TYPE_TEXTURE_PIXMAP,
389 ClutterX11TexturePixmapPrivate);
391 if (!check_extensions (self))
393 /* FIMXE: means display lacks needed extensions for at least auto.
394 * - a _can_autoupdate() method ?
398 self->priv->automatic_updates = FALSE;
399 self->priv->damage = None;
400 self->priv->window = None;
401 self->priv->pixmap = None;
402 self->priv->pixmap_height = 0;
403 self->priv->pixmap_width = 0;
404 self->priv->window_redirect_automatic = TRUE;
405 self->priv->window_mapped = FALSE;
406 self->priv->destroyed = FALSE;
407 self->priv->override_redirect = FALSE;
408 self->priv->window_x = 0;
409 self->priv->window_y = 0;
413 clutter_x11_texture_pixmap_dispose (GObject *object)
415 ClutterX11TexturePixmap *texture = CLUTTER_X11_TEXTURE_PIXMAP (object);
417 free_damage_resources (texture);
419 clutter_x11_remove_filter (on_x_event_filter_too, (gpointer)texture);
420 clutter_x11_texture_pixmap_set_pixmap (texture, None);
422 G_OBJECT_CLASS (clutter_x11_texture_pixmap_parent_class)->dispose (object);
426 clutter_x11_texture_pixmap_set_property (GObject *object,
431 ClutterX11TexturePixmap *texture = CLUTTER_X11_TEXTURE_PIXMAP (object);
432 ClutterX11TexturePixmapPrivate *priv = texture->priv;
437 clutter_x11_texture_pixmap_set_pixmap (texture,
438 g_value_get_ulong (value));
441 clutter_x11_texture_pixmap_set_automatic (texture,
442 g_value_get_boolean (value));
445 clutter_x11_texture_pixmap_set_window (texture,
446 g_value_get_ulong (value),
447 priv->window_redirect_automatic);
449 case PROP_WINDOW_REDIRECT_AUTOMATIC:
452 new = g_value_get_boolean (value);
454 /* Change the update mode.. */
455 if (new != priv->window_redirect_automatic && priv->window)
456 clutter_x11_texture_pixmap_set_window (texture, priv->window, new);
458 priv->window_redirect_automatic = new;
462 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
468 clutter_x11_texture_pixmap_get_property (GObject *object,
473 ClutterX11TexturePixmap *texture = CLUTTER_X11_TEXTURE_PIXMAP (object);
474 ClutterX11TexturePixmapPrivate *priv = texture->priv;
479 g_value_set_ulong (value, priv->pixmap);
481 case PROP_PIXMAP_WIDTH:
482 g_value_set_uint (value, priv->pixmap_width);
484 case PROP_PIXMAP_HEIGHT:
485 g_value_set_uint (value, priv->pixmap_height);
488 g_value_set_uint (value, priv->depth);
491 g_value_set_boolean (value, priv->automatic_updates);
494 g_value_set_ulong (value, priv->window);
496 case PROP_WINDOW_REDIRECT_AUTOMATIC:
497 g_value_set_boolean (value, priv->window_redirect_automatic);
499 case PROP_WINDOW_MAPPED:
500 g_value_set_boolean (value, priv->window_mapped);
503 g_value_set_boolean (value, priv->destroyed);
506 g_value_set_int (value, priv->window_x);
509 g_value_set_int (value, priv->window_y);
511 case PROP_WINDOW_OVERRIDE_REDIRECT:
512 g_value_set_boolean (value, priv->override_redirect);
515 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
521 clutter_x11_texture_pixmap_class_init (ClutterX11TexturePixmapClass *klass)
523 GObjectClass *object_class = G_OBJECT_CLASS (klass);
524 ClutterActorClass *actor_class = CLUTTER_ACTOR_CLASS (klass);
527 g_type_class_add_private (klass, sizeof (ClutterX11TexturePixmapPrivate));
529 actor_class->get_paint_volume = clutter_x11_texture_pixmap_get_paint_volume;
531 object_class->dispose = clutter_x11_texture_pixmap_dispose;
532 object_class->set_property = clutter_x11_texture_pixmap_set_property;
533 object_class->get_property = clutter_x11_texture_pixmap_get_property;
535 klass->update_area = clutter_x11_texture_pixmap_update_area_real;
537 pspec = g_param_spec_ulong ("pixmap",
539 P_("The X11 Pixmap to be bound"),
544 g_object_class_install_property (object_class, PROP_PIXMAP, pspec);
546 pspec = g_param_spec_uint ("pixmap-width",
548 P_("The width of the pixmap bound to this texture"),
553 g_object_class_install_property (object_class, PROP_PIXMAP_WIDTH, pspec);
555 pspec = g_param_spec_uint ("pixmap-height",
557 P_("The height of the pixmap bound to this texture"),
562 g_object_class_install_property (object_class, PROP_PIXMAP_HEIGHT, pspec);
564 pspec = g_param_spec_uint ("pixmap-depth",
566 P_("The depth (in number of bits) of the pixmap bound to this texture"),
571 g_object_class_install_property (object_class, PROP_DEPTH, pspec);
573 pspec = g_param_spec_boolean ("automatic-updates",
574 P_("Automatic Updates"),
575 P_("If the texture should be kept in "
576 "sync with any pixmap changes."),
580 g_object_class_install_property (object_class, PROP_AUTO, pspec);
582 pspec = g_param_spec_ulong ("window",
584 P_("The X11 Window to be bound"),
589 g_object_class_install_property (object_class, PROP_WINDOW, pspec);
591 pspec = g_param_spec_boolean ("window-redirect-automatic",
592 P_("Window Redirect Automatic"),
593 P_("If composite window redirects are set to "
594 "Automatic (or Manual if false)"),
598 g_object_class_install_property (object_class,
599 PROP_WINDOW_REDIRECT_AUTOMATIC, pspec);
602 pspec = g_param_spec_boolean ("window-mapped",
604 P_("If window is mapped"),
608 g_object_class_install_property (object_class,
609 PROP_WINDOW_MAPPED, pspec);
612 pspec = g_param_spec_boolean ("destroyed",
614 P_("If window has been destroyed"),
618 g_object_class_install_property (object_class,
619 PROP_DESTROYED, pspec);
621 pspec = g_param_spec_int ("window-x",
623 P_("X position of window on screen according to X11"),
624 G_MININT, G_MAXINT, 0, G_PARAM_READABLE);
626 g_object_class_install_property (object_class,
627 PROP_WINDOW_X, pspec);
630 pspec = g_param_spec_int ("window-y",
632 P_("Y position of window on screen according to X11"),
633 G_MININT, G_MAXINT, 0, G_PARAM_READABLE);
635 g_object_class_install_property (object_class,
636 PROP_WINDOW_Y, pspec);
638 pspec = g_param_spec_boolean ("window-override-redirect",
639 P_("Window Override Redirect"),
640 P_("If this is an override-redirect window"),
644 g_object_class_install_property (object_class,
645 PROP_WINDOW_OVERRIDE_REDIRECT, pspec);
649 * ClutterX11TexturePixmap::update-area:
650 * @texture: the object which received the signal
652 * The ::update-area signal is emitted to ask the texture to update its
653 * content from its source pixmap.
657 signals[UPDATE_AREA] =
658 g_signal_new (g_intern_static_string ("update-area"),
659 G_TYPE_FROM_CLASS (object_class),
661 G_STRUCT_OFFSET (ClutterX11TexturePixmapClass, \
664 _clutter_marshal_VOID__INT_INT_INT_INT,
672 * ClutterX11TexturePixmap::queue-damage-redraw:
673 * @texture: the object which received the signal
674 * @x: The top left x position of the damage region
675 * @y: The top left y position of the damage region
676 * @width: The width of the damage region
677 * @height: The height of the damage region
679 * ::queue-damage-redraw is emitted to notify that some sub-region
680 * of the texture has been changed (either by an automatic damage
681 * update or by an explicit call to
682 * clutter_x11_texture_pixmap_update_area). This usually means a
683 * redraw needs to be queued for the actor.
685 * The default handler will queue a clipped redraw in response to
686 * the damage, using the assumption that the pixmap is being painted
687 * to a rectangle covering the transformed allocation of the actor.
688 * If you sub-class and change the paint method so this isn't true
689 * then you must also provide your own damage signal handler to
690 * queue a redraw that blocks this default behaviour.
694 signals[QUEUE_DAMAGE_REDRAW] =
695 g_signal_new (g_intern_static_string ("queue-damage-redraw"),
696 G_TYPE_FROM_CLASS (object_class),
700 _clutter_marshal_VOID__INT_INT_INT_INT,
707 g_signal_override_class_handler ("queue-damage-redraw",
708 CLUTTER_X11_TYPE_TEXTURE_PIXMAP,
709 G_CALLBACK (clutter_x11_texture_pixmap_real_queue_damage_redraw));
713 clutter_x11_texture_pixmap_update_area_real (ClutterX11TexturePixmap *texture,
719 CoglHandle cogl_texture;
721 cogl_texture = clutter_texture_get_cogl_texture (CLUTTER_TEXTURE (texture));
724 cogl_texture_pixmap_x11_update_area (cogl_texture, x, y, width, height);
728 * clutter_x11_texture_pixmap_new:
730 * Creates a new #ClutterX11TexturePixmap which can be used to display the
731 * contents of an X11 Pixmap inside a Clutter scene graph
733 * Return value: A new #ClutterX11TexturePixmap
738 clutter_x11_texture_pixmap_new (void)
742 actor = g_object_new (CLUTTER_X11_TYPE_TEXTURE_PIXMAP, NULL);
748 * clutter_x11_texture_pixmap_new_with_pixmap:
749 * @pixmap: the X Pixmap to which this texture should be bound
751 * Creates a new #ClutterX11TexturePixmap for @pixmap
753 * Return value: A new #ClutterX11TexturePixmap bound to the given X Pixmap
758 clutter_x11_texture_pixmap_new_with_pixmap (Pixmap pixmap)
762 actor = g_object_new (CLUTTER_X11_TYPE_TEXTURE_PIXMAP,
770 * clutter_x11_texture_pixmap_new_with_window:
771 * @window: the X window to which this texture should be bound
773 * Creates a new #ClutterX11TexturePixmap for @window
775 * Return value: A new #ClutterX11TexturePixmap bound to the given X window.
780 clutter_x11_texture_pixmap_new_with_window (Window window)
784 actor = g_object_new (CLUTTER_X11_TYPE_TEXTURE_PIXMAP,
792 * clutter_x11_texture_pixmap_set_pixmap:
793 * @texture: the texture to bind
794 * @pixmap: the X Pixmap to which the texture should be bound
796 * Sets the X Pixmap to which the texture should be bound.
801 clutter_x11_texture_pixmap_set_pixmap (ClutterX11TexturePixmap *texture,
806 unsigned int width, height, border_width, depth;
808 gboolean new_pixmap = FALSE, new_pixmap_width = FALSE;
809 gboolean new_pixmap_height = FALSE, new_pixmap_depth = FALSE;
810 CoglPipeline *pipeline;
812 ClutterX11TexturePixmapPrivate *priv;
814 g_return_if_fail (CLUTTER_X11_IS_TEXTURE_PIXMAP (texture));
816 priv = texture->priv;
818 /* Get rid of the existing Cogl texture early because it may try to
819 use the pixmap which we might destroy */
820 pipeline = (CoglPipeline *)
821 clutter_texture_get_cogl_material (CLUTTER_TEXTURE (texture));
823 cogl_pipeline_set_layer_texture (pipeline, 0, NULL);
827 clutter_x11_trap_x_errors ();
828 status = XGetGeometry (clutter_x11_get_default_display(),
838 if (clutter_x11_untrap_x_errors () || status == 0)
840 g_warning ("Unable to query pixmap: %lx", pixmap);
842 width = height = depth = 0;
847 width = height = depth = 0;
850 if (priv->pixmap != pixmap)
852 if (priv->pixmap && priv->owns_pixmap)
853 XFreePixmap (clutter_x11_get_default_display (), priv->pixmap);
855 priv->pixmap = pixmap;
858 /* The damage object is created on the pixmap, so it needs to be
859 * recreated with a change in pixmap.
861 if (priv->automatic_updates)
863 free_damage_resources (texture);
864 create_damage_resources (texture);
868 if (priv->pixmap_width != width)
870 priv->pixmap_width = width;
871 new_pixmap_width = TRUE;
874 if (priv->pixmap_height != height)
876 priv->pixmap_height = height;
877 new_pixmap_height = TRUE;
880 if (priv->depth != depth)
883 new_pixmap_depth = TRUE;
886 /* NB: We defer sending the signals until updating all the
887 * above members so the values are all available to the
888 * signal handlers. */
889 g_object_ref (texture);
892 g_object_notify (G_OBJECT (texture), "pixmap");
893 if (new_pixmap_width)
894 g_object_notify (G_OBJECT (texture), "pixmap-width");
895 if (new_pixmap_height)
896 g_object_notify (G_OBJECT (texture), "pixmap-height");
897 if (new_pixmap_depth)
898 g_object_notify (G_OBJECT (texture), "pixmap-depth");
903 clutter_backend_get_cogl_context (clutter_get_default_backend ());
904 GError *error = NULL;
905 CoglTexturePixmapX11 *texture_pixmap =
906 cogl_texture_pixmap_x11_new (ctx, pixmap, FALSE, &error);
909 clutter_texture_set_cogl_texture (CLUTTER_TEXTURE (texture),
910 COGL_TEXTURE (texture_pixmap));
911 cogl_object_unref (texture_pixmap);
912 update_pixmap_damage_object (texture);
916 g_warning ("Failed to create CoglTexturePixmapX11: %s",
918 g_error_free (error);
923 * Keep ref until here in case a notify causes removal from the scene; can't
924 * lower the notifies because glx's notify handler needs to run before
927 g_object_unref (texture);
931 * clutter_x11_texture_pixmap_set_window:
932 * @texture: the texture to bind
933 * @window: the X window to which the texture should be bound
934 * @automatic: %TRUE for automatic window updates, %FALSE for manual.
936 * Sets up a suitable pixmap for the window, using the composite and damage
937 * extensions if possible, and then calls
938 * clutter_x11_texture_pixmap_set_pixmap().
940 * If you want to display a window in a #ClutterTexture, you probably want
941 * this function, or its older sister, clutter_glx_texture_pixmap_set_window().
943 * This function has no effect unless the XComposite extension is available.
948 clutter_x11_texture_pixmap_set_window (ClutterX11TexturePixmap *texture,
952 ClutterX11TexturePixmapPrivate *priv;
953 XWindowAttributes attr;
956 g_return_if_fail (CLUTTER_X11_IS_TEXTURE_PIXMAP (texture));
958 if (!clutter_x11_has_composite_extension ())
961 dpy = clutter_x11_get_default_display ();
966 priv = texture->priv;
968 if (priv->window == window && automatic == priv->window_redirect_automatic)
973 clutter_x11_remove_filter (on_x_event_filter_too, (gpointer)texture);
974 clutter_x11_trap_x_errors ();
975 XCompositeUnredirectWindow(clutter_x11_get_default_display (),
977 priv->window_redirect_automatic ?
978 CompositeRedirectAutomatic : CompositeRedirectManual);
979 XSync (clutter_x11_get_default_display (), False);
980 clutter_x11_untrap_x_errors ();
982 clutter_x11_texture_pixmap_set_pixmap (texture, None);
985 priv->window = window;
986 priv->window_redirect_automatic = automatic;
987 priv->window_mapped = FALSE;
988 priv->destroyed = FALSE;
993 clutter_x11_trap_x_errors ();
995 if (!XGetWindowAttributes (dpy, window, &attr))
998 clutter_x11_untrap_x_errors ();
999 g_warning ("bad window 0x%x", (guint32)window);
1000 priv->window = None;
1004 XCompositeRedirectWindow
1008 CompositeRedirectAutomatic : CompositeRedirectManual);
1012 clutter_x11_untrap_x_errors ();
1014 XSelectInput (dpy, priv->window,
1015 attr.your_event_mask | StructureNotifyMask);
1016 clutter_x11_add_filter (on_x_event_filter_too, (gpointer)texture);
1018 g_object_ref (texture);
1019 g_object_notify (G_OBJECT (texture), "window");
1021 clutter_x11_texture_pixmap_set_mapped (texture,
1022 attr.map_state == IsViewable);
1024 clutter_x11_texture_pixmap_sync_window_internal (texture,
1026 attr.width, attr.height,
1027 attr.override_redirect);
1028 g_object_unref (texture);
1030 #endif /* HAVE_XCOMPOSITE */
1034 clutter_x11_texture_pixmap_sync_window_internal (ClutterX11TexturePixmap *texture,
1039 gboolean override_redirect)
1041 ClutterX11TexturePixmapPrivate *priv;
1042 Pixmap pixmap = None;
1043 gboolean mapped = FALSE;
1044 gboolean notify_x = FALSE;
1045 gboolean notify_y = FALSE;
1046 gboolean notify_override_redirect = FALSE;
1048 priv = texture->priv;
1050 if (priv->destroyed)
1053 notify_x = x != priv->window_x;
1054 notify_y = y != priv->window_y;
1055 notify_override_redirect = override_redirect != priv->override_redirect;
1058 priv->window_width = width;
1059 priv->window_height = height;
1060 priv->override_redirect = override_redirect;
1062 if (!clutter_x11_has_composite_extension ())
1064 /* FIXME: this should just be an error, this is unlikely to work worth anything */
1065 clutter_x11_texture_pixmap_set_pixmap (texture, priv->window);
1069 if (priv->pixmap == None || width != priv->pixmap_width || height != priv->pixmap_height)
1071 /* Note that we're checking the size from the event against the size we obtained
1072 * from the last XCompositeNameWindowPixmap/XGetGeometry pair. This will always
1073 * end up right in the end, but we can have a series like:
1075 * Window sized to 100x100
1076 * Window sized to 110x110
1077 * Window sized to 120x120
1078 * Configure received for 100x100 - NameWindowPixmap
1079 * Configure received for 110x110 - NameWindowPixmap
1080 * Configure received for 120x120 - last size OK
1082 * Where we NameWindowPixmap several times in a row. (Using pixmap_width/pixmap_height
1083 * rather than window_width/window_height saves the last one.)
1086 Display *dpy = clutter_x11_get_default_display ();
1088 /* NB: It's only valid to name a pixmap if the window is viewable.
1090 * We don't explicitly check this though since there would be a race
1091 * between checking and naming unless we use a server grab which is
1094 * Instead we gracefully handle any error with naming the pixmap.
1096 clutter_x11_trap_x_errors ();
1098 pixmap = XCompositeNameWindowPixmap (dpy, priv->window);
1100 /* Possible improvement: combine with the XGetGeometry in
1101 * clutter_x11_texture_pixmap_set_pixmap() */
1104 if (clutter_x11_untrap_x_errors ())
1108 g_object_ref (texture); /* guard against unparent */
1109 g_object_freeze_notify (G_OBJECT (texture));
1111 /* FIXME: mapped is always FALSE */
1112 clutter_x11_texture_pixmap_set_mapped (texture, mapped);
1116 clutter_x11_texture_pixmap_set_pixmap (texture, pixmap);
1117 priv->owns_pixmap = TRUE;
1120 if (notify_override_redirect)
1121 g_object_notify (G_OBJECT (texture), "window-override-redirect");
1123 g_object_notify (G_OBJECT (texture), "window-x");
1125 g_object_notify (G_OBJECT (texture), "window-y");
1127 g_object_thaw_notify (G_OBJECT (texture));
1128 g_object_unref (texture);
1132 * clutter_x11_texture_pixmap_sync_window:
1133 * @texture: the texture to bind
1135 * Resets the texture's pixmap from its window, perhaps in response to the
1136 * pixmap's invalidation as the window changed size.
1141 clutter_x11_texture_pixmap_sync_window (ClutterX11TexturePixmap *texture)
1143 ClutterX11TexturePixmapPrivate *priv;
1145 g_return_if_fail (CLUTTER_X11_IS_TEXTURE_PIXMAP (texture));
1147 priv = texture->priv;
1149 if (priv->destroyed)
1152 if (priv->window != None)
1154 Display *dpy = clutter_x11_get_default_display ();
1155 XWindowAttributes attr;
1161 clutter_x11_trap_x_errors ();
1163 status = XGetWindowAttributes (dpy, priv->window, &attr);
1165 clutter_x11_texture_pixmap_sync_window_internal (texture,
1167 attr.width, attr.height,
1168 attr.override_redirect);
1170 clutter_x11_untrap_x_errors ();
1175 clutter_x11_texture_pixmap_set_mapped (ClutterX11TexturePixmap *texture,
1178 ClutterX11TexturePixmapPrivate *priv;
1180 priv = texture->priv;
1182 if (mapped != priv->window_mapped)
1184 priv->window_mapped = mapped;
1185 g_object_notify (G_OBJECT (texture), "window-mapped");
1190 clutter_x11_texture_pixmap_destroyed (ClutterX11TexturePixmap *texture)
1192 ClutterX11TexturePixmapPrivate *priv;
1194 priv = texture->priv;
1196 if (!priv->destroyed)
1198 priv->destroyed = TRUE;
1199 g_object_notify (G_OBJECT (texture), "destroyed");
1203 * Don't set window to None, that would destroy the pixmap, which might still
1204 * be useful e.g. for destroy animations -- app's responsibility.
1209 * clutter_x11_texture_pixmap_update_area:
1210 * @texture: The texture whose content shall be updated.
1211 * @x: the X coordinate of the area to update
1212 * @y: the Y coordinate of the area to update
1213 * @width: the width of the area to update
1214 * @height: the height of the area to update
1216 * Performs the actual binding of texture to the current content of
1217 * the pixmap. Can be called to update the texture if the pixmap
1218 * content has changed.
1223 clutter_x11_texture_pixmap_update_area (ClutterX11TexturePixmap *texture,
1229 g_return_if_fail (CLUTTER_X11_IS_TEXTURE_PIXMAP (texture));
1231 g_signal_emit (texture, signals[UPDATE_AREA], 0, x, y, width, height);
1233 /* The default handler for the "queue-damage-redraw" signal is
1234 * clutter_x11_texture_pixmap_real_queue_damage_redraw which will queue a
1235 * clipped redraw. */
1236 g_signal_emit (texture, signals[QUEUE_DAMAGE_REDRAW],
1237 0, x, y, width, height);
1241 * clutter_x11_texture_pixmap_set_automatic:
1242 * @texture: a #ClutterX11TexturePixmap
1243 * @setting: %TRUE to enable automatic updates
1245 * Enables or disables the automatic updates ot @texture in case the backing
1246 * pixmap or window is damaged
1251 clutter_x11_texture_pixmap_set_automatic (ClutterX11TexturePixmap *texture,
1254 ClutterX11TexturePixmapPrivate *priv;
1256 g_return_if_fail (CLUTTER_X11_IS_TEXTURE_PIXMAP (texture));
1258 priv = texture->priv;
1260 setting = !!setting;
1261 if (setting == priv->automatic_updates)
1265 create_damage_resources (texture);
1267 free_damage_resources (texture);
1269 priv->automatic_updates = setting;