summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorFilippo Argiolas <filippo.argiolas@gmail.com>2009-04-19 20:42:44 +0200
committerFilippo Argiolas <filippo.argiolas@gmail.com>2009-04-19 21:15:55 +0200
commit8918375e77c548711f0e93edfb901c61de6d7c8f (patch)
treee73312ad9415191f11bf326b8123b88fb43bef57
parentbe5eb9a9cd1aca2a73686f51b3dac36e1b6299f5 (diff)
Initial commit for GtkClutterEmbed integration
I'm sorry for this big commit but I was working on a separate branch and it was stuffed with several silly commits with unuseful messages (in sardo) that I didn't want to make public :P Let's summarize what happened: 1. Move to gdkwindow - clutter-gtk disables x11 event retrieval. This has the unfortunate consequence of f***ing up ClutterX11TexturePixmap auto update part and sync pixmap on window configure/map part - also this prevents me from using the x11 filters to remap unmapped windows on stage iconification - how to solve this? clutter doesn't handle x11 events anymore because gdk does, so let's use a gdk filter to: a) listen to damage events to reproduce auto-updates behaviour (partly copied and reworked from ClutterX11TexturePixmap implementation b) listen to structure events to sync pixmap on map and configure c) listen to stage win map events to remap on iconification - also take advantage of gdk windowing api (to improve) - I'm still doubtful about reparent on stage realize thing... but don't how to handle differently since GtkClutterEmbed sets a foreign window for the stage on realize 2. First test with a layout manager - copied from TidyGrid just to test how a layout works - resize layout on window configure-event 3. Hope that's all... it is as far as I remember
-rw-r--r--configure.ac5
-rw-r--r--src/Makefile.am4
-rw-r--r--src/cheese-grid.c1006
-rw-r--r--src/cheese-grid.h99
-rw-r--r--src/cheese-stage.c155
-rw-r--r--src/cheese-texture.c218
6 files changed, 1407 insertions, 80 deletions
diff --git a/configure.ac b/configure.ac
index 04d5886..7faf6da 100644
--- a/configure.ac
+++ b/configure.ac
@@ -5,8 +5,6 @@ AC_PROG_CC
AC_HEADER_STDC
AM_PROG_LIBTOOL
-CFLAGS="${CFLAGS} -Wall -Werror"
-
GNOME_MAINTAINER_MODE_DEFINES
GNOME_COMPILE_WARNINGS
@@ -21,7 +19,8 @@ PKG_CHECK_MODULES([GSTREAMER], \
PKG_CHECK_MODULES([CLUTTER], \
clutter-0.9 >= 0.9.0 \
clutter-glx-0.9 >= 0.9.0 \
- clutter-x11-0.9 >= 0.9.0)
+ clutter-x11-0.9 >= 0.9.0 \
+ clutter-gtk-0.9 >= 0.9.0)
AC_OUTPUT([
Makefile
diff --git a/src/Makefile.am b/src/Makefile.am
index 50cb73b..4c77e41 100644
--- a/src/Makefile.am
+++ b/src/Makefile.am
@@ -3,7 +3,9 @@ bin_PROGRAMS = cheese-stage
cheese_stage_SOURCES = \
cheese-stage.c \
cheese-texture.h \
- cheese-texture.c
+ cheese-texture.c \
+ cheese-grid.h \
+ cheese-grid.c
cheese_stage_LDADD = \
$(GLIB_LIBS) \
diff --git a/src/cheese-grid.c b/src/cheese-grid.c
new file mode 100644
index 0000000..3fe5ce0
--- /dev/null
+++ b/src/cheese-grid.c
@@ -0,0 +1,1006 @@
+/* cheese-grid.h: Reflowing grid layout container for clutter.
+ *
+ * Copyright (C) 2008 Intel Corporation
+ *
+ * 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.
+ *
+ * Written by: Øyvind Kolås <pippin@linux.intel.com>
+ */
+
+/* TODO:
+ *
+ * - Better names for properties.
+ * - Caching layouted positions? (perhaps needed for huge collections)
+ * - More comments / overall concept on how the layouting is done.
+ * - Allow more layout directions than just row major / column major.
+ */
+
+#include "cheese-grid.h"
+
+typedef struct _CheeseGridActorData CheeseGridActorData;
+
+static void cheese_grid_dispose (GObject *object);
+static void cheese_grid_finalize (GObject *object);
+
+static void cheese_grid_finalize (GObject *object);
+
+static void cheese_grid_set_property (GObject *object,
+ guint prop_id,
+ const GValue *value,
+ GParamSpec *pspec);
+static void cheese_grid_get_property (GObject *object,
+ guint prop_id,
+ GValue *value,
+ GParamSpec *pspec);
+
+static void clutter_container_iface_init (ClutterContainerIface *iface);
+
+static void cheese_grid_real_add (ClutterContainer *container,
+ ClutterActor *actor);
+static void cheese_grid_real_remove (ClutterContainer *container,
+ ClutterActor *actor);
+static void cheese_grid_real_foreach (ClutterContainer *container,
+ ClutterCallback callback,
+ gpointer user_data);
+static void cheese_grid_real_raise (ClutterContainer *container,
+ ClutterActor *actor,
+ ClutterActor *sibling);
+static void cheese_grid_real_lower (ClutterContainer *container,
+ ClutterActor *actor,
+ ClutterActor *sibling);
+static void
+cheese_grid_real_sort_depth_order (ClutterContainer *container);
+
+static void
+cheese_grid_free_actor_data (gpointer data);
+
+static void cheese_grid_paint (ClutterActor *actor);
+
+static void cheese_grid_pick (ClutterActor *actor,
+ const ClutterColor *color);
+
+static void
+cheese_grid_get_preferred_width (ClutterActor *self,
+ ClutterUnit for_height,
+ ClutterUnit *min_width_p,
+ ClutterUnit *natural_width_p);
+
+static void
+cheese_grid_get_preferred_height (ClutterActor *self,
+ ClutterUnit for_width,
+ ClutterUnit *min_height_p,
+ ClutterUnit *natural_height_p);
+
+static void cheese_grid_allocate (ClutterActor *self,
+ const ClutterActorBox *box,
+ gboolean absolute_origin_changed);
+
+G_DEFINE_TYPE_WITH_CODE (CheeseGrid, cheese_grid,
+ CLUTTER_TYPE_ACTOR,
+ G_IMPLEMENT_INTERFACE (CLUTTER_TYPE_CONTAINER,
+ clutter_container_iface_init));
+
+#define CHEESE_GRID_GET_PRIVATE(obj) \
+ (G_TYPE_INSTANCE_GET_PRIVATE ((obj), CHEESE_TYPE_GRID, \
+ CheeseGridPrivate))
+
+struct _CheeseGridPrivate
+{
+ ClutterUnit for_height, for_width;
+ ClutterUnit pref_width, pref_height;
+ ClutterUnit alloc_width, alloc_height;
+
+ gboolean absolute_origin_changed;
+ GHashTable *hash_table;
+ GList *list;
+
+ gboolean homogenous_rows;
+ gboolean homogenous_columns;
+ gboolean end_align;
+ ClutterUnit column_gap, row_gap;
+ gdouble valign, halign;
+
+ gboolean column_major;
+
+ gboolean first_of_batch;
+ ClutterUnit a_current_sum, a_wrap;
+ ClutterUnit max_extent_a;
+ ClutterUnit max_extent_b;
+};
+
+enum
+{
+ PROP_0,
+ PROP_HOMOGENOUS_ROWS,
+ PROP_HOMOGENOUS_COLUMNS,
+ PROP_ROW_GAP,
+ PROP_COLUMN_GAP,
+ PROP_VALIGN,
+ PROP_HALIGN,
+ PROP_END_ALIGN,
+ PROP_COLUMN_MAJOR,
+};
+
+struct _CheeseGridActorData
+{
+ gboolean xpos_set, ypos_set;
+ ClutterUnit xpos, ypos;
+ ClutterUnit pref_width, pref_height;
+};
+
+static void
+cheese_grid_class_init (CheeseGridClass *klass)
+{
+ GObjectClass *gobject_class = (GObjectClass *) klass;
+ ClutterActorClass *actor_class = (ClutterActorClass *) klass;
+
+ gobject_class->dispose = cheese_grid_dispose;
+ gobject_class->finalize = cheese_grid_finalize;
+
+ gobject_class->set_property = cheese_grid_set_property;
+ gobject_class->get_property = cheese_grid_get_property;
+
+ actor_class->paint = cheese_grid_paint;
+ actor_class->pick = cheese_grid_pick;
+ actor_class->get_preferred_width = cheese_grid_get_preferred_width;
+ actor_class->get_preferred_height = cheese_grid_get_preferred_height;
+ actor_class->allocate = cheese_grid_allocate;
+
+ g_type_class_add_private (klass, sizeof (CheeseGridPrivate));
+
+
+ g_object_class_install_property
+ (gobject_class,
+ PROP_ROW_GAP,
+ clutter_param_spec_unit ("row-gap",
+ "Row gap",
+ "gap between rows in the layout",
+ 0, CLUTTER_MAXUNIT,
+ 0,
+ G_PARAM_READWRITE|G_PARAM_CONSTRUCT));
+
+ g_object_class_install_property
+ (gobject_class,
+ PROP_COLUMN_GAP,
+ clutter_param_spec_unit ("column-gap",
+ "Column gap",
+ "gap between columns in the layout",
+ 0, CLUTTER_MAXUNIT,
+ 0,
+ G_PARAM_READWRITE|G_PARAM_CONSTRUCT));
+
+
+ g_object_class_install_property
+ (gobject_class,
+ PROP_HOMOGENOUS_ROWS,
+ g_param_spec_boolean ("homogenous-rows",
+ "homogenous rows",
+ "Should all rows have the same height?",
+ FALSE,
+ G_PARAM_READWRITE|G_PARAM_CONSTRUCT));
+
+ g_object_class_install_property
+ (gobject_class,
+ PROP_HOMOGENOUS_COLUMNS,
+ g_param_spec_boolean ("homogenous-columns",
+ "homogenous columns",
+ "Should all columns have the same height?",
+ FALSE,
+ G_PARAM_READWRITE|G_PARAM_CONSTRUCT));
+
+ g_object_class_install_property
+ (gobject_class,
+ PROP_COLUMN_MAJOR,
+ g_param_spec_boolean ("column-major",
+ "column-major",
+ "Do a column filling first instead of row filling first",
+ FALSE,
+ G_PARAM_READWRITE|G_PARAM_CONSTRUCT));
+
+ g_object_class_install_property
+ (gobject_class,
+ PROP_END_ALIGN,
+ g_param_spec_boolean ("end-align",
+ "end-align",
+ "Right/bottom aligned rows/columns",
+ FALSE,
+ G_PARAM_READWRITE|G_PARAM_CONSTRUCT));
+
+ g_object_class_install_property
+ (gobject_class,
+ PROP_VALIGN,
+ g_param_spec_double ("valign",
+ "Vertical align",
+ "Vertical alignment of items within cells",
+ 0.0, 1.0, 0.0,
+ G_PARAM_READWRITE|G_PARAM_CONSTRUCT));
+
+ g_object_class_install_property
+ (gobject_class,
+ PROP_HALIGN,
+ g_param_spec_double ("halign",
+ "Horizontal align",
+ "Horizontal alignment of items within cells",
+ 0.0, 1.0, 0.0,
+ G_PARAM_READWRITE|G_PARAM_CONSTRUCT));
+
+}
+
+static void
+clutter_container_iface_init (ClutterContainerIface *iface)
+{
+ iface->add = cheese_grid_real_add;
+ iface->remove = cheese_grid_real_remove;
+ iface->foreach = cheese_grid_real_foreach;
+ iface->raise = cheese_grid_real_raise;
+ iface->lower = cheese_grid_real_lower;
+ iface->sort_depth_order = cheese_grid_real_sort_depth_order;
+}
+
+static void
+cheese_grid_init (CheeseGrid *self)
+{
+ CheeseGridPrivate *priv;
+
+ self->priv = priv = CHEESE_GRID_GET_PRIVATE (self);
+
+ /* do not unref in the hashtable, the reference is for now kept by the list
+ * (double bookkeeping sucks)
+ */
+ priv->hash_table
+ = g_hash_table_new_full (g_direct_hash,
+ g_direct_equal,
+ NULL,
+ cheese_grid_free_actor_data);
+}
+
+static void
+cheese_grid_dispose (GObject *object)
+{
+ CheeseGrid *self = (CheeseGrid *) object;
+ CheeseGridPrivate *priv;
+
+ priv = self->priv;
+
+ /* Destroy all of the children. This will cause them to be removed
+ from the container and unparented */
+ clutter_container_foreach (CLUTTER_CONTAINER (object),
+ (ClutterCallback) clutter_actor_destroy,
+ NULL);
+
+ G_OBJECT_CLASS (cheese_grid_parent_class)->dispose (object);
+}
+
+static void
+cheese_grid_finalize (GObject *object)
+{
+ CheeseGrid *self = (CheeseGrid *) object;
+ CheeseGridPrivate *priv = self->priv;
+
+ g_hash_table_destroy (priv->hash_table);
+
+ G_OBJECT_CLASS (cheese_grid_parent_class)->finalize (object);
+}
+
+
+void
+cheese_grid_set_end_align (CheeseGrid *self,
+ gboolean value)
+{
+ CheeseGridPrivate *priv = CHEESE_GRID_GET_PRIVATE (self);
+ priv->end_align = value;
+ clutter_actor_queue_relayout (CLUTTER_ACTOR (self));
+}
+
+gboolean
+cheese_grid_get_end_align (CheeseGrid *self)
+{
+ CheeseGridPrivate *priv = CHEESE_GRID_GET_PRIVATE (self);
+ return priv->end_align;
+}
+
+void
+cheese_grid_set_homogenous_rows (CheeseGrid *self,
+ gboolean value)
+{
+ CheeseGridPrivate *priv = CHEESE_GRID_GET_PRIVATE (self);
+ priv->homogenous_rows = value;
+ clutter_actor_queue_relayout (CLUTTER_ACTOR (self));
+}
+
+gboolean
+cheese_grid_get_homogenous_rows (CheeseGrid *self)
+{
+ CheeseGridPrivate *priv = CHEESE_GRID_GET_PRIVATE (self);
+ return priv->homogenous_rows;
+}
+
+
+void
+cheese_grid_set_homogenous_columns (CheeseGrid *self,
+ gboolean value)
+{
+ CheeseGridPrivate *priv = CHEESE_GRID_GET_PRIVATE (self);
+ priv->homogenous_columns = value;
+ clutter_actor_queue_relayout (CLUTTER_ACTOR (self));
+}
+
+
+gboolean
+cheese_grid_get_homogenous_columns (CheeseGrid *self)
+{
+ CheeseGridPrivate *priv = CHEESE_GRID_GET_PRIVATE (self);
+ return priv->homogenous_columns;
+}
+
+
+void
+cheese_grid_set_column_major (CheeseGrid *self,
+ gboolean value)
+{
+ CheeseGridPrivate *priv = CHEESE_GRID_GET_PRIVATE (self);
+ priv->column_major = value;
+ clutter_actor_queue_relayout (CLUTTER_ACTOR (self));
+}
+
+gboolean
+cheese_grid_get_column_major (CheeseGrid *self)
+{
+ CheeseGridPrivate *priv = CHEESE_GRID_GET_PRIVATE (self);
+ return priv->column_major;
+}
+
+void
+cheese_grid_set_column_gap (CheeseGrid *self,
+ ClutterUnit value)
+{
+ CheeseGridPrivate *priv = CHEESE_GRID_GET_PRIVATE (self);
+ priv->column_gap = value;
+ clutter_actor_queue_relayout (CLUTTER_ACTOR (self));
+}
+
+ClutterUnit
+cheese_grid_get_column_gap (CheeseGrid *self)
+{
+ CheeseGridPrivate *priv = CHEESE_GRID_GET_PRIVATE (self);
+ return priv->column_gap;
+}
+
+
+
+void
+cheese_grid_set_row_gap (CheeseGrid *self,
+ ClutterUnit value)
+{
+ CheeseGridPrivate *priv = CHEESE_GRID_GET_PRIVATE (self);
+ priv->row_gap = value;
+ clutter_actor_queue_relayout (CLUTTER_ACTOR (self));
+}
+
+ClutterUnit
+cheese_grid_get_row_gap (CheeseGrid *self)
+{
+ CheeseGridPrivate *priv = CHEESE_GRID_GET_PRIVATE (self);
+ return priv->row_gap;
+}
+
+
+void
+cheese_grid_set_valign (CheeseGrid *self,
+ gdouble value)
+{
+ CheeseGridPrivate *priv = CHEESE_GRID_GET_PRIVATE (self);
+ priv->valign = value;
+ clutter_actor_queue_relayout (CLUTTER_ACTOR (self));
+}
+
+gdouble
+cheese_grid_get_valign (CheeseGrid *self)
+{
+ CheeseGridPrivate *priv = CHEESE_GRID_GET_PRIVATE (self);
+ return priv->valign;
+}
+
+
+
+void
+cheese_grid_set_halign (CheeseGrid *self,
+ gdouble value)
+
+{
+ CheeseGridPrivate *priv = CHEESE_GRID_GET_PRIVATE (self);
+ priv->halign = value;
+ clutter_actor_queue_relayout (CLUTTER_ACTOR (self));
+}
+
+gdouble
+cheese_grid_get_halign (CheeseGrid *self)
+{
+ CheeseGridPrivate *priv = CHEESE_GRID_GET_PRIVATE (self);
+ return priv->halign;
+}
+
+
+static void
+cheese_grid_set_property (GObject *object,
+ guint prop_id,
+ const GValue *value,
+ GParamSpec *pspec)
+{
+ CheeseGrid *grid = CHEESE_GRID (object);
+
+ CheeseGridPrivate *priv;
+
+ priv = CHEESE_GRID_GET_PRIVATE (object);
+
+ switch (prop_id)
+ {
+ case PROP_END_ALIGN:
+ cheese_grid_set_end_align (grid, g_value_get_boolean (value));
+ break;
+ case PROP_HOMOGENOUS_ROWS:
+ cheese_grid_set_homogenous_rows (grid, g_value_get_boolean (value));
+ break;
+ case PROP_HOMOGENOUS_COLUMNS:
+ cheese_grid_set_homogenous_columns (grid, g_value_get_boolean (value));
+ break;
+ case PROP_COLUMN_MAJOR:
+ cheese_grid_set_column_major (grid, g_value_get_boolean (value));
+ break;
+ case PROP_COLUMN_GAP:
+ cheese_grid_set_column_gap (grid, clutter_value_get_unit (value));
+ break;
+ case PROP_ROW_GAP:
+ cheese_grid_set_row_gap (grid, clutter_value_get_unit (value));
+ break;
+ case PROP_VALIGN:
+ cheese_grid_set_valign (grid, g_value_get_double (value));
+ break;
+ case PROP_HALIGN:
+ cheese_grid_set_halign (grid, g_value_get_double (value));
+ break;
+ default:
+ G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+ break;
+ }
+}
+
+static void
+cheese_grid_get_property (GObject *object,
+ guint prop_id,
+ GValue *value,
+ GParamSpec *pspec)
+{
+ CheeseGrid *grid = CHEESE_GRID (object);
+
+ CheeseGridPrivate *priv;
+
+ priv = CHEESE_GRID_GET_PRIVATE (object);
+
+ switch (prop_id)
+ {
+ case PROP_HOMOGENOUS_ROWS:
+ g_value_set_boolean (value, cheese_grid_get_homogenous_rows (grid));
+ break;
+ case PROP_HOMOGENOUS_COLUMNS:
+ g_value_set_boolean (value, cheese_grid_get_homogenous_columns (grid));
+ break;
+ case PROP_END_ALIGN:
+ g_value_set_boolean (value, cheese_grid_get_end_align (grid));
+ break;
+ case PROP_COLUMN_MAJOR:
+ g_value_set_boolean (value, cheese_grid_get_column_major (grid));
+ break;
+ case PROP_COLUMN_GAP:
+ clutter_value_set_unit (value, cheese_grid_get_column_gap (grid));
+ break;
+ case PROP_ROW_GAP:
+ clutter_value_set_unit (value, cheese_grid_get_row_gap (grid));
+ break;
+ case PROP_VALIGN:
+ g_value_set_double (value, cheese_grid_get_valign (grid));
+ break;
+ case PROP_HALIGN:
+ g_value_set_double (value, cheese_grid_get_halign (grid));
+ break;
+ default:
+ G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+ break;
+ }
+}
+
+
+static void
+cheese_grid_free_actor_data (gpointer data)
+{
+ g_slice_free (CheeseGridActorData, data);
+}
+
+ClutterActor *
+cheese_grid_new (void)
+{
+ ClutterActor *self = g_object_new (CHEESE_TYPE_GRID, NULL);
+
+ return self;
+}
+
+static void
+cheese_grid_real_add (ClutterContainer *container,
+ ClutterActor *actor)
+{
+ CheeseGridPrivate *priv;
+ CheeseGridActorData *data;
+
+ g_return_if_fail (CHEESE_IS_GRID (container));
+
+ priv = CHEESE_GRID (container)->priv;
+
+ g_object_ref (actor);
+
+ clutter_actor_set_parent (actor, CLUTTER_ACTOR (container));
+
+ data = g_slice_alloc0 (sizeof (CheeseGridActorData));
+
+ priv->list = g_list_append (priv->list, actor);
+ g_hash_table_insert (priv->hash_table, actor, data);
+
+ g_signal_emit_by_name (container, "actor-added", actor);
+
+ clutter_actor_queue_relayout (CLUTTER_ACTOR (container));
+
+ g_object_unref (actor);
+}
+
+static void
+cheese_grid_real_remove (ClutterContainer *container,
+ ClutterActor *actor)
+{
+ CheeseGrid *layout = CHEESE_GRID (container);
+ CheeseGridPrivate *priv = layout->priv;
+
+ g_object_ref (actor);
+
+ if (g_hash_table_remove (priv->hash_table, actor))
+ {
+ clutter_actor_unparent (actor);
+
+ clutter_actor_queue_relayout (CLUTTER_ACTOR (layout));
+
+ g_signal_emit_by_name (container, "actor-removed", actor);
+
+ if (CLUTTER_ACTOR_IS_VISIBLE (CLUTTER_ACTOR (layout)))
+ clutter_actor_queue_redraw (CLUTTER_ACTOR (layout));
+ }
+ priv->list = g_list_remove (priv->list, actor);
+
+ g_object_unref (actor);
+}
+
+static void
+cheese_grid_real_foreach (ClutterContainer *container,
+ ClutterCallback callback,
+ gpointer user_data)
+{
+ CheeseGrid *layout = CHEESE_GRID (container);
+ CheeseGridPrivate *priv = layout->priv;
+
+ g_list_foreach (priv->list, (GFunc) callback, user_data);
+}
+
+static void
+cheese_grid_real_raise (ClutterContainer *container,
+ ClutterActor *actor,
+ ClutterActor *sibling)
+{
+ /* STUB */
+}
+
+static void
+cheese_grid_real_lower (ClutterContainer *container,
+ ClutterActor *actor,
+ ClutterActor *sibling)
+{
+ /* STUB */
+}
+
+static void
+cheese_grid_real_sort_depth_order (ClutterContainer *container)
+{
+ /* STUB */
+}
+
+static void
+cheese_grid_paint (ClutterActor *actor)
+{
+ CheeseGrid *layout = (CheeseGrid *) actor;
+ CheeseGridPrivate *priv = layout->priv;
+ GList *child_item;
+
+ for (child_item = priv->list;
+ child_item != NULL;
+ child_item = child_item->next)
+ {
+ ClutterActor *child = child_item->data;
+
+ g_assert (child != NULL);
+
+ if (CLUTTER_ACTOR_IS_VISIBLE (child))
+ clutter_actor_paint (child);
+ }
+
+}
+
+static void
+cheese_grid_pick (ClutterActor *actor,
+ const ClutterColor *color)
+{
+ /* Chain up so we get a bounding box pained (if we are reactive) */
+ CLUTTER_ACTOR_CLASS (cheese_grid_parent_class)->pick (actor, color);
+
+ /* Just forward to the paint call which in turn will trigger
+ * the child actors also getting 'picked'.
+ */
+ if (CLUTTER_ACTOR_IS_VISIBLE (actor))
+ cheese_grid_paint (actor);
+}
+
+static void
+cheese_grid_get_preferred_width (ClutterActor *self,
+ ClutterUnit for_height,
+ ClutterUnit *min_width_p,
+ ClutterUnit *natural_width_p)
+{
+ CheeseGrid *layout = (CheeseGrid *) self;
+ CheeseGridPrivate *priv = layout->priv;
+ ClutterUnit natural_width;
+ ClutterActor *parent = clutter_actor_get_parent (self);
+
+// natural_width = clutter_actor_get_width (parent);
+ natural_width = CLUTTER_UNITS_FROM_INT (200);
+
+ if (min_width_p)
+ *min_width_p = natural_width;
+ if (natural_width_p)
+ *natural_width_p = natural_width;
+
+ priv->pref_width = natural_width;
+}
+
+static void
+cheese_grid_get_preferred_height (ClutterActor *self,
+ ClutterUnit for_width,
+ ClutterUnit *min_height_p,
+ ClutterUnit *natural_height_p)
+{
+ CheeseGrid *layout = (CheeseGrid *) self;
+ CheeseGridPrivate *priv = layout->priv;
+ ClutterUnit natural_height;
+ ClutterActor *parent = clutter_actor_get_parent (self);
+
+// natural_height = clutter_actor_get_height (parent);
+ natural_height = CLUTTER_UNITS_FROM_INT (200);
+
+ priv->for_width = for_width;
+ priv->pref_height = natural_height;
+
+ if (min_height_p)
+ *min_height_p = natural_height;
+ if (natural_height_p)
+ *natural_height_p = natural_height;
+}
+
+static ClutterUnit
+compute_row_height (GList *siblings,
+ ClutterUnit best_yet,
+ ClutterUnit current_a,
+ CheeseGridPrivate *priv)
+{
+ GList *l;
+
+ gboolean homogenous_a;
+ gboolean homogenous_b;
+ ClutterUnit gap;
+
+ if (priv->column_major)
+ {
+ homogenous_b = priv->homogenous_columns;
+ homogenous_a = priv->homogenous_rows;
+ gap = priv->row_gap;
+ }
+ else
+ {
+ homogenous_a = priv->homogenous_columns;
+ homogenous_b = priv->homogenous_rows;
+ gap = priv->column_gap;
+ }
+
+ for (l = siblings; l != NULL; l = l->next)
+ {
+ ClutterActor *child = l->data;
+ ClutterUnit natural_width, natural_height;
+
+ /* each child will get as much space as they require */
+ clutter_actor_get_preferred_size (CLUTTER_ACTOR (child),
+ NULL, NULL,
+ &natural_width, &natural_height);
+
+ if (priv->column_major)
+ {
+ ClutterUnit temp = natural_height;
+ natural_height = natural_width;
+ natural_width = temp;
+ }
+
+ /* if the primary axis is homogenous, each additional item is the same
+ * width */
+ if (homogenous_a)
+ natural_width = priv->max_extent_a;
+
+ if (natural_height > best_yet)
+ best_yet = natural_height;
+
+ /* if the child is overflowing, we wrap to next line */
+ if (current_a + natural_width + gap > priv->a_wrap)
+ {
+ return best_yet;
+ }
+ current_a += natural_width + gap;
+ }
+ return best_yet;
+}
+
+
+
+
+static ClutterUnit
+compute_row_start (GList *siblings,
+ ClutterUnit start_x,
+ CheeseGridPrivate *priv)
+{
+ ClutterUnit current_a = start_x;
+ GList *l;
+
+ gboolean homogenous_a;
+ gboolean homogenous_b;
+ ClutterUnit gap;
+
+ if (priv->column_major)
+ {
+ homogenous_b = priv->homogenous_columns;
+ homogenous_a = priv->homogenous_rows;
+ gap = priv->row_gap;
+ }
+ else
+ {
+ homogenous_a = priv->homogenous_columns;
+ homogenous_b = priv->homogenous_rows;
+ gap = priv->column_gap;
+ }
+
+ for (l = siblings; l != NULL; l = l->next)
+ {
+ ClutterActor *child = l->data;
+ ClutterUnit natural_width, natural_height;
+
+ /* each child will get as much space as they require */
+ clutter_actor_get_preferred_size (CLUTTER_ACTOR (child),
+ NULL, NULL,
+ &natural_width, &natural_height);
+
+
+ if (priv->column_major)
+ natural_width = natural_height;
+
+ /* if the primary axis is homogenous, each additional item is the same width */
+ if (homogenous_a)
+ natural_width = priv->max_extent_a;
+
+ /* if the child is overflowing, we wrap to next line */
+ if (current_a + natural_width + gap > priv->a_wrap)
+ {
+ if (current_a == start_x)
+ return start_x;
+ return (priv->a_wrap - current_a);
+ }
+ current_a += natural_width + gap;
+ }
+ return (priv->a_wrap - current_a);
+}
+
+static void
+cheese_grid_allocate (ClutterActor *self,
+ const ClutterActorBox *box,
+ gboolean absolute_origin_changed)
+{
+ CheeseGrid *layout = (CheeseGrid *) self;
+ CheeseGridPrivate *priv = layout->priv;
+
+ ClutterUnit current_a;
+ ClutterUnit current_b;
+ ClutterUnit next_b;
+ ClutterUnit agap;
+ ClutterUnit bgap;
+
+ gboolean homogenous_a;
+ gboolean homogenous_b;
+ gdouble aalign;
+ gdouble balign;
+
+ current_a = current_b = next_b = 0;
+
+ GList *iter;
+
+ /* chain up to set actor->allocation */
+ CLUTTER_ACTOR_CLASS (cheese_grid_parent_class)
+ ->allocate (self, box, absolute_origin_changed);
+
+ priv->alloc_width = box->x2 - box->x1;
+ priv->alloc_height = box->y2 - box->y1;
+ priv->absolute_origin_changed = absolute_origin_changed;
+
+ /* Make sure we have calculated the preferred size */
+ /* what does this do? */
+ clutter_actor_get_preferred_size (self, NULL, NULL, NULL, NULL);
+
+
+ if (priv->column_major)
+ {
+ priv->a_wrap = priv->alloc_height;
+ homogenous_b = priv->homogenous_columns;
+ homogenous_a = priv->homogenous_rows;
+ aalign = priv->valign;
+ balign = priv->halign;
+ agap = priv->row_gap;
+ bgap = priv->column_gap;
+ }
+ else
+ {
+ priv->a_wrap = priv->alloc_width;
+ homogenous_a = priv->homogenous_columns;
+ homogenous_b = priv->homogenous_rows;
+ aalign = priv->halign;
+ balign = priv->valign;
+ agap = priv->column_gap;
+ bgap = priv->row_gap;
+ }
+
+ priv->max_extent_a = 0;
+ priv->max_extent_b = 0;
+
+ priv->first_of_batch = TRUE;
+
+ if (homogenous_a ||
+ homogenous_b)
+ {
+ for (iter = priv->list; iter; iter = iter->next)
+ {
+ ClutterActor *child = iter->data;
+ ClutterUnit natural_width;
+ ClutterUnit natural_height;
+
+ /* each child will get as much space as they require */
+ clutter_actor_get_preferred_size (CLUTTER_ACTOR (child),
+ NULL, NULL,
+ &natural_width, &natural_height);
+ if (natural_width > priv->max_extent_a)
+ priv->max_extent_a = natural_width;
+ if (natural_height > priv->max_extent_b)
+ priv->max_extent_b = natural_width;
+ }
+ }
+
+ if (priv->column_major)
+ {
+ ClutterUnit temp = priv->max_extent_a;
+ priv->max_extent_a = priv->max_extent_b;
+ priv->max_extent_b = temp;
+ }
+
+ for (iter = priv->list; iter; iter=iter->next)
+ {
+ ClutterActor *child = iter->data;
+ ClutterUnit natural_a;
+ ClutterUnit natural_b;
+
+ /* each child will get as much space as they require */
+ clutter_actor_get_preferred_size (CLUTTER_ACTOR (child),
+ NULL, NULL,
+ &natural_a, &natural_b);
+
+ if (priv->column_major) /* swap axes around if column is major */
+ {
+ ClutterUnit temp = natural_a;
+ natural_a = natural_b;
+ natural_b = temp;
+ }
+
+ /* if the child is overflowing, we wrap to next line */
+ if (current_a + natural_a > priv->a_wrap ||
+ (homogenous_a && current_a + priv->max_extent_a > priv->a_wrap))
+ {
+ current_b = next_b + bgap;
+ current_a = 0;
+ next_b = current_b + bgap;
+ priv->first_of_batch = TRUE;
+ }
+
+ if (priv->end_align &&
+ priv->first_of_batch)
+ {
+ current_a = compute_row_start (iter, current_a, priv);
+ priv->first_of_batch = FALSE;
+ }
+
+ if (next_b-current_b < natural_b)
+ next_b = current_b + natural_b;
+
+ {
+ ClutterUnit row_height;
+ ClutterActorBox child_box;
+
+ if (homogenous_b)
+ {
+ row_height = priv->max_extent_b;
+ }
+ else
+ {
+ row_height = compute_row_height (iter, next_b-current_b,
+ current_a, priv);
+ }
+
+ if (homogenous_a)
+ {
+ child_box.x1 = current_a + (priv->max_extent_a-natural_a) * aalign;
+ child_box.x2 = child_box.x1 + natural_a;
+
+ }
+ else
+ {
+ child_box.x1 = current_a;
+ child_box.x2 = child_box.x1 + natural_a;
+ }
+
+ child_box.y1 = current_b + (row_height-natural_b) * balign;
+ child_box.y2 = child_box.y1 + natural_b;
+
+
+ if (priv->column_major)
+ {
+ ClutterUnit temp = child_box.x1;
+ child_box.x1 = child_box.y1;
+ child_box.y1 = temp;
+
+ temp = child_box.x2;
+ child_box.x2 = child_box.y2;
+ child_box.y2 = temp;
+ }
+
+ /* update the allocation */
+ clutter_actor_allocate (CLUTTER_ACTOR (child),
+ &child_box,
+ absolute_origin_changed);
+
+ if (homogenous_a)
+ {
+ current_a += priv->max_extent_a + agap;
+ }
+ else
+ {
+ current_a += natural_a + agap;
+ }
+ }
+ }
+}
diff --git a/src/cheese-grid.h b/src/cheese-grid.h
new file mode 100644
index 0000000..18d78dd
--- /dev/null
+++ b/src/cheese-grid.h
@@ -0,0 +1,99 @@
+/*
+ * Clutter.
+ *
+ * An OpenGL based 'interactive canvas' library.
+ *
+ * Authored By Matthew Allum <mallum@openedhand.com>
+ *
+ * Copyright (C) 2008 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 __CHEESE_GRID_H__
+#define __CHEESE_GRID_H__
+
+#include <clutter/clutter.h>
+
+G_BEGIN_DECLS
+
+#define CHEESE_TYPE_GRID (cheese_grid_get_type())
+#define CHEESE_GRID(obj) \
+ (G_TYPE_CHECK_INSTANCE_CAST ((obj), \
+ CHEESE_TYPE_GRID, \
+ CheeseGrid))
+#define CHEESE_GRID_CLASS(klass) \
+ (G_TYPE_CHECK_CLASS_CAST ((klass), \
+ CHEESE_TYPE_GRID, \
+ CheeseGridClass))
+#define CHEESE_IS_GRID(obj) \
+ (G_TYPE_CHECK_INSTANCE_TYPE ((obj), \
+ CHEESE_TYPE_GRID))
+#define CHEESE_IS_GRID_CLASS(klass) \
+ (G_TYPE_CHECK_CLASS_TYPE ((klass), \
+ CHEESE_TYPE_GRID))
+#define CHEESE_GRID_GET_CLASS(obj) \
+ (G_TYPE_INSTANCE_GET_CLASS ((obj), \
+ CHEESE_TYPE_GRID, \
+ CheeseGridClass))
+
+typedef struct _CheeseGrid CheeseGrid;
+typedef struct _CheeseGridClass CheeseGridClass;
+typedef struct _CheeseGridPrivate CheeseGridPrivate;
+
+struct _CheeseGridClass
+{
+ ClutterActorClass parent_class;
+};
+
+struct _CheeseGrid
+{
+ ClutterActor parent;
+
+ CheeseGridPrivate *priv;
+};
+
+GType cheese_grid_get_type (void) G_GNUC_CONST;
+
+ClutterActor *cheese_grid_new (void);
+void cheese_grid_set_end_align (CheeseGrid *self,
+ gboolean value);
+gboolean cheese_grid_get_end_align (CheeseGrid *self);
+void cheese_grid_set_homogenous_rows (CheeseGrid *self,
+ gboolean value);
+gboolean cheese_grid_get_homogenous_rows (CheeseGrid *self);
+void cheese_grid_set_homogenous_columns (CheeseGrid *self,
+ gboolean value);
+gboolean cheese_grid_get_homogenous_columns (CheeseGrid *self);
+void cheese_grid_set_column_major (CheeseGrid *self,
+ gboolean value);
+gboolean cheese_grid_get_column_major (CheeseGrid *self);
+void cheese_grid_set_row_gap (CheeseGrid *self,
+ ClutterUnit value);
+ClutterUnit cheese_grid_get_row_gap (CheeseGrid *self);
+void cheese_grid_set_column_gap (CheeseGrid *self,
+ ClutterUnit value);
+ClutterUnit cheese_grid_get_column_gap (CheeseGrid *self);
+void cheese_grid_set_valign (CheeseGrid *self,
+ gdouble value);
+gdouble cheese_grid_get_valign (CheeseGrid *self);
+void cheese_grid_set_halign (CheeseGrid *self,
+ gdouble value);
+gdouble cheese_grid_get_halign (CheeseGrid *self);
+
+G_END_DECLS
+
+#endif /* __CHEESE_GRID_H__ */
diff --git a/src/cheese-stage.c b/src/cheese-stage.c
index 7d1b067..2a6f6e4 100644
--- a/src/cheese-stage.c
+++ b/src/cheese-stage.c
@@ -1,5 +1,4 @@
-/*
- * GStreamer
+/* GStreamer
* Copyright (C) 2009 Filippo Argiolas <filippo.argiolas@gmail.com>
*
* This library is free software; you can redistribute it and/or
@@ -19,8 +18,12 @@
*/
#include "cheese-texture.h"
+#include "cheese-grid.h"
+#include <gtk/gtk.h>
#include <clutter/clutter.h>
+#include <clutter/x11/clutter-x11.h>
+#include <clutter-gtk/clutter-gtk.h>
#include <gst/gst.h>
#include <gst/interfaces/xoverlay.h>
@@ -54,6 +57,8 @@ create_window (GstBus * bus, GstMessage * message, gpointer data)
g_message ("adding actor: %d win: %ld", count, win);
gst_x_overlay_set_xwindow_id (GST_X_OVERLAY (GST_MESSAGE_SRC (message)),
win);
+ Display *disp = clutter_x11_get_default_display ();
+ XMapWindow (disp, win);
count++;
}
@@ -63,6 +68,7 @@ create_window (GstBus * bus, GstMessage * message, gpointer data)
return GST_BUS_DROP;
}
+#if 0
static gboolean
on_enter_animate (ClutterActor *actor, ClutterEvent *event, gpointer data)
{
@@ -71,10 +77,12 @@ on_enter_animate (ClutterActor *actor, ClutterEvent *event, gpointer data)
previous_animation = clutter_actor_get_animation (actor);
if (previous_animation)
clutter_animation_completed (previous_animation);
+
+ clutter_actor_raise_top (actor);
- clutter_actor_animate (actor, CLUTTER_LINEAR, 250,
- "scale-x", 0.99,
- "scale-y", 0.99,
+ clutter_actor_animate (actor, CLUTTER_LINEAR, 150,
+ "scale-x", 1.1,
+ "scale-y", 1.1,
NULL);
return TRUE;
}
@@ -88,12 +96,59 @@ on_leave_animate (ClutterActor *actor, ClutterEvent *event, gpointer data)
if (previous_animation)
clutter_animation_completed (previous_animation);
- clutter_actor_animate (actor, CLUTTER_LINEAR, 250,
- "scale-x", 0.95,
- "scale-y", 0.95,
+ clutter_actor_animate (actor, CLUTTER_LINEAR, 500,
+ "scale-x", 1.0,
+ "scale-y", 1.0,
NULL);
return TRUE;
}
+#endif
+
+static gboolean
+on_window_configure (GtkWidget *window, GdkEventConfigure *ev, ClutterActor *layout)
+{
+ clutter_actor_set_size(layout,
+ CLUTTER_UNITS_FROM_INT (ev->width),
+ CLUTTER_UNITS_FROM_INT (ev->height));
+
+ return FALSE;
+}
+
+static gboolean
+on_button_animate (ClutterActor *actor, ClutterEvent *event, gpointer data)
+{
+ /* still doesn't work with the layout... (not that I tried to make in work) */
+ ClutterActor *stage = clutter_actor_get_stage (actor);
+
+ gint stagew, stageh, w, h;
+
+ ClutterAnimation *previous_animation;
+
+ previous_animation = clutter_actor_get_animation (actor);
+ if (previous_animation)
+ clutter_animation_completed (previous_animation);
+
+ stagew = clutter_actor_get_width (stage);
+ stageh = clutter_actor_get_height (stage);
+ w = clutter_actor_get_width (actor);
+ h = clutter_actor_get_height (actor);
+
+ if ((w > W) | (h > H)) {
+ clutter_actor_animate (actor, CLUTTER_LINEAR, 250,
+ "width", W,
+ "height", H,
+ NULL);
+ }
+ else {
+ clutter_actor_animate (actor, CLUTTER_LINEAR, 250,
+ "width", stagew,
+ "height", stageh,
+ "x", 0,
+ "y", 0,
+ NULL);
+ }
+ return TRUE;
+}
int
main (int argc, char *argv[])
@@ -103,6 +158,7 @@ main (int argc, char *argv[])
GstElement *srcbin;
GstElement *tee;
+ GstElement *fx[N_ACTORS];
GstElement *queue[N_ACTORS], *sink[N_ACTORS];
/*
GstElement *upload[N_ACTORS];
@@ -118,46 +174,68 @@ main (int argc, char *argv[])
ClutterActor *stage;
ClutterColor color;
ClutterActor *actor[N_ACTORS];
+ ClutterActor *layout;
+
+ GtkWidget *window, *clutter;
+
+ if (gtk_clutter_init (&argc, &argv) != CLUTTER_INIT_SUCCESS)
+ g_error ("Unable to initialize GtkClutter");
- clutter_init (&argc, &argv);
gst_init (&argc, &argv);
- stage = clutter_stage_get_default ();
+ window = gtk_window_new (GTK_WINDOW_TOPLEVEL);
+ g_signal_connect (window, "destroy",
+ G_CALLBACK (gtk_main_quit), NULL);
+
+ clutter = gtk_clutter_embed_new ();
- clutter_actor_set_size (CLUTTER_ACTOR (stage),
- W * COLS + (COLS - 1), H * ROWS + (ROWS - 1));
+ gtk_container_add (GTK_CONTAINER (window), clutter);
+ stage = gtk_clutter_embed_get_stage (GTK_CLUTTER_EMBED (clutter));
- clutter_color_from_string (&color, "DarkSlateGrey");
+ clutter_color_from_string (&color, "DarkSlateBlue");
clutter_stage_set_color (CLUTTER_STAGE (stage), &color);
-// clutter_stage_set_user_resizable (stage, TRUE);
+ layout = g_object_new (CHEESE_TYPE_GRID,
+ "valign", 0.5,
+ "halign", 0.5,
+ "row-gap", CLUTTER_UNITS_FROM_INT(5),
+ "column-gap", CLUTTER_UNITS_FROM_INT(5),
+ NULL);
+
+// clutter_actor_set_size (layout, 600, 200);
+
+ clutter_container_add_actor (CLUTTER_CONTAINER (stage), layout);
+
+ g_signal_connect (window, "configure-event",
+ G_CALLBACK (on_window_configure), layout);
+
for (i = 0; i < N_ACTORS; i++) {
actor[i] = cheese_texture_new ();
- clutter_actor_set_scale_with_gravity (actor[i], 0.95, 0.95,
+ clutter_actor_set_scale_with_gravity (actor[i], 1.0, 1.0,
CLUTTER_GRAVITY_CENTER);
- clutter_container_add_actor (CLUTTER_CONTAINER (stage), actor[i]);
- clutter_actor_set_position (actor[i], xpos, ypos);
+ clutter_container_add_actor (CLUTTER_CONTAINER (layout), actor[i]);
+// clutter_actor_set_position (actor[i], xpos, ypos);
clutter_actor_set_reactive (actor[i], TRUE);
- g_signal_connect (actor[i], "enter-event", G_CALLBACK (on_enter_animate), NULL);
- g_signal_connect (actor[i], "leave-event", G_CALLBACK (on_leave_animate), NULL);
+ g_signal_connect (actor[i], "button-press-event", G_CALLBACK (on_button_animate), NULL);
+// g_signal_connect (actor[i], "enter-event", G_CALLBACK (on_enter_animate), NULL);
+// g_signal_connect (actor[i], "leave-event", G_CALLBACK (on_leave_animate), NULL);
if (xpos > (COLS - 1) * W) {
xpos = 0;
ypos += H + 1;
} else
xpos += W + 1;
- clutter_actor_show (actor[i]);
+// clutter_actor_show (actor[i]);
}
-/*
- desc = g_strdup_printf ("v4l2src ! "
- "video/x-raw-yuv, width=640, height=480, framerate=30/1 ! "
- "videoscale ! videorate ! "
- "video/x-raw-yuv, width=%d, height=%d, framerate=15/1 ! "
+/* desc = g_strdup_printf ("v4l2src ! "
+ "video/x-raw-rgb, width=320, height=240, framerate=30/1 ! "
+ "videoscale ! "
+ "video/x-raw-rgb, width=%d, height=%d ! ffmpegcolorspace ! "
"identity", W, H);
*/
-
desc = g_strdup_printf ("videotestsrc ! "
"video/x-raw-rgb, width=%d, height=%d, framerate=10/1 ! ffmpegcolorspace ! identity", W, H);
+
pipeline = GST_PIPELINE (gst_pipeline_new (NULL));
srcbin = gst_parse_bin_from_description (desc, TRUE, NULL);
@@ -167,17 +245,31 @@ main (int argc, char *argv[])
tee = gst_element_factory_make ("tee", NULL);
gst_bin_add_many (GST_BIN (pipeline), srcbin, tee, NULL);
-
+
+ fx[0] = gst_parse_bin_from_description ("identity", TRUE, NULL);
+// fx[1] = gst_parse_bin_from_description ("ffmpegcolorspace ! videobalance saturation=0 ! ffmpegcolorspace", TRUE, NULL);
+ fx[1] = gst_parse_bin_from_description ("identity", TRUE, NULL);
+// fx[2] = gst_parse_bin_from_description ("ffmpegcolorspace ! videoflip method=4 ! ffmpegcolorspace", TRUE, NULL);
+ fx[2] = gst_parse_bin_from_description ("identity", TRUE, NULL);
+ fx[3] = gst_parse_bin_from_description ("dicetv square-bits=3", TRUE, NULL);
+ fx[4] = gst_parse_bin_from_description ("warptv", TRUE, NULL);
+ fx[5] = gst_parse_bin_from_description ("shagadelictv", TRUE, NULL);
+ fx[6] = gst_parse_bin_from_description ("vertigotv", TRUE, NULL);
+// fx[7] = gst_parse_bin_from_description ("ffmpegcolorspace ! videobalance saturation=1.5 hue=-0.5 ! ffmpegcolorspace", TRUE, NULL);
+ fx[7] = gst_parse_bin_from_description ("identity", TRUE, NULL);
+// fx[8] = gst_parse_bin_from_description ("ffmpegcolorspace ! videoflip method=5 ! ffmpegcolorspace", TRUE, NULL);
+ fx[8] = gst_parse_bin_from_description ("identity", TRUE, NULL);
+
for (i = 0; i < N_ACTORS; i++) {
queue[i] = gst_element_factory_make ("queue", NULL);
- sink[i] = gst_element_factory_make ("ximagesink", NULL);
- gst_bin_add_many (GST_BIN (pipeline), queue[i], sink[i], NULL);
+ sink[i] = gst_element_factory_make ("glimagesink", NULL);
+ gst_bin_add_many (GST_BIN (pipeline), queue[i], fx[i], sink[i], NULL);
}
gst_element_link_many (srcbin, tee, NULL);
for (i = 0; i < N_ACTORS; i++) {
- ok |= gst_element_link_many (tee, queue[i], sink[i], NULL);
+ ok |= gst_element_link_many (tee, queue[i], fx[i], sink[i], NULL);
}
if (!ok)
@@ -189,9 +281,10 @@ main (int argc, char *argv[])
gst_element_set_state (GST_ELEMENT (pipeline), GST_STATE_PLAYING);
+ gtk_widget_show_all (window);
clutter_actor_show_all (stage);
- clutter_main ();
+ gtk_main ();
gst_element_set_state (GST_ELEMENT (pipeline), GST_STATE_NULL);
g_object_unref (pipeline);
diff --git a/src/cheese-texture.c b/src/cheese-texture.c
index bdf9671..e61d26f 100644
--- a/src/cheese-texture.c
+++ b/src/cheese-texture.c
@@ -1,5 +1,4 @@
/*
- * GStreamer
* Copyright (C) 2009 Filippo Argiolas <filippo.argiolas@gmail.com>
*
* This library is free software; you can redistribute it and/or
@@ -21,6 +20,7 @@
#include "cheese-texture.h"
#include <X11/Xlib.h>
+#include <X11/extensions/Xdamage.h>
#include <X11/extensions/Xcomposite.h>
#include <X11/extensions/Xfixes.h>
#include <X11/extensions/shape.h>
@@ -31,6 +31,8 @@
#include <gst/gst.h>
#include <gst/interfaces/xoverlay.h>
+#include <gdk/gdkx.h>
+
G_DEFINE_TYPE (CheeseTexture, cheese_texture, CLUTTER_GLX_TYPE_TEXTURE_PIXMAP);
#define CHEESE_TEXTURE_GET_PRIVATE(o) \
@@ -40,41 +42,90 @@ struct _CheeseTexturePrivate
{
/* stuff */
Window parent;
+ GdkWindow *gdk_window;
+ Damage damage;
+ Drawable damage_drawable;
};
-static ClutterX11FilterReturn
-on_x_event_filter (XEvent * xev, ClutterEvent * cev, gpointer data);
+static int _damage_event_base = 0;
-static ClutterX11FilterReturn
-on_x_event_filter (XEvent * xev, ClutterEvent * cev, gpointer data)
+static GdkFilterReturn
+gdk_filter (GdkXEvent *xevent, GdkEvent *event, gpointer data)
{
+ XEvent *xev = (XEvent *) xevent;
CheeseTexture *self = CHEESE_TEXTURE (data);
CheeseTexturePrivate *priv = self->priv = CHEESE_TEXTURE_GET_PRIVATE (self);
-
- Window window;
-
- if (xev->xany.window != priv->parent)
- return CLUTTER_X11_FILTER_CONTINUE;
-
- g_object_get (self, "window", &window, NULL);
- if (window == None)
- return CLUTTER_X11_FILTER_CONTINUE;
-
- switch (xev->type) {
- case MapNotify:
- g_message ("stage mapped %ld", xev->xmap.window);
- XMapWindow (xev->xmap.display, window);
- XSync (xev->xmap.display, FALSE);
- break;
- case UnmapNotify:
- g_message ("stage unmapped %ld", xev->xmap.window);
- XUnmapWindow (xev->xmap.display, window);
- XSync (xev->xmap.display, FALSE);
- break;
- default:
- break;
+ Display *dpy;
+ Window win, toplevel;
+
+ dpy = clutter_x11_get_default_display();
+ win = GDK_WINDOW_XID (priv->gdk_window);
+ toplevel = GDK_WINDOW_XID (gdk_window_get_toplevel (priv->gdk_window));
+
+ if (xev->xany.window == win) {
+ switch (xev->type) {
+ case ConfigureNotify:
+ case MapNotify:
+ clutter_x11_texture_pixmap_sync_window (CLUTTER_X11_TEXTURE_PIXMAP (self));
+ break;
+ case UnmapNotify:
+ break;
+ }
+ 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->damage_drawable)
+ return GDK_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 (CLUTTER_X11_TEXTURE_PIXMAP (self),
+ r_damage[i].x,
+ r_damage[i].y,
+ r_damage[i].width,
+ r_damage[i].height);
+ XFree (r_damage);
+ XSync (dpy, FALSE);
+ }
+
+ XFixesDestroyRegion (dpy, parts);
+ return GDK_FILTER_REMOVE;
+ }
+ }
+ else if (xev->xany.window == toplevel) {
+ switch (xev->type) {
+ case ConfigureNotify:
+ case MapNotify:
+ gdk_window_show_unraised (priv->gdk_window);
+ break;
+ case UnmapNotify:
+ gdk_window_hide (priv->gdk_window);
+ break;
+ }
}
- return CLUTTER_X11_FILTER_CONTINUE;
+
+ return GDK_FILTER_CONTINUE;
}
static void
@@ -85,8 +136,6 @@ cheese_texture_dispose (GObject *object)
g_object_get (self, "window", &window, NULL);
- clutter_x11_remove_filter (on_x_event_filter, NULL);
-
G_OBJECT_CLASS (cheese_texture_parent_class)->dispose (object);
if (window != None)
@@ -94,14 +143,50 @@ cheese_texture_dispose (GObject *object)
}
static void
+on_stage_realize (ClutterActor *stage, ClutterActor *actor)
+{
+ Window stage_win, window;
+ Display *disp;
+ CheeseTexture *self = CHEESE_TEXTURE (actor);
+ CheeseTexturePrivate *priv = self->priv = CHEESE_TEXTURE_GET_PRIVATE (self);
+
+ stage_win = clutter_x11_get_stage_window (stage);
+
+ if (gdk_window_get_parent (priv->gdk_window) != gdk_window_lookup (stage_win))
+ {
+// g_message ("reparent!");
+ gdk_window_reparent (priv->gdk_window, gdk_window_lookup (stage_win), 0, 0);
+ priv->parent = stage_win;
+ gdk_window_show_unraised (priv->gdk_window);
+ }
+}
+
+static void
+cheese_texture_realize (ClutterActor *actor)
+{
+ Window stage_win, window;
+ Display *disp;
+ CheeseTexture *self = CHEESE_TEXTURE (actor);
+ CheeseTexturePrivate *priv = self->priv = CHEESE_TEXTURE_GET_PRIVATE (self);
+ ClutterActor *stage = clutter_actor_get_stage (actor);
+
+ disp = clutter_x11_get_default_display ();
+
+ CLUTTER_ACTOR_CLASS (cheese_texture_parent_class)->realize (actor);
+
+ g_signal_connect (G_OBJECT (stage), "realize", G_CALLBACK (on_stage_realize), actor);
+}
+
+static void
cheese_texture_class_init (CheeseTextureClass * klass)
{
GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
-/* ClutterActorClass *actor_class = CLUTTER_ACTOR_CLASS (klass); */
+ ClutterActorClass *actor_class = CLUTTER_ACTOR_CLASS (klass);
g_type_class_add_private (klass, sizeof (CheeseTexturePrivate));
gobject_class->dispose = cheese_texture_dispose;
+ actor_class->realize = cheese_texture_realize;
}
static void
@@ -112,30 +197,73 @@ cheese_texture_init (CheeseTexture * self)
Window win;
Window stage_win;
+ ClutterActor *stage_default;
ClutterActor *stage;
- disp = clutter_x11_get_default_display ();
+ GdkWindow *window;
+ GdkWindowAttr attributes;
+ int attributes_mask;
- stage = clutter_stage_get_default ();
- stage_win = clutter_x11_get_stage_window (CLUTTER_STAGE (stage));
+ const XVisualInfo *xvinfo;
+ GdkVisual *visual;
+ GdkColormap *colormap;
+
+ stage_default = clutter_stage_get_default ();
+ stage_win = clutter_x11_get_stage_window (CLUTTER_STAGE (stage_default));
+ disp = clutter_x11_get_default_display ();
- win = XCreateSimpleWindow (disp, stage_win,
- 0, 0, DEFAULT_W, DEFAULT_H, 0, 0,
- BlackPixel (disp, DefaultScreen (disp)));
+ xvinfo = clutter_x11_get_stage_visual (CLUTTER_STAGE (stage_default));
+ visual = gdk_x11_screen_lookup_visual (gdk_screen_get_default (),
+ xvinfo->visualid);
+ colormap = gdk_colormap_new (visual, FALSE);
+
+ attributes.window_type = GDK_WINDOW_CHILD;
+ attributes.x = 0;
+ attributes.y = 0;
+ attributes.width = DEFAULT_W;
+ attributes.height = DEFAULT_H;
+ attributes.wclass = GDK_INPUT_OUTPUT;
+ attributes.visual = visual;
+ attributes.colormap = colormap;
+ attributes.override_redirect = TRUE;
+
+ attributes.event_mask = GDK_EXPOSURE_MASK | GDK_STRUCTURE_MASK;
+
+ attributes_mask = GDK_WA_X | GDK_WA_Y | GDK_WA_VISUAL | GDK_WA_COLORMAP | GDK_WA_NOREDIR;
+
+ window = gdk_window_new (gdk_window_foreign_new (stage_win),
+ &attributes,
+ attributes_mask);
+ priv->gdk_window = window;
- /* Allow input passthrough: don't steal clutter's input */
XserverRegion region = XFixesCreateRegion (disp, NULL, 0);
- XFixesSetWindowShapeRegion (disp, win, ShapeBounding, 0, 0, 0);
- XFixesSetWindowShapeRegion (disp, win, ShapeInput, 0, 0, region);
+ XFixesSetWindowShapeRegion (disp, GDK_WINDOW_XID (window), ShapeBounding, 0, 0, 0);
+ XFixesSetWindowShapeRegion (disp, GDK_WINDOW_XID (window), ShapeInput, 0, 0, region);
XFixesDestroyRegion (disp, region);
- priv->parent = stage_win;
+ gdk_window_set_composited (window, TRUE);
+ gdk_window_show_unraised (window);
+
+ int damage_error;
+
+ if (!XDamageQueryExtension (disp,
+ &_damage_event_base, &damage_error))
+ {
+ g_warning ("No Damage extension");
+ }
+// else g_message ("event base: %d", _damage_event_base);
+
+ priv->damage_drawable = GDK_WINDOW_XID (window);
+ priv->damage = XDamageCreate (disp,
+ priv->damage_drawable,
+ XDamageReportNonEmpty);
- XCompositeRedirectWindow (disp, win, CompositeRedirectManual);
+ XSync (disp, FALSE);
- g_object_set (self, "window", win, "automatic-updates", TRUE, NULL);
+ gdk_window_add_filter (NULL, gdk_filter, self);
+// g_message ("toplevel is %d", GDK_WINDOW_XID (gdk_window_get_toplevel (window)));
- clutter_x11_add_filter (on_x_event_filter, self);
+ g_object_set (self, "window", GDK_WINDOW_XID (window), NULL);
}
ClutterActor *