banshee r4948 - in trunk/banshee: . build/m4/banshee libbanshee src/Backends/Banshee.GStreamer/Banshee.GStreamer src/Core/Banshee.Services src/Core/Banshee.Services/Banshee.MediaEngine src/Core/Banshee.Services/Banshee.ServiceStack src/Core/Banshee.ThickClient src/Core/Banshee.ThickClient/Banshee.Gui src/Extensions/Banshee.NowPlaying src/Extensions/Banshee.NowPlaying/Banshee.NowPlaying



Author: abock
Date: Sat Jan 24 23:05:00 2009
New Revision: 4948
URL: http://svn.gnome.org/viewvc/banshee?rev=4948&view=rev

Log:
2009-01-24  Aaron Bockover  <abock gnome org>

    First hacky pass at Clutter integration; nothing to see, and I probably
    broke some things. trunk is going to be sketchy for a bit...

    * src/Core/Banshee.Services/Banshee.MediaEngine/VideoDisplayContextType.cs:
    Enum of context types pipelines might support for video (e.g. xoverlay,
    clutter, cairo, etc.)

    * src/Extensions/Banshee.NowPlaying/Banshee.NowPlaying/VideoDisplay.cs:
    * src/Extensions/Banshee.NowPlaying/Banshee.NowPlaying/NowPlayingContents.cs:
    * src/Extensions/Banshee.NowPlaying/Banshee.NowPlaying/IVideoDisplay.cs:
    * src/Extensions/Banshee.NowPlaying/Banshee.NowPlaying/XOverlayVideoDisplay.cs:
    Updated to support the video context API changes in the player engine

    * src/Core/Banshee.ThickClient/Banshee.Gui/GtkBaseClient.cs: Temporary
    clutter initialization, to be moved into the clutter extension

    * src/Core/Banshee.Services/Banshee.ServiceStack/ServiceManager.cs:
    Fix a small string.format bug

    * src/Core/Banshee.Services/Banshee.MediaEngine/PlayerEngine.cs:
    * src/Core/Banshee.Services/Banshee.MediaEngine/PlayerEngineService.cs:
    Instead of a simple SupportsVideo bool, replace with
    VideoDisplayContextType, and change the VideoWindow property to
    VideoDisplayContext with both a getter and setter, the meaning of which
    depends on VideoDisplayContextType

    * src/Core/Banshee.Services/Banshee.MediaEngine/NullPlayerEngine.cs:
    * src/Backends/Banshee.GStreamer/Banshee.GStreamer/PlayerEngine.cs:
    Implement changes to API above

    * libbanshee/banshee-player-video.c: Implement inital clutter support,
    and the backend implementation for the new video context API above,
    providing both xoverlay (GDK) and clutter contexts

    * libbanshee/clutter-gst-shaders.h:
    * libbanshee/clutter-gst-video-sink.h:
    * libbanshee/clutter-gst-video-sink.c: Clutter GStreamer integration
    from the clutter-gst package; currently I don't want to take the dep
    as changes might need to be made

    * libbanshee/banshee-player-private.h: Add the clutter texture if we
    are building with clutter support

    * build/m4/banshee/libbanshee.m4: Check for clutter (optional)

    * configure.ac: Clean up the configure summary, make it nicer and more
    organized

    * build/m4/banshee/dap-karma.m4: Small fix



Added:
   trunk/banshee/libbanshee/clutter-gst-shaders.h
   trunk/banshee/libbanshee/clutter-gst-video-sink.c
   trunk/banshee/libbanshee/clutter-gst-video-sink.h
   trunk/banshee/src/Core/Banshee.Services/Banshee.MediaEngine/VideoDisplayContextType.cs
   trunk/banshee/src/Core/Banshee.ThickClient/Banshee.ThickClient.dll.config
   trunk/banshee/src/Extensions/Banshee.NowPlaying/Banshee.NowPlaying.dll.config
   trunk/banshee/src/Extensions/Banshee.NowPlaying/Banshee.NowPlaying/IVideoDisplay.cs
Modified:
   trunk/banshee/ChangeLog
   trunk/banshee/build/m4/banshee/dap-karma.m4
   trunk/banshee/build/m4/banshee/libbanshee.m4
   trunk/banshee/configure.ac
   trunk/banshee/libbanshee/Makefile.am
   trunk/banshee/libbanshee/banshee-player-private.h
   trunk/banshee/libbanshee/banshee-player-video.c
   trunk/banshee/libbanshee/libbanshee.cproj
   trunk/banshee/src/Backends/Banshee.GStreamer/Banshee.GStreamer/PlayerEngine.cs
   trunk/banshee/src/Core/Banshee.Services/Banshee.MediaEngine/NullPlayerEngine.cs
   trunk/banshee/src/Core/Banshee.Services/Banshee.MediaEngine/PlayerEngine.cs
   trunk/banshee/src/Core/Banshee.Services/Banshee.MediaEngine/PlayerEngineService.cs
   trunk/banshee/src/Core/Banshee.Services/Banshee.ServiceStack/ServiceManager.cs
   trunk/banshee/src/Core/Banshee.Services/Makefile.am
   trunk/banshee/src/Core/Banshee.ThickClient/Banshee.Gui/GtkBaseClient.cs
   trunk/banshee/src/Core/Banshee.ThickClient/Makefile.am
   trunk/banshee/src/Extensions/Banshee.NowPlaying/Banshee.NowPlaying/NowPlayingContents.cs
   trunk/banshee/src/Extensions/Banshee.NowPlaying/Banshee.NowPlaying/VideoDisplay.cs
   trunk/banshee/src/Extensions/Banshee.NowPlaying/Banshee.NowPlaying/XOverlayVideoDisplay.cs
   trunk/banshee/src/Extensions/Banshee.NowPlaying/Makefile.am

Modified: trunk/banshee/build/m4/banshee/dap-karma.m4
==============================================================================
--- trunk/banshee/build/m4/banshee/dap-karma.m4	(original)
+++ trunk/banshee/build/m4/banshee/dap-karma.m4	Sat Jan 24 23:05:00 2009
@@ -11,8 +11,6 @@
 		karma-sharp >= $KARMASHARP_REQUIRED,
 		enable_karmasharp="$enable_karmasharp", enable_karmasharp=no)
 
-	AC_MSG_RESULT([$enable_karmasharp])
-
 	if test "x$enable_karmasharp" = "xyes"; then
 		KARMASHARP_ASSEMBLIES="`$PKG_CONFIG --variable=Libraries karma-sharp`"
 		AC_SUBST(KARMASHARP_ASSEMBLIES)

Modified: trunk/banshee/build/m4/banshee/libbanshee.m4
==============================================================================
--- trunk/banshee/build/m4/banshee/libbanshee.m4	(original)
+++ trunk/banshee/build/m4/banshee/libbanshee.m4	Sat Jan 24 23:05:00 2009
@@ -25,8 +25,19 @@
 		PKG_CHECK_MODULES(GTK, gtk+-2.0 >= 2.8)
 	fi
 
+	PKG_CHECK_MODULES(CLUTTER,
+		clutter-0.8 >= 0.8.6,
+		enable_clutter=yes, enable_clutter=no)
+
+	if test "x$enable_clutter" = "xyes"; then
+		SHAMROCK_CONCAT_MODULE(LIBBANSHEE, CLUTTER)
+		AC_DEFINE(HAVE_CLUTTER, 1, 
+			[Define if the video sink should be Clutter])
+	fi
+
 	AM_CONDITIONAL(HAVE_X11, test "x$GRAPHICS_SUBSYSTEM" = "xX11")
 	AM_CONDITIONAL(HAVE_QUARTZ, test "x$GRAPHICS_SUBSYSTEM" = "xQuartz")
+	AM_CONDITIONAL(HAVE_CLUTTER, test "x$enable_clutter" = "xyes")
 
 	AC_SUBST(GRAPHICS_SUBSYSTEM)
 	AC_SUBST(LIBBANSHEE_CFLAGS)

Modified: trunk/banshee/configure.ac
==============================================================================
--- trunk/banshee/configure.ac	(original)
+++ trunk/banshee/configure.ac	Sat Jan 24 23:05:00 2009
@@ -250,9 +250,11 @@
 src/Extensions/Banshee.RemoteAudio/Makefile
 ])
 
-echo "
+cat <<EOF
+
 ${PACKAGE}-${VERSION}
 
+  Build Environment
     Install Prefix:    ${prefix}
     Datadir:           ${expanded_datadir}
     Libdir:            ${expanded_libdir}
@@ -261,36 +263,44 @@
     Mono C# Compiler:  ${MCS} ${GMCS_FLAGS}
     Mono Runtime:      ${MONO}
 
-    Digital Audio Player (DAP) Support:
-      Mass Storage:    yes
-      MTP:             ${enable_libmtp}
-      iPod:            ${enable_ipodsharp}
-      Karma:           ${enable_karmasharp}
+  Video/Graphics:
+    Graphics System:   ${GRAPHICS_SUBSYSTEM}
+    X11 Video:         ${have_xvidmode}
+    Clutter:           ${enable_clutter} (experimental)
+
+  Operating System/Desktop Environment:
+    GNOME Support:     ${enable_gnome}
+    OSX Support:       ${enable_osx}
+
+  Digital Audio Player (DAP) Support:
+    Mass Storage:      yes
+    MTP:               ${enable_libmtp}
+    iPod:              ${enable_ipodsharp}
+    Karma:             ${enable_karmasharp}
 
+  Extra Features:
     DAAP Support:      ${enable_daap}
     Podcast Support:   ${enable_podcast}
     Boo Scripting:     ${enable_boo}
-    X11 Video Support: ${have_xvidmode}
-    GNOME Support:     ${enable_gnome}
-    OSX Support:       ${enable_osx}
-    Graphics System:   ${GRAPHICS_SUBSYSTEM}
 
-    Unit Tests:        ${do_tests}	(requires nunit >= ${NUNIT_REQUIRED})
+  Build/Development:
+    Unit Tests:        ${do_tests} (requires nunit >= ${NUNIT_REQUIRED})
     Release Build:     ${enable_release}
     Vendor Build ID:   ${vendor_build_id}
-"
+
+EOF
 
 # Unstable/in-development features; only show them if they were manually enabled
-if test "x$enable_moonlight" = "xyes";    then echo "    Moonlight Effects: ${enable_moonlight}"; fi
-if test "x$enable_remote_audio" = "xyes"; then echo "    Remote Audio:      ${enable_remote_audio}"; fi
-if test "x$enable_mediaweb" = "xyes";     then echo "    MediaWeb:          ${enable_mediaweb}"; fi
-if test "x$enable_torrent" = "xyes";      then echo "    Torrent Podcasts:  ${enable_torrent}"; fi
+if test "x$enable_moonlight" = "xyes";    then br=yes; echo "  Moonlight Effects:   ${enable_moonlight}";    fi
+if test "x$enable_remote_audio" = "xyes"; then br=yes; echo "  Remote Audio:        ${enable_remote_audio}"; fi
+if test "x$enable_mediaweb" = "xyes";     then br=yes; echo "  MediaWeb:            ${enable_mediaweb}";     fi
+if test "x$enable_torrent" = "xyes";      then br=yes; echo "  Torrent Podcasts:    ${enable_torrent}";      fi
 
 if test -d ${expanded_libdir}/${PACKAGE}; then
-	echo
-	echo "WARNING: An existing Banshee install is in ${expanded_libdir}/${PACKAGE}"
-	echo "         Remove the existing install before installing this build."
-	echo "         Installing over an existing install will cause conflicts!"
+	if test x$br = xyes; then echo; fi
+	echo "  WARNING: An existing Banshee install is in ${expanded_libdir}/${PACKAGE}"
+	echo "           Remove the existing install before installing this build."
+	echo "           Installing over an existing install will cause conflicts!"
 	echo 
 fi
 

Modified: trunk/banshee/libbanshee/Makefile.am
==============================================================================
--- trunk/banshee/libbanshee/Makefile.am	(original)
+++ trunk/banshee/libbanshee/Makefile.am	Sat Jan 24 23:05:00 2009
@@ -24,22 +24,13 @@
 	banshee-tagger.c \
 	banshee-transcoder.c
 
-noinst_HEADERS =  \
-	banshee-gst.h \
-	banshee-player-cdda.h \
-	banshee-player-equalizer.h \
-	banshee-player-missing-elements.h \
-	banshee-player-pipeline.h \
-	banshee-player-private.h \
-	banshee-player-replaygain.h \
-	banshee-player-video.h \
-	banshee-player-vis.h \
-	banshee-tagger.h
+if HAVE_CLUTTER
+libbanshee_la_SOURCES += clutter-gst-video-sink.c
+endif
 
 libbanshee_la_LIBADD = \
 	$(LIBBANSHEE_LIBS) \
-	$(GST_LIBS) \
-	$(LIBNAUTILUS_BURN_LIBS)
+	$(GST_LIBS)
 
 all: $(top_builddir)/bin/libbanshee.so
 
@@ -49,5 +40,7 @@
 
 CLEANFILES = $(top_builddir)/bin/libbanshee.so
 MAINTAINERCLEANFILES = Makefile.in
-EXTRA_DIST = $(libbanshee_la_SOURCES)
-
+EXTRA_DIST = \
+	$(libbanshee_la_SOURCES) \
+	$(wildcard *.h) \
+	$(wildcard clutter-*.c)

Modified: trunk/banshee/libbanshee/banshee-player-private.h
==============================================================================
--- trunk/banshee/libbanshee/banshee-player-private.h	(original)
+++ trunk/banshee/libbanshee/banshee-player-private.h	Sat Jan 24 23:05:00 2009
@@ -47,6 +47,10 @@
 #  include <gst/interfaces/xoverlay.h>
 #endif
 
+#ifdef HAVE_CLUTTER
+#  include <clutter/clutter.h>
+#endif
+
 #include "banshee-gst.h"
 
 #define P_INVOKE
@@ -99,6 +103,12 @@
     GdkWindow *video_window;
     #endif
     
+    // Clutter State
+    #ifdef HAVE_CLUTTER
+    GstElement *clutter_sink;
+    ClutterTexture *clutter_texture;
+    #endif
+    
     // Visualization State
     GstAdapter *vis_buffer;
     gfloat *spectrum_buffer;

Modified: trunk/banshee/libbanshee/banshee-player-video.c
==============================================================================
--- trunk/banshee/libbanshee/banshee-player-video.c	(original)
+++ trunk/banshee/libbanshee/banshee-player-video.c	Sat Jan 24 23:05:00 2009
@@ -32,6 +32,37 @@
 // Private Functions
 // ---------------------------------------------------------------------------
 
+#ifdef HAVE_CLUTTER
+
+#include <clutter/clutter.h>
+#include "clutter-gst-video-sink.h"
+
+typedef enum {
+    BP_VIDEO_DISPLAY_CONTEXT_UNSUPPORTED = 0,
+    BP_VIDEO_DISPLAY_CONTEXT_GDK_WINDOW = 1,
+    BP_VIDEO_DISPLAY_CONTEXT_CLUTTER_TEXTURE = 2
+} BpVideoDisplayContextType;
+
+static gboolean
+bp_video_pipeline_setup_clutter (BansheePlayer *player, GstBus *bus)
+{
+    if (player->clutter_texture == NULL) {
+        player->clutter_texture = g_object_new (CLUTTER_TYPE_TEXTURE,
+            "sync-size", FALSE,
+            "disable-slicing", TRUE,
+            NULL);
+    }
+    
+    bp_debug ("Created ClutterTexture: %p", player->clutter_texture);
+    
+    player->clutter_sink = clutter_gst_video_sink_new (CLUTTER_TEXTURE (player->clutter_texture));
+    g_object_set (G_OBJECT (player->playbin), "video-sink", player->clutter_sink, NULL);
+
+    return TRUE;
+}
+
+#endif /* HAVE_CLUTTER */
+
 #ifdef GDK_WINDOWING_X11
 
 static gboolean
@@ -126,10 +157,16 @@
 {
     GstElement *videosink;
     
-    #ifdef GDK_WINDOWING_X11
-    
     g_return_if_fail (IS_BANSHEE_PLAYER (player));
     
+    #if HAVE_CLUTTER
+    if (bp_video_pipeline_setup_clutter (player, bus)) {
+        return;
+    }
+    #endif
+    
+    #ifdef GDK_WINDOWING_X11
+    
     videosink = gst_element_factory_make ("gconfvideosink", "videosink");
     if (videosink == NULL) {
         videosink = gst_element_factory_make ("ximagesink", "videosink");
@@ -150,6 +187,15 @@
         g_signal_connect (videosink, "element-added", G_CALLBACK (bp_video_sink_element_added), player);
     }
     
+    #else
+    
+    videosink = gst_element_factory_make ("fakesink", "videosink");
+    if (videosink != NULL) {
+        g_object_set (G_OBJECT (videosink), "sync", TRUE, NULL);
+    }
+    
+    g_object_set (G_OBJECT (player->playbin), "video-sink", videosink, NULL);
+    
     #endif
 }
 
@@ -159,18 +205,44 @@
 
 #ifdef GDK_WINDOWING_X11
 
-P_INVOKE gboolean
-bp_video_is_supported (BansheePlayer *player)
+P_INVOKE BpVideoDisplayContextType
+bp_video_get_display_context_type (BansheePlayer *player)
 {
-    return TRUE; // bp_video_find_xoverlay (player);
+    #ifdef HAVE_CLUTTER
+    return player->clutter_sink == NULL
+        ? BP_VIDEO_DISPLAY_CONTEXT_GDK_WINDOW
+        : BP_VIDEO_DISPLAY_CONTEXT_CLUTTER_TEXTURE;
+    #else
+    return BP_VIDEO_DISPLAY_CONTEXT_GDK_WINDOW; // bp_video_find_xoverlay (player);
+    #endif
 }
 
 P_INVOKE void
-bp_video_set_window (BansheePlayer *player, GdkWindow *window)
+bp_video_set_display_context (BansheePlayer *player, gpointer context)
 {
     g_return_if_fail (IS_BANSHEE_PLAYER (player));
     
-    player->video_window = window;
+    if (bp_video_get_display_context_type (player) == BP_VIDEO_DISPLAY_CONTEXT_GDK_WINDOW) {
+        player->video_window = (GdkWindow *)context;
+    }
+}
+
+P_INVOKE gpointer
+bp_video_get_display_context (BansheePlayer *player)
+{
+    g_return_val_if_fail (IS_BANSHEE_PLAYER (player), NULL);
+    
+    #ifdef HAVE_CLUTTER
+    if (bp_video_get_display_context_type (player) == BP_VIDEO_DISPLAY_CONTEXT_CLUTTER_TEXTURE) {
+        return player->clutter_texture;
+    }
+    #endif
+    
+    if (bp_video_get_display_context_type (player) == BP_VIDEO_DISPLAY_CONTEXT_GDK_WINDOW) {
+        return player->video_window;
+    }
+    
+    return NULL;
 }
 
 P_INVOKE void
@@ -205,15 +277,33 @@
 
 #else /* GDK_WINDOWING_X11 */
 
-P_INVOKE gboolean
-bp_video_is_supported (BansheePlayer *player)
+P_INVOKE BpVideoDisplayContextType
+bp_video_get_display_context_type (BansheePlayer *player)
 {
-    return FALSE;
+    #ifdef HAVE_CLUTTER
+    return player->clutter_sink == NULL
+        ? BP_VIDEO_DISPLAY_CONTEXT_UNSUPPORTED
+        : BP_VIDEO_DISPLAY_CONTEXT_CLUTTER_TEXTURE;
+    #else
+    return BP_VIDEO_DISPLAY_CONTEXT_UNSUPPORTED;
+    #endif
 }
 
 P_INVOKE void
-bp_video_set_window (BansheePlayer *player, GdkWindow *window)
+bp_video_set_display_context (BansheePlayer *player, gpointer context)
+{
+}
+
+P_INVOKE gpointer
+bp_video_get_display_context (BansheePlayer *player)
 {
+    #ifdef HAVE_CLUTTER
+    if (bp_video_get_display_context_type (player) == BP_VIDEO_DISPLAY_CONTEXT_CLUTTER_TEXTURE) {
+        return player->clutter_texture;
+    }
+    #endif
+    
+    return NULL;
 }
 
 P_INVOKE void

Added: trunk/banshee/libbanshee/clutter-gst-shaders.h
==============================================================================
--- (empty file)
+++ trunk/banshee/libbanshee/clutter-gst-shaders.h	Sat Jan 24 23:05:00 2009
@@ -0,0 +1,43 @@
+
+#ifndef CLUTTER_GST_SHADERS_H
+#define CLUTTER_GST_SHADERS_H
+
+#include <clutter/clutter.h>
+
+/* Copied from test-shaders */
+
+/* These variables are used instead of the standard GLSL variables on
+   GLES 2 */
+#ifdef HAVE_COGL_GLES2
+
+#define GLES2_VARS              \
+  "precision mediump float;\n"  \
+  "varying vec2 tex_coord;\n"   \
+  "varying vec4 frag_color;\n"
+#define TEX_COORD "tex_coord"
+#define COLOR_VAR "frag_color"
+
+#else /* HAVE_COGL_GLES2 */
+
+#define GLES2_VARS ""
+#define TEX_COORD "gl_TexCoord[0]"
+#define COLOR_VAR "gl_Color"
+
+#endif /* HAVE_COGL_GLES2 */
+
+/* a couple of boilerplate defines that are common amongst all the
+ * sample shaders
+ */
+
+#define FRAGMENT_SHADER_VARS      \
+  GLES2_VARS
+
+/* FRAGMENT_SHADER_END: apply the changed color to the output buffer correctly
+ * blended with the gl specified color (makes the opacity of actors work
+ * correctly).
+ */
+#define FRAGMENT_SHADER_END                             \
+     "  gl_FragColor = gl_FragColor * " COLOR_VAR ";"
+
+#endif
+

Added: trunk/banshee/libbanshee/clutter-gst-video-sink.c
==============================================================================
--- (empty file)
+++ trunk/banshee/libbanshee/clutter-gst-video-sink.c	Sat Jan 24 23:05:00 2009
@@ -0,0 +1,781 @@
+/*
+ * Clutter-GStreamer.
+ *
+ * GStreamer integration library for Clutter.
+ *
+ * clutter-gst-video-sink.h - Gstreamer Video Sink that renders to a
+ *                            Clutter Texture.
+ *
+ * Authored by Jonathan Matthew  <jonathan kaolin wh9 net>,
+ *             Chris Lord        <chris openedhand com>
+ *
+ * Copyright (C) 2007,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.
+ */
+
+/**
+ * SECTION:clutter-gst-video-sink
+ * @short_description: GStreamer video sink
+ *
+ * #ClutterGstVideoSink is a GStreamer sink element that sends
+ * data to a #ClutterTexture.
+ */
+
+#include "config.h"
+
+#include "clutter-gst-video-sink.h"
+#include "clutter-gst-shaders.h"
+
+#include <gst/gst.h>
+#include <gst/gstvalue.h>
+#include <gst/video/video.h>
+#include <gst/riff/riff-ids.h>
+
+#include <glib.h>
+#include <clutter/clutter.h>
+#include <string.h>
+
+static gchar *ayuv_to_rgba_shader = \
+     FRAGMENT_SHADER_VARS
+     "uniform sampler2D tex;"
+     "void main () {"
+     "  vec4 color = texture2D (tex, vec2(" TEX_COORD "));"
+     "  float y = 1.1640625 * (color.g - 0.0625);"
+     "  float u = color.b - 0.5;"
+     "  float v = color.a - 0.5;"
+     "  color.a = color.r;"
+     "  color.r = y + 1.59765625 * v;"
+     "  color.g = y - 0.390625 * u - 0.8125 * v;"
+     "  color.b = y + 2.015625 * u;"
+     "  gl_FragColor = color;"
+     FRAGMENT_SHADER_END
+     "}";
+
+static gchar *dummy_shader = \
+     FRAGMENT_SHADER_VARS
+     "void main () {"
+     "}";
+
+static gchar *yv12_to_rgba_shader = \
+     FRAGMENT_SHADER_VARS
+     "uniform sampler2D ytex;"
+     "uniform sampler2D utex;"
+     "uniform sampler2D vtex;"
+     "void main () {"
+     "  vec2 coord = vec2(" TEX_COORD ");"
+     "  float y = 1.1640625 * (texture2D (ytex, coord).g - 0.0625);"
+     "  float u = texture2D (utex, coord).g - 0.5;"
+     "  float v = texture2D (vtex, coord).g - 0.5;"
+     "  vec4 color;"
+     "  color.r = y + 1.59765625 * v;"
+     "  color.g = y - 0.390625 * u - 0.8125 * v;"
+     "  color.b = y + 2.015625 * u;"
+     "  color.a = 1.0;"
+     "  gl_FragColor = color;"
+     FRAGMENT_SHADER_END
+     "}";
+
+static GstStaticPadTemplate sinktemplate 
+ = GST_STATIC_PAD_TEMPLATE ("sink",
+                            GST_PAD_SINK,
+                            GST_PAD_ALWAYS,
+                            GST_STATIC_CAPS (GST_VIDEO_CAPS_RGBx ";"   \
+                                             GST_VIDEO_CAPS_BGRx "; " \
+                                             GST_VIDEO_CAPS_RGB ";"   \
+                                             GST_VIDEO_CAPS_BGR \
+                                             ));
+
+/* Multi-texturing will only be available on GL, so decide on capabilties
+ * accordingly.
+ */
+
+#ifdef CLUTTER_COGL_HAS_GL
+#define YUV_CAPS GST_VIDEO_CAPS_YUV("AYUV") ";" GST_VIDEO_CAPS_YUV("YV12") ";"
+#else
+#define YUV_CAPS GST_VIDEO_CAPS_YUV("AYUV") ";"
+#endif
+
+/* Don't advertise RGB/BGR as it seems to override yv12, even when it's the
+ * better choice. Unfortunately, RGBx/BGRx also override AYUV when it's the
+ * better choice too, but that's not quite as bad.
+ */
+
+static GstStaticPadTemplate sinktemplate_shaders 
+ = GST_STATIC_PAD_TEMPLATE ("sink",
+                            GST_PAD_SINK,
+                            GST_PAD_ALWAYS,
+                            GST_STATIC_CAPS (YUV_CAPS \
+                                             GST_VIDEO_CAPS_RGBx ";" \
+                                             GST_VIDEO_CAPS_BGRx));
+
+static GstStaticPadTemplate sinktemplate_all 
+ = GST_STATIC_PAD_TEMPLATE ("sink",
+                            GST_PAD_SINK,
+                            GST_PAD_ALWAYS,
+                            GST_STATIC_CAPS (YUV_CAPS \
+                                             GST_VIDEO_CAPS_RGBx ";" \
+                                             GST_VIDEO_CAPS_BGRx ";" \
+                                             GST_VIDEO_CAPS_RGB ";" \
+                                             GST_VIDEO_CAPS_BGR));
+
+GST_DEBUG_CATEGORY_STATIC (clutter_gst_video_sink_debug);
+#define GST_CAT_DEFAULT clutter_gst_video_sink_debug
+
+static GstElementDetails clutter_gst_video_sink_details =
+  GST_ELEMENT_DETAILS ("Clutter video sink",
+      "Sink/Video",
+      "Sends video data from a GStreamer pipeline to a Clutter texture",
+      "Jonathan Matthew <jonathan kaolin wh9 net>, "
+      "Matthew Allum <mallum o-hand com, "
+      "Chris Lord <chris o-hand com>");
+
+enum
+{
+  PROP_0,
+  PROP_TEXTURE,
+  PROP_USE_SHADERS,
+};
+
+typedef enum
+{
+  CLUTTER_GST_NOFORMAT,
+  CLUTTER_GST_RGB32,
+  CLUTTER_GST_RGB24,
+  CLUTTER_GST_AYUV,
+  CLUTTER_GST_YV12,
+} ClutterGstVideoFormat;
+
+typedef void (*GLUNIFORM1IPROC)(COGLint location, COGLint value);
+
+struct _ClutterGstVideoSinkPrivate
+{
+  ClutterTexture        *texture;
+  CoglHandle             u_tex;
+  CoglHandle             v_tex;
+  CoglHandle             program;
+  CoglHandle             shader;
+  GAsyncQueue           *async_queue;
+  ClutterGstVideoFormat  format;
+  gboolean               bgr;
+  int                    width;
+  int                    height;
+  int                    fps_n, fps_d;
+  int                    par_n, par_d;
+  gboolean               use_shaders;
+  gboolean               shaders_init;
+  
+  GLUNIFORM1IPROC        glUniform1iARB;
+};
+
+
+#define _do_init(bla) \
+  GST_DEBUG_CATEGORY_INIT (clutter_gst_video_sink_debug, \
+                                 "cluttersink", \
+                                 0, \
+                                 "clutter video sink")
+
+GST_BOILERPLATE_FULL (ClutterGstVideoSink,
+                          clutter_gst_video_sink,
+                      GstBaseSink,
+                      GST_TYPE_BASE_SINK,
+                      _do_init);
+
+static void
+clutter_gst_video_sink_base_init (gpointer g_class)
+{
+  GstElementClass *element_class = GST_ELEMENT_CLASS (g_class);
+
+  gst_element_class_add_pad_template 
+                     (element_class,
+                      gst_static_pad_template_get (&sinktemplate_all));
+
+  gst_element_class_set_details (element_class, 
+                                 &clutter_gst_video_sink_details);
+}
+
+static void
+clutter_gst_video_sink_init (ClutterGstVideoSink      *sink,
+                             ClutterGstVideoSinkClass *klass)
+{
+  ClutterGstVideoSinkPrivate *priv;
+
+  sink->priv = priv =
+    G_TYPE_INSTANCE_GET_PRIVATE (sink, CLUTTER_GST_TYPE_VIDEO_SINK,
+                                 ClutterGstVideoSinkPrivate);
+
+  priv->async_queue = g_async_queue_new ();
+
+#ifdef CLUTTER_COGL_HAS_GL
+  priv->glUniform1iARB = (GLUNIFORM1IPROC)
+    cogl_get_proc_address ("glUniform1iARB");
+#endif
+}
+
+static void
+clutter_gst_video_sink_paint (ClutterActor        *actor,
+                              ClutterGstVideoSink *sink)
+{
+  ClutterGstVideoSinkPrivate *priv = sink->priv;
+  if (priv->program)
+    cogl_program_use (priv->program);
+}
+
+static void
+clutter_gst_yv12_paint (ClutterActor        *actor,
+                        ClutterGstVideoSink *sink)
+{
+#ifdef CLUTTER_COGL_HAS_GL
+  ClutterGstVideoSinkPrivate *priv = sink->priv;
+  GLuint texture;
+  
+  /* Bind the U and V textures in texture units 1 and 2 */
+  if (priv->u_tex)
+    {
+      cogl_texture_get_gl_texture (priv->u_tex, &texture, NULL);
+      glActiveTexture (GL_TEXTURE1);
+      glEnable (GL_TEXTURE_2D);
+      glBindTexture (GL_TEXTURE_2D, texture);
+    }
+
+  if (priv->v_tex)
+    {
+      cogl_texture_get_gl_texture (priv->v_tex, &texture, NULL);
+      glActiveTexture (GL_TEXTURE2);
+      glEnable (GL_TEXTURE_2D);
+      glBindTexture (GL_TEXTURE_2D, texture);
+    }
+  
+  glActiveTexture (GL_TEXTURE0_ARB);
+#endif
+}
+
+static void
+clutter_gst_yv12_post_paint (ClutterActor        *actor,
+                             ClutterGstVideoSink *sink)
+{
+#ifdef CLUTTER_COGL_HAS_GL
+  /* Disable the extra texture units */
+  glActiveTexture (GL_TEXTURE1);
+  glDisable (GL_TEXTURE_2D);
+  glActiveTexture (GL_TEXTURE2);
+  glDisable (GL_TEXTURE_2D);
+  glActiveTexture (GL_TEXTURE0);
+#endif
+}
+
+static void
+clutter_gst_video_sink_set_shader (ClutterGstVideoSink *sink,
+                                   const gchar         *shader_src)
+{
+  ClutterGstVideoSinkPrivate *priv = sink->priv;
+  
+  priv->shaders_init = FALSE;
+  if (priv->texture)
+    clutter_actor_set_shader (CLUTTER_ACTOR (priv->texture), NULL);
+
+  if (priv->program)
+    {
+      cogl_program_unref (priv->program);
+      priv->program = NULL;
+    }
+  
+  if (priv->shader)
+    {
+      cogl_program_unref (priv->shader);
+      priv->shader = NULL;
+    }
+  
+  if (shader_src)
+    {
+      ClutterShader *shader;
+
+      /* Set a dummy shader so we don't interfere with the shader stack */
+      shader = clutter_shader_new ();
+      clutter_shader_set_fragment_source (shader, dummy_shader, -1);
+      clutter_actor_set_shader (CLUTTER_ACTOR (priv->texture), shader);
+      g_object_unref (shader);
+
+      /* Create shader through COGL - necessary as we need to be able to set
+       * integer uniform variables for multi-texturing.
+       */
+      priv->shader = cogl_create_shader (CGL_FRAGMENT_SHADER);
+      cogl_shader_source (priv->shader, shader_src);
+      cogl_shader_compile (priv->shader);
+      
+      priv->program = cogl_create_program ();
+      cogl_program_attach_shader (priv->program, priv->shader);
+      cogl_program_link (priv->program);
+
+      /* Hook onto the pre-paint signal to replace the dummy shader with
+       * the real shader.
+       */
+      g_signal_connect (priv->texture,
+                        "paint",
+                        G_CALLBACK (clutter_gst_video_sink_paint),
+                        sink);
+      
+      priv->shaders_init = TRUE;
+    }
+}
+
+static gboolean
+clutter_gst_video_sink_idle_func (gpointer data)
+{
+  ClutterGstVideoSink        *sink;
+  ClutterGstVideoSinkPrivate *priv;
+  GstBuffer                  *buffer;
+
+  sink = data;
+  priv = sink->priv;
+
+  buffer = g_async_queue_try_pop (priv->async_queue);
+  if (buffer == NULL || G_UNLIKELY (!GST_IS_BUFFER (buffer)))
+    {
+      return FALSE;
+    }
+
+  if ((priv->format == CLUTTER_GST_RGB32) || (priv->format == CLUTTER_GST_AYUV))
+    {
+      clutter_texture_set_from_rgb_data (priv->texture,
+                                         GST_BUFFER_DATA (buffer),
+                                         TRUE,
+                                         priv->width,
+                                         priv->height,
+                                         GST_ROUND_UP_4 (4 * priv->width),
+                                         4,
+                                         priv->bgr ?
+                                         CLUTTER_TEXTURE_RGB_FLAG_BGR : 0,
+                                         NULL);
+
+      /* Initialise AYUV shader */
+      if ((priv->format == CLUTTER_GST_AYUV) && !priv->shaders_init)
+        clutter_gst_video_sink_set_shader (sink,
+                                           ayuv_to_rgba_shader);
+    }
+  else if (priv->format == CLUTTER_GST_RGB24)
+    {
+      clutter_texture_set_from_rgb_data (priv->texture,
+                                         GST_BUFFER_DATA (buffer),
+                                         FALSE,
+                                         priv->width,
+                                         priv->height,
+                                         GST_ROUND_UP_4 (3 * priv->width),
+                                         3,
+                                         priv->bgr ?
+                                         CLUTTER_TEXTURE_RGB_FLAG_BGR : 0,
+                                         NULL);
+    }
+  else if (priv->format == CLUTTER_GST_YV12)
+    {
+      CoglHandle y_tex =
+        cogl_texture_new_from_data (priv->width,
+                                    priv->height,
+                                    -1,
+                                    FALSE,
+                                    COGL_PIXEL_FORMAT_G_8,
+                                    COGL_PIXEL_FORMAT_G_8,
+                                    priv->width,
+                                    GST_BUFFER_DATA (buffer));
+      cogl_texture_set_filters (y_tex, CGL_LINEAR, CGL_LINEAR);
+      clutter_texture_set_cogl_texture (priv->texture, y_tex);
+      cogl_texture_unref (y_tex);
+      
+      if (priv->u_tex)
+        cogl_texture_unref (priv->u_tex);
+      
+      if (priv->v_tex)
+        cogl_texture_unref (priv->v_tex);
+      
+      priv->v_tex =
+        cogl_texture_new_from_data (priv->width/2,
+                                    priv->height/2,
+                                    -1,
+                                    FALSE,
+                                    COGL_PIXEL_FORMAT_G_8,
+                                    COGL_PIXEL_FORMAT_G_8,
+                                    priv->width/2,
+                                    GST_BUFFER_DATA (buffer) +
+                                      (priv->width * priv->height));
+      cogl_texture_set_filters (priv->v_tex, CGL_LINEAR, CGL_LINEAR);
+
+      priv->u_tex =
+        cogl_texture_new_from_data (priv->width/2,
+                                    priv->height/2,
+                                    -1,
+                                    FALSE,
+                                    COGL_PIXEL_FORMAT_G_8,
+                                    COGL_PIXEL_FORMAT_G_8,
+                                    priv->width/2,
+                                    GST_BUFFER_DATA (buffer) +
+                                      (priv->width * priv->height) +
+                                      (priv->width/2 * priv->height/2));
+      cogl_texture_set_filters (priv->u_tex, CGL_LINEAR, CGL_LINEAR);
+      
+      /* Initialise YV12 shader */
+      if (!priv->shaders_init)
+        {
+#ifdef CLUTTER_COGL_HAS_GL
+          COGLint location;
+          clutter_gst_video_sink_set_shader (sink,
+                                             yv12_to_rgba_shader);
+          
+          cogl_program_use (priv->program);
+          location = cogl_program_get_uniform_location (priv->program, "ytex");
+          priv->glUniform1iARB (location, 0);
+          location = cogl_program_get_uniform_location (priv->program, "utex");
+          priv->glUniform1iARB (location, 1);
+          location = cogl_program_get_uniform_location (priv->program, "vtex");
+          priv->glUniform1iARB (location, 2);
+          cogl_program_use (COGL_INVALID_HANDLE);
+          
+          g_signal_connect (priv->texture,
+                            "paint",
+                            G_CALLBACK (clutter_gst_yv12_paint),
+                            sink);
+          g_signal_connect_after (priv->texture,
+                                  "paint",
+                                  G_CALLBACK (clutter_gst_yv12_post_paint),
+                                  sink);
+#endif
+        }
+    }
+
+  gst_buffer_unref (buffer);
+  
+  return FALSE;
+}
+
+static GstFlowReturn
+clutter_gst_video_sink_render (GstBaseSink *bsink,
+                               GstBuffer   *buffer)
+{
+  ClutterGstVideoSink *sink;
+  ClutterGstVideoSinkPrivate *priv;
+
+  sink = CLUTTER_GST_VIDEO_SINK (bsink);
+  priv = sink->priv;
+
+  g_async_queue_push (priv->async_queue, gst_buffer_ref (buffer));
+
+  clutter_threads_add_idle_full (G_PRIORITY_HIGH_IDLE,
+                                 clutter_gst_video_sink_idle_func,
+                                 sink,
+                                 NULL);
+
+  return GST_FLOW_OK;
+}
+
+static GstCaps *
+clutter_gst_video_sink_get_caps (GstBaseSink *sink)
+{
+  ClutterGstVideoSinkPrivate *priv = CLUTTER_GST_VIDEO_SINK (sink)->priv;
+  
+  if (priv->use_shaders && cogl_features_available (COGL_FEATURE_SHADERS_GLSL))
+    return gst_static_pad_template_get_caps (&sinktemplate_shaders);
+  else
+    return gst_static_pad_template_get_caps (&sinktemplate);
+}
+
+static gboolean
+clutter_gst_video_sink_set_caps (GstBaseSink *bsink,
+                                 GstCaps     *caps)
+{
+  ClutterGstVideoSink        *sink;
+  ClutterGstVideoSinkPrivate *priv;
+  GstCaps                    *intersection;
+  GstStructure               *structure;
+  gboolean                    ret;
+  const GValue               *fps;
+  const GValue               *par;
+  gint                        width, height;
+  guint32                     fourcc;
+  int                         red_mask, blue_mask;
+
+  sink = CLUTTER_GST_VIDEO_SINK(bsink);
+  priv = sink->priv;
+
+  clutter_gst_video_sink_set_shader (sink, NULL);
+
+  if (priv->use_shaders && cogl_features_available (COGL_FEATURE_SHADERS_GLSL))
+    intersection 
+      = gst_caps_intersect 
+            (gst_static_pad_template_get_caps (&sinktemplate_shaders), 
+             caps);
+  else
+    intersection 
+      = gst_caps_intersect 
+            (gst_static_pad_template_get_caps (&sinktemplate), 
+             caps);
+
+  if (gst_caps_is_empty (intersection)) 
+    return FALSE;
+
+  gst_caps_unref (intersection);
+
+  structure = gst_caps_get_structure (caps, 0);
+
+  ret  = gst_structure_get_int (structure, "width", &width);
+  ret &= gst_structure_get_int (structure, "height", &height);
+  fps  = gst_structure_get_value (structure, "framerate");
+  ret &= (fps != NULL);
+
+  par  = gst_structure_get_value (structure, "pixel-aspect-ratio");
+
+  if (!ret)
+    return FALSE;
+
+  priv->width  = width;
+  priv->height = height;
+
+  /* We dont yet use fps or pixel aspect into but handy to have */
+  priv->fps_n  = gst_value_get_fraction_numerator (fps);
+  priv->fps_d  = gst_value_get_fraction_denominator (fps);
+
+  if (par) 
+    {
+      priv->par_n = gst_value_get_fraction_numerator (par);
+      priv->par_d = gst_value_get_fraction_denominator (par);
+    } 
+  else 
+    priv->par_n = priv->par_d = 1;
+
+  ret = gst_structure_get_fourcc (structure, "format", &fourcc);
+  if (ret && (fourcc == GST_RIFF_YV12))
+    {
+      priv->format = CLUTTER_GST_YV12;
+    }
+  else if (ret && (fourcc == GST_MAKE_FOURCC ('A', 'Y', 'U', 'V')))
+    {
+      priv->format = CLUTTER_GST_AYUV;
+      priv->bgr = FALSE;
+    }
+  else
+    {
+      guint32 width;
+      gst_structure_get_int (structure, "red_mask", &red_mask);
+      gst_structure_get_int (structure, "blue_mask", &blue_mask);
+      
+      width = red_mask | blue_mask;
+      if (width < 0x1000000)
+        {
+          priv->format = CLUTTER_GST_RGB24;
+          priv->bgr = (red_mask == 0xff0000) ? FALSE : TRUE;
+        }
+      else
+        {
+          priv->format = CLUTTER_GST_RGB32;
+          priv->bgr = (red_mask == 0xff000000) ? FALSE : TRUE;
+        }
+    }
+
+  return TRUE;
+}
+
+static void
+clutter_gst_video_sink_dispose (GObject *object)
+{
+  ClutterGstVideoSink *self;
+  ClutterGstVideoSinkPrivate *priv;
+
+  self = CLUTTER_GST_VIDEO_SINK (object);
+  priv = self->priv;
+
+  clutter_gst_video_sink_set_shader (self, NULL);
+
+  if (priv->texture)
+    {
+      g_object_unref (priv->texture);
+      priv->texture = NULL;
+    }
+
+  if (priv->async_queue)
+    {
+      g_async_queue_unref (priv->async_queue);
+      priv->async_queue = NULL;
+    }
+
+  G_OBJECT_CLASS (parent_class)->dispose (object);
+}
+
+static void
+clutter_gst_video_sink_finalize (GObject *object)
+{
+  ClutterGstVideoSink *self;
+  ClutterGstVideoSinkPrivate *priv;
+
+  self = CLUTTER_GST_VIDEO_SINK (object);
+  priv = self->priv;
+
+  G_OBJECT_CLASS (parent_class)->finalize (object);
+}
+
+static void
+clutter_gst_video_sink_set_property (GObject *object,
+                                     guint prop_id,
+                                     const GValue *value,
+                                     GParamSpec *pspec)
+{
+  ClutterGstVideoSink *sink;
+  ClutterGstVideoSinkPrivate *priv;
+  gboolean use_shaders;
+
+  sink = CLUTTER_GST_VIDEO_SINK (object);
+  priv = sink->priv;
+
+  switch (prop_id) 
+    {
+    case PROP_TEXTURE:
+      if (priv->texture)
+        g_object_unref (priv->texture);
+
+      priv->texture = CLUTTER_TEXTURE (g_value_dup_object (value));
+      break;
+    case PROP_USE_SHADERS:
+      use_shaders = g_value_get_boolean (value);
+      if (priv->use_shaders != use_shaders)
+        {
+          priv->use_shaders = use_shaders;
+          g_object_notify (object, "use_shaders");
+        }
+      break;
+    default:
+      G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+      break;
+    }
+}
+
+static void
+clutter_gst_video_sink_get_property (GObject *object,
+                                     guint prop_id,
+                                     GValue *value,
+                                     GParamSpec *pspec)
+{
+  ClutterGstVideoSink *sink;
+
+  sink = CLUTTER_GST_VIDEO_SINK (object);
+
+  switch (prop_id) 
+    {
+    case PROP_TEXTURE:
+      g_value_set_object (value, sink->priv->texture);
+      break;
+    case PROP_USE_SHADERS:
+      g_value_set_boolean (value, sink->priv->use_shaders);
+      break;
+    default:
+      G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+      break;
+  }
+}
+
+static gboolean
+clutter_gst_video_sink_stop (GstBaseSink *base_sink)
+{
+  ClutterGstVideoSinkPrivate *priv;
+  GstBuffer *buffer;
+
+  priv = CLUTTER_GST_VIDEO_SINK (base_sink)->priv;
+
+  g_async_queue_lock (priv->async_queue);
+
+  /* Remove all remaining objects from the queue */
+  do
+    {
+      buffer = g_async_queue_try_pop_unlocked (priv->async_queue);
+      if (buffer)
+        gst_buffer_unref (buffer);
+    } while (buffer != NULL);
+
+  g_async_queue_unlock (priv->async_queue);
+
+  return TRUE;
+}
+
+static void
+clutter_gst_video_sink_class_init (ClutterGstVideoSinkClass *klass)
+{
+  GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
+  GstBaseSinkClass *gstbase_sink_class = GST_BASE_SINK_CLASS (klass);
+
+  g_type_class_add_private (klass, sizeof (ClutterGstVideoSinkPrivate));
+
+  gobject_class->set_property = clutter_gst_video_sink_set_property;
+  gobject_class->get_property = clutter_gst_video_sink_get_property;
+
+  gobject_class->dispose = clutter_gst_video_sink_dispose;
+  gobject_class->finalize = clutter_gst_video_sink_finalize;
+
+  gstbase_sink_class->render = clutter_gst_video_sink_render;
+  gstbase_sink_class->preroll = clutter_gst_video_sink_render;
+  gstbase_sink_class->stop = clutter_gst_video_sink_stop;
+  gstbase_sink_class->set_caps = clutter_gst_video_sink_set_caps;
+  gstbase_sink_class->get_caps = clutter_gst_video_sink_get_caps;
+
+  g_object_class_install_property 
+              (gobject_class, PROP_TEXTURE,
+               g_param_spec_object ("texture",
+                                    "texture",
+                                    "Target ClutterTexture object",
+                                    CLUTTER_TYPE_TEXTURE,
+                                    G_PARAM_READWRITE));
+
+  g_object_class_install_property 
+              (gobject_class, PROP_USE_SHADERS,
+               g_param_spec_boolean ("use_shaders",
+                                     "Use shaders",
+                                     "Use a fragment shader to accelerate "
+                                     "colour-space conversion.",
+                                     FALSE,
+                                     G_PARAM_READWRITE));
+}
+
+/**
+ * clutter_gst_video_sink_new:
+ * @texture: a #ClutterTexture
+ *
+ * Creates a new GStreamer video sink which uses @texture as the target
+ * for sinking a video stream from GStreamer.
+ *
+ * Return value: a #GstElement for the newly created video sink
+ */
+GstElement *
+clutter_gst_video_sink_new (ClutterTexture *texture)
+{
+  return g_object_new (CLUTTER_GST_TYPE_VIDEO_SINK,
+                       "texture", texture,
+                       NULL);
+}
+
+static gboolean
+plugin_init (GstPlugin *plugin)
+{
+  gboolean ret = gst_element_register (plugin,
+                                             "cluttersink",
+                                       GST_RANK_PRIMARY,
+                                       CLUTTER_GST_TYPE_VIDEO_SINK);
+  return ret;
+}
+
+GST_PLUGIN_DEFINE_STATIC (GST_VERSION_MAJOR,
+                          GST_VERSION_MINOR,
+                          "cluttersink",
+                          "Element to render to Clutter textures",
+                          plugin_init,
+                          VERSION,
+                          "LGPL", /* license */
+                          PACKAGE,
+                          "");

Added: trunk/banshee/libbanshee/clutter-gst-video-sink.h
==============================================================================
--- (empty file)
+++ trunk/banshee/libbanshee/clutter-gst-video-sink.h	Sat Jan 24 23:05:00 2009
@@ -0,0 +1,103 @@
+/*
+ * Clutter-GStreamer.
+ *
+ * GStreamer integration library for Clutter.
+ *
+ * clutter-gst-video-sink.h - Gstreamer Video Sink that renders to a
+ *                            Clutter Texture.
+ *
+ * Authored by Jonathan Matthew  <jonathan kaolin wh9 net>
+ *
+ * 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 _HAVE_CLUTTER_GST_VIDEO_SINK_H
+#define _HAVE_CLUTTER_GST_VIDEO_SINK_H
+
+#include <glib-object.h>
+#include <gst/base/gstbasesink.h>
+#include <clutter/clutter.h>
+
+G_BEGIN_DECLS
+
+#define CLUTTER_GST_TYPE_VIDEO_SINK clutter_gst_video_sink_get_type()
+
+#define CLUTTER_GST_VIDEO_SINK(obj) \
+  (G_TYPE_CHECK_INSTANCE_CAST ((obj), \
+  CLUTTER_GST_TYPE_VIDEO_SINK, ClutterGstVideoSink))
+
+#define CLUTTER_GST_VIDEO_SINK_CLASS(klass) \
+  (G_TYPE_CHECK_CLASS_CAST ((klass), \
+  CLUTTER_GST_TYPE_VIDEO_SINK, ClutterGstVideoSinkClass))
+
+#define CLUTTER_GST_IS_VIDEO_SINK(obj) \
+  (G_TYPE_CHECK_INSTANCE_TYPE ((obj), \
+  CLUTTER_GST_TYPE_VIDEO_SINK))
+
+#define CLUTTER_GST_IS_VIDEO_SINK_CLASS(klass) \
+  (G_TYPE_CHECK_CLASS_TYPE ((klass), \
+  CLUTTER_GST_TYPE_VIDEO_SINK))
+
+#define CLUTTER_GST_VIDEO_SINK_GET_CLASS(obj) \
+  (G_TYPE_INSTANCE_GET_CLASS ((obj), \
+  CLUTTER_GST_TYPE_VIDEO_SINK, ClutterGstVideoSinkClass))
+
+typedef struct _ClutterGstVideoSink        ClutterGstVideoSink;
+typedef struct _ClutterGstVideoSinkClass   ClutterGstVideoSinkClass;
+typedef struct _ClutterGstVideoSinkPrivate ClutterGstVideoSinkPrivate;
+
+/**
+ * ClutterGstVideoSink:
+ *
+ * Class implementing a GStreamer sink element for #ClutterTexture<!-- -->s.
+ *
+ * The #ClutterGstVideoSink structure contains only private data and should
+ * not be accessed directly.
+ */
+struct _ClutterGstVideoSink
+{
+  /*< private >*/
+  GstBaseSink                 parent;
+  ClutterGstVideoSinkPrivate *priv;
+};
+
+/**
+ * ClutterGstVideoSinkClass:
+ *
+ * Base class for #ClutterGstVideoSink.
+ */
+struct _ClutterGstVideoSinkClass
+{
+  /*< private >*/
+  GstBaseSinkClass parent_class;
+
+  /* Future padding */
+  void (* _clutter_reserved1) (void);
+  void (* _clutter_reserved2) (void);
+  void (* _clutter_reserved3) (void);
+  void (* _clutter_reserved4) (void);
+  void (* _clutter_reserved5) (void);
+  void (* _clutter_reserved6) (void);
+};
+
+GType       clutter_gst_video_sink_get_type    (void) G_GNUC_CONST;
+GstElement *clutter_gst_video_sink_new         (ClutterTexture *texture);
+
+G_END_DECLS
+
+#endif

Modified: trunk/banshee/libbanshee/libbanshee.cproj
==============================================================================
--- trunk/banshee/libbanshee/libbanshee.cproj	(original)
+++ trunk/banshee/libbanshee/libbanshee.cproj	Sat Jan 24 23:05:00 2009
@@ -5,9 +5,6 @@
     <Platform Condition=" '$(Platform)' == '' ">AnyCPU</Platform>
     <ProductVersion>8.0.50727</ProductVersion>
     <ProjectGuid>{6B781836-AB65-49EF-BECD-CCC193C5D589}</ProjectGuid>
-    <Packages>
-      <Packages />
-    </Packages>
     <Compiler>
       <Compiler ctype="GccCompiler" />
     </Compiler>

Modified: trunk/banshee/src/Backends/Banshee.GStreamer/Banshee.GStreamer/PlayerEngine.cs
==============================================================================
--- trunk/banshee/src/Backends/Banshee.GStreamer/Banshee.GStreamer/PlayerEngine.cs	(original)
+++ trunk/banshee/src/Backends/Banshee.GStreamer/Banshee.GStreamer/PlayerEngine.cs	Sat Jan 24 23:05:00 2009
@@ -423,19 +423,13 @@
             }
         }
         
-        private bool? supports_video = null;
-        public override bool SupportsVideo {
-            get { 
-                if (supports_video == null) {
-                    supports_video = bp_video_is_supported (handle); 
-                }
-                
-                return supports_video.Value;
-            }
+        public override VideoDisplayContextType VideoDisplayContextType {
+            get { return bp_video_get_display_context_type (handle); }
         }
         
-        public override IntPtr VideoWindow {
-            set { bp_video_set_window (handle, value); }
+        public override IntPtr VideoDisplayContext {
+            set { bp_video_set_display_context (handle, value); }
+            get { return bp_video_get_display_context (handle); }
         }
         
         public double AmplifierLevel {
@@ -599,13 +593,16 @@
         private static extern void bp_set_application_gdk_window (HandleRef player, IntPtr window);
         
         [DllImport ("libbanshee")]
-        private static extern bool bp_video_is_supported (HandleRef player);
+        private static extern VideoDisplayContextType bp_video_get_display_context_type (HandleRef player);
+        
+        [DllImport ("libbanshee")]
+        private static extern void bp_video_set_display_context (HandleRef player, IntPtr displayContext);
         
         [DllImport ("libbanshee")]
-        private static extern void bp_video_set_window (HandleRef player, IntPtr window);
+        private static extern IntPtr bp_video_get_display_context (HandleRef player);
         
         [DllImport ("libbanshee")]
-        private static extern void bp_video_window_expose (HandleRef player, IntPtr window, bool direct);
+        private static extern void bp_video_window_expose (HandleRef player, IntPtr displayContext, bool direct);
                                                                    
         [DllImport ("libbanshee")]
         private static extern void bp_get_error_quarks (out uint core, out uint library, 

Modified: trunk/banshee/src/Core/Banshee.Services/Banshee.MediaEngine/NullPlayerEngine.cs
==============================================================================
--- trunk/banshee/src/Core/Banshee.Services/Banshee.MediaEngine/NullPlayerEngine.cs	(original)
+++ trunk/banshee/src/Core/Banshee.Services/Banshee.MediaEngine/NullPlayerEngine.cs	Sat Jan 24 23:05:00 2009
@@ -72,8 +72,8 @@
             get { return false; }
         }
         
-        public override bool SupportsVideo {
-            get { return false; }
+        public override VideoDisplayContextType VideoDisplayContextType {
+            get { return VideoDisplayContextType.Unsupported; }
         }
         
         private static string [] source_capabilities = { "file", "http", "cdda" };

Modified: trunk/banshee/src/Core/Banshee.Services/Banshee.MediaEngine/PlayerEngine.cs
==============================================================================
--- trunk/banshee/src/Core/Banshee.Services/Banshee.MediaEngine/PlayerEngine.cs	(original)
+++ trunk/banshee/src/Core/Banshee.Services/Banshee.MediaEngine/PlayerEngine.cs	Sat Jan 24 23:05:00 2009
@@ -107,7 +107,7 @@
 
         public abstract void Pause ();
         
-        public virtual void VideoExpose (IntPtr window, bool direct)
+        public virtual void VideoExpose (IntPtr displayContext, bool direct)
         {
             throw new NotImplementedException ("Engine must implement VideoExpose since this method only gets called when SupportsVideo is true");
         }
@@ -251,12 +251,13 @@
             get;
         }
         
-        public abstract bool SupportsVideo {
+        public abstract VideoDisplayContextType VideoDisplayContextType {
             get;
         }
         
-        public virtual IntPtr VideoWindow {
+        public virtual IntPtr VideoDisplayContext {
             set { }
+            get { return IntPtr.Zero; }
         }
     }
 }

Modified: trunk/banshee/src/Core/Banshee.Services/Banshee.MediaEngine/PlayerEngineService.cs
==============================================================================
--- trunk/banshee/src/Core/Banshee.Services/Banshee.MediaEngine/PlayerEngineService.cs	(original)
+++ trunk/banshee/src/Core/Banshee.Services/Banshee.MediaEngine/PlayerEngineService.cs	Sat Jan 24 23:05:00 2009
@@ -416,13 +416,14 @@
             }
         }
         
-        public void VideoExpose (IntPtr window, bool direct)
+        public void VideoExpose (IntPtr displayContext, bool direct)
         {
-            active_engine.VideoExpose (window, direct);
+            active_engine.VideoExpose (displayContext, direct);
         }
         
-        public IntPtr VideoWindow {
-            set { active_engine.VideoWindow = value; }
+        public IntPtr VideoDisplayContext {
+            set { active_engine.VideoDisplayContext = value; }
+            get { return active_engine.VideoDisplayContext; }
         }
         
         public void TrackInfoUpdated ()
@@ -522,8 +523,8 @@
             get { return ((active_engine is IEqualizer) && active_engine.SupportsEqualizer); }
         }
         
-        public bool SupportsVideo {
-            get { return active_engine.SupportsVideo; }
+        public VideoDisplayContextType VideoDisplayContextType {
+            get { return active_engine.VideoDisplayContextType; }
         }
         
         public uint Length {

Added: trunk/banshee/src/Core/Banshee.Services/Banshee.MediaEngine/VideoDisplayContextType.cs
==============================================================================
--- (empty file)
+++ trunk/banshee/src/Core/Banshee.Services/Banshee.MediaEngine/VideoDisplayContextType.cs	Sat Jan 24 23:05:00 2009
@@ -0,0 +1,39 @@
+//
+// VideoDisplayContextType.cs
+//
+// Author:
+//   Aaron Bockover <abockover novell com>
+//
+// Copyright (C) 2009 Novell, Inc.
+//
+// Permission is hereby granted, free of charge, to any person obtaining
+// a copy of this software and associated documentation files (the
+// "Software"), to deal in the Software without restriction, including
+// without limitation the rights to use, copy, modify, merge, publish,
+// distribute, sublicense, and/or sell copies of the Software, and to
+// permit persons to whom the Software is furnished to do so, subject to
+// the following conditions:
+//
+// The above copyright notice and this permission notice shall be
+// included in all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
+// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
+// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
+// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+//
+
+using System;
+
+namespace Banshee.MediaEngine
+{
+    public enum VideoDisplayContextType
+    {
+        Unsupported = 0,
+        GdkWindow = 1,
+        ClutterTexture = 2
+    }
+}

Modified: trunk/banshee/src/Core/Banshee.Services/Banshee.ServiceStack/ServiceManager.cs
==============================================================================
--- trunk/banshee/src/Core/Banshee.Services/Banshee.ServiceStack/ServiceManager.cs	(original)
+++ trunk/banshee/src/Core/Banshee.Services/Banshee.ServiceStack/ServiceManager.cs	Sat Jan 24 23:05:00 2009
@@ -274,7 +274,7 @@
                         ((IDisposable)service).Dispose ();
                         Log.DebugFormat ("Service disposed ({0})", service.ServiceName);
                     } catch (Exception e) {
-                        Log.Exception ("Service disposal ({0}) threw an exception", e);
+                        Log.Exception (String.Format ("Service disposal ({0}) threw an exception", service.ServiceName), e);
                     }
                 }
                 

Modified: trunk/banshee/src/Core/Banshee.Services/Makefile.am
==============================================================================
--- trunk/banshee/src/Core/Banshee.Services/Makefile.am	(original)
+++ trunk/banshee/src/Core/Banshee.Services/Makefile.am	Sat Jan 24 23:05:00 2009
@@ -85,6 +85,7 @@
 	Banshee.MediaEngine/PlayerEngineService.cs \
 	Banshee.MediaEngine/PlayerEvent.cs \
 	Banshee.MediaEngine/TranscoderService.cs \
+	Banshee.MediaEngine/VideoDisplayContextType.cs \
 	Banshee.MediaProfiles/MediaProfileManager.cs \
 	Banshee.MediaProfiles/Pipeline.cs \
 	Banshee.MediaProfiles/PipelineVariable.cs \

Modified: trunk/banshee/src/Core/Banshee.ThickClient/Banshee.Gui/GtkBaseClient.cs
==============================================================================
--- trunk/banshee/src/Core/Banshee.ThickClient/Banshee.Gui/GtkBaseClient.cs	(original)
+++ trunk/banshee/src/Core/Banshee.ThickClient/Banshee.Gui/GtkBaseClient.cs	Sat Jan 24 23:05:00 2009
@@ -92,6 +92,9 @@
             }
         }
         
+        [System.Runtime.InteropServices.DllImport ("clutter-gtk")]
+        private static extern int gtk_clutter_init (IntPtr argc, IntPtr argv);
+        
         protected void Initialize (bool registerCommonServices)
         {
             // Set the process name so system process listings and commands are pretty
@@ -99,8 +102,15 @@
             
             Application.Initialize ();
             
-            // Initialize GTK
-            Gtk.Application.Init ();
+            // Initialize Clutter/GTK
+            try {
+                if (gtk_clutter_init (IntPtr.Zero, IntPtr.Zero) != 1) {
+                    Gtk.Application.Init ();
+                }
+            } catch {
+                Gtk.Application.Init ();
+            }
+            
             Gtk.Window.DefaultIconName = default_icon_name;
 
             ThreadAssist.InitializeMainThread ();

Added: trunk/banshee/src/Core/Banshee.ThickClient/Banshee.ThickClient.dll.config
==============================================================================
--- (empty file)
+++ trunk/banshee/src/Core/Banshee.ThickClient/Banshee.ThickClient.dll.config	Sat Jan 24 23:05:00 2009
@@ -0,0 +1,3 @@
+<configuration>
+  <dllmap dll="clutter-gtk" target="libclutter-gtk-0.8.so.0"/>
+</configuration>

Modified: trunk/banshee/src/Core/Banshee.ThickClient/Makefile.am
==============================================================================
--- trunk/banshee/src/Core/Banshee.ThickClient/Makefile.am	(original)
+++ trunk/banshee/src/Core/Banshee.ThickClient/Makefile.am	Sat Jan 24 23:05:00 2009
@@ -152,3 +152,6 @@
 
 include $(top_srcdir)/build/build.mk
 
+module_SCRIPTS += Banshee.ThickClient.dll.config
+EXTRA_DIST += Banshee.ThickClient.dll.config
+

Added: trunk/banshee/src/Extensions/Banshee.NowPlaying/Banshee.NowPlaying.dll.config
==============================================================================
--- (empty file)
+++ trunk/banshee/src/Extensions/Banshee.NowPlaying/Banshee.NowPlaying.dll.config	Sat Jan 24 23:05:00 2009
@@ -0,0 +1,3 @@
+<configuration>
+  <dllmap dll="clutter-gtk" target="libclutter-gtk-0.8.so.0"/>
+</configuration>

Added: trunk/banshee/src/Extensions/Banshee.NowPlaying/Banshee.NowPlaying/IVideoDisplay.cs
==============================================================================
--- (empty file)
+++ trunk/banshee/src/Extensions/Banshee.NowPlaying/Banshee.NowPlaying/IVideoDisplay.cs	Sat Jan 24 23:05:00 2009
@@ -0,0 +1,38 @@
+//
+// IVideoDisplay.cs
+//
+// Author:
+//   Aaron Bockover <abockover novell com>
+//
+// Copyright (C) 2009 Novell, Inc.
+//
+// Permission is hereby granted, free of charge, to any person obtaining
+// a copy of this software and associated documentation files (the
+// "Software"), to deal in the Software without restriction, including
+// without limitation the rights to use, copy, modify, merge, publish,
+// distribute, sublicense, and/or sell copies of the Software, and to
+// permit persons to whom the Software is furnished to do so, subject to
+// the following conditions:
+//
+// The above copyright notice and this permission notice shall be
+// included in all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
+// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
+// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
+// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+//
+
+using System;
+
+namespace Banshee.NowPlaying
+{
+    public interface IVideoDisplay
+    {
+        event EventHandler IdleStateChanged;
+        bool IsIdle { get; }
+    }
+}

Modified: trunk/banshee/src/Extensions/Banshee.NowPlaying/Banshee.NowPlaying/NowPlayingContents.cs
==============================================================================
--- trunk/banshee/src/Extensions/Banshee.NowPlaying/Banshee.NowPlaying/NowPlayingContents.cs	(original)
+++ trunk/banshee/src/Extensions/Banshee.NowPlaying/Banshee.NowPlaying/NowPlayingContents.cs	Sat Jan 24 23:05:00 2009
@@ -35,7 +35,7 @@
 {
     public class NowPlayingContents : Table, IDisposable
     {
-        private VideoDisplay video_display;
+        private Widget video_display;
         private bool video_display_initial_shown = false;
         
         private TrackInfoDisplay track_info_display;
@@ -44,8 +44,21 @@
         {
             NoShowAll = true;
         
-            video_display = new XOverlayVideoDisplay ();
-            video_display.IdleStateChanged += OnVideoDisplayIdleStateChanged;
+            switch (Banshee.ServiceStack.ServiceManager.PlayerEngine.VideoDisplayContextType) {
+                case Banshee.MediaEngine.VideoDisplayContextType.GdkWindow:
+                    video_display = new XOverlayVideoDisplay ();
+                    break;
+                case Banshee.MediaEngine.VideoDisplayContextType.Unsupported:
+                default:
+                    video_display = null;
+                    break;
+            }
+            
+            IVideoDisplay ivideo_display = video_display as IVideoDisplay;
+            if (ivideo_display != null) {
+                ivideo_display.IdleStateChanged += OnVideoDisplayIdleStateChanged;
+            }
+            
             Attach (video_display, 0, 1, 0, 1, 
                 AttachOptions.Expand | AttachOptions.Fill, 
                 AttachOptions.Expand | AttachOptions.Fill, 0, 0);
@@ -58,8 +71,12 @@
         
         public override void Dispose ()
         {
+            IVideoDisplay ivideo_display = video_display as IVideoDisplay;
+            if (ivideo_display != null) {
+                ivideo_display.IdleStateChanged -= OnVideoDisplayIdleStateChanged;
+            }
+            
             if (video_display != null) {
-                video_display.IdleStateChanged -= OnVideoDisplayIdleStateChanged;
                 video_display = null;
             }
             
@@ -73,7 +90,11 @@
             // Ugly hack to ensure the video window is mapped/realized
             if (!video_display_initial_shown) {
                 video_display_initial_shown = true;
-                video_display.Show ();
+                
+                if (video_display != null) {
+                    video_display.Show ();
+                }
+                
                 GLib.Idle.Add (delegate { 
                     CheckIdle (); 
                     return false;
@@ -92,8 +113,11 @@
 
         private void CheckIdle ()
         {
-            video_display.Visible = !video_display.IsIdle;
-            track_info_display.Visible = video_display.IsIdle;
+            IVideoDisplay ivideo_display = video_display as IVideoDisplay;
+            if (ivideo_display != null) {
+                video_display.Visible = !ivideo_display.IsIdle;
+                track_info_display.Visible = ivideo_display.IsIdle;
+            }
         }
 
         private void OnVideoDisplayIdleStateChanged (object o, EventArgs args)

Modified: trunk/banshee/src/Extensions/Banshee.NowPlaying/Banshee.NowPlaying/VideoDisplay.cs
==============================================================================
--- trunk/banshee/src/Extensions/Banshee.NowPlaying/Banshee.NowPlaying/VideoDisplay.cs	(original)
+++ trunk/banshee/src/Extensions/Banshee.NowPlaying/Banshee.NowPlaying/VideoDisplay.cs	Sat Jan 24 23:05:00 2009
@@ -35,7 +35,7 @@
 
 namespace Banshee.NowPlaying
 {   
-    public abstract class VideoDisplay : Gtk.Widget
+    public abstract class VideoDisplay : Gtk.Widget, IVideoDisplay
     {
         private bool is_idle = true;
         
@@ -73,7 +73,7 @@
                 return true;
             }
             
-            if (!is_idle && ServiceManager.PlayerEngine.SupportsVideo) {
+            if (!is_idle && ServiceManager.PlayerEngine.VideoDisplayContextType != VideoDisplayContextType.Unsupported) {
                 ExposeVideo (evnt);
             }
             

Modified: trunk/banshee/src/Extensions/Banshee.NowPlaying/Banshee.NowPlaying/XOverlayVideoDisplay.cs
==============================================================================
--- trunk/banshee/src/Extensions/Banshee.NowPlaying/Banshee.NowPlaying/XOverlayVideoDisplay.cs	(original)
+++ trunk/banshee/src/Extensions/Banshee.NowPlaying/Banshee.NowPlaying/XOverlayVideoDisplay.cs	Sat Jan 24 23:05:00 2009
@@ -30,6 +30,7 @@
 using Gtk;
 
 using Banshee.ServiceStack;
+using Banshee.MediaEngine;
 
 namespace Banshee.NowPlaying
 {   
@@ -80,7 +81,11 @@
                         
             video_window.SetBackPixmap (null, false);
             
-            ServiceManager.PlayerEngine.VideoWindow = video_window.Handle;
+            if (ServiceManager.PlayerEngine.VideoDisplayContextType == VideoDisplayContextType.GdkWindow) {
+                ServiceManager.PlayerEngine.VideoDisplayContext = video_window.Handle;
+            } else {
+                ServiceManager.PlayerEngine.VideoDisplayContext = IntPtr.Zero;
+            }
         }
         
         protected override void OnUnrealized ()
@@ -119,7 +124,7 @@
         
         protected override bool OnConfigureEvent (Gdk.EventConfigure evnt)
         {
-            if (video_window != null && ServiceManager.PlayerEngine.SupportsVideo) {
+            if (video_window != null && ServiceManager.PlayerEngine.VideoDisplayContextType == VideoDisplayContextType.GdkWindow) {
                 ServiceManager.PlayerEngine.VideoExpose (video_window.Handle, true);
             }
             
@@ -128,7 +133,9 @@
         
         protected override void ExposeVideo (Gdk.EventExpose evnt)
         {
-            ServiceManager.PlayerEngine.VideoExpose (video_window.Handle, true);
+            if (ServiceManager.PlayerEngine.VideoDisplayContextType == VideoDisplayContextType.GdkWindow) {
+                ServiceManager.PlayerEngine.VideoExpose (video_window.Handle, true);
+            }
         }
     }
 }

Modified: trunk/banshee/src/Extensions/Banshee.NowPlaying/Makefile.am
==============================================================================
--- trunk/banshee/src/Extensions/Banshee.NowPlaying/Makefile.am	(original)
+++ trunk/banshee/src/Extensions/Banshee.NowPlaying/Makefile.am	Sat Jan 24 23:05:00 2009
@@ -9,6 +9,7 @@
 	Banshee.NowPlaying/FullscreenWindow.cs \
 	Banshee.NowPlaying/IFullscreenAdapter.cs \
 	Banshee.NowPlaying/IScreensaverManager.cs \
+	Banshee.NowPlaying/IVideoDisplay.cs \
 	Banshee.NowPlaying/NowPlayingContents.cs \
 	Banshee.NowPlaying/NowPlayingInterface.cs \
 	Banshee.NowPlaying/NowPlayingSource.cs \
@@ -25,3 +26,6 @@
 
 include $(top_srcdir)/build/build.mk
 
+module_SCRIPTS += Banshee.NowPlaying.dll.config
+EXTRA_DIST += Banshee.NowPlaying.dll.config
+



[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]