Modified: libbanshee/gst-playback-0.10.c
==============================================================================
--- libbanshee/gst-playback-0.10.c        (original)
+++ libbanshee/gst-playback-0.10.c        Mon Mar 24 19:46:10 2008
@@ -54,11 +54,6 @@
 #define IS_GST_PLAYBACK(e) (e != NULL)
 #define SET_CALLBACK(cb_name) { if(engine != NULL) { engine->cb_name = cb; } }
 
+// Visualisation defaults
+#define DEFAULT_FPS 20
+#define DEFAULT_WIDTH 320
+#define DEFAULT_HEIGHT 240
+
 typedef struct GstPlayback GstPlayback;
 
 typedef void (* GstPlaybackEosCallback) (GstPlayback *engine);
@@ -83,8 +78,6 @@
     GstXOverlay *xoverlay;
     GdkWindow *video_window;
     #endif
+    
+    GList *visualisations;
 
     guint iterate_timeout_id;
     gchar *cdda_device;
@@ -439,97 +432,6 @@
     #endif
 }
 
+static gboolean
+filter_features (GstPluginFeature * feature, gpointer data)
+{
+    GstElementFactory *f;
+
+    if (!GST_IS_ELEMENT_FACTORY (feature))
+        return FALSE;
+    f = GST_ELEMENT_FACTORY (feature);
+        if (!g_strrstr (gst_element_factory_get_klass (f), "Visualization"))
+    return FALSE;
+
+    return TRUE;
+}
+
+void
+gst_playback_set_active_visualisation (GstPlayback *engine, const gchar *name, gint width, gint height, gint fps)
+{
+    //g_debug ("Setting active visulisation: %s", name);
+    GList *feature;
+    GstElementFactory *tmp;
+    GstElementFactory *fac = NULL;
+    GstElement *vis_bin;
+    GstElement *vis_element;
+    GstElement *vis_capsfilter;
+    GstPad *pad;
+    GstCaps *caps;
+    
+    if (engine == NULL || name == NULL || engine->visualisations == NULL) {
+        return;
+    }
+    
+    for (feature = engine->visualisations; feature; feature = feature->next) {
+        tmp = GST_ELEMENT_FACTORY(feature->data);
+        if (!strcmp(GST_PLUGIN_FEATURE_NAME(tmp), name))
+            fac = tmp;
+    }
+    
+    vis_element = gst_element_factory_create (fac, "vis_element");
+    if (vis_element == NULL) {
+        return;
+    }
+    
+    vis_capsfilter = gst_element_factory_make("capsfilter", "vis_capsfilter");
+    g_return_if_fail(GST_IS_ELEMENT(vis_capsfilter));
+
+    vis_bin = gst_bin_new ("vis_bin");
+    g_return_if_fail(GST_IS_ELEMENT (vis_bin));
+
+    gst_bin_add_many(GST_BIN(vis_bin), vis_element, vis_capsfilter, NULL);
+
+    /* Sink ghostpad */
+    pad = gst_element_get_pad(vis_element, "sink");
+    gst_element_add_pad(vis_bin, gst_ghost_pad_new("sink", pad));
+    gst_object_unref(pad);
+
+    /* Source ghostpad, link with vis_element */
+    pad = gst_element_get_pad(vis_capsfilter, "src");
+    gst_element_add_pad(vis_bin, gst_ghost_pad_new("src", pad));
+    gst_element_link_pads(vis_element, "src", vis_capsfilter, "sink");
+    gst_object_unref (pad);
+
+    /* Get allowed output caps from visualisation element */
+    pad = gst_element_get_pad(vis_element, "src");
+    caps = gst_pad_get_allowed_caps(pad);
+    gst_object_unref(pad);
+
+    /* Can we fixate ? */
+    if (caps && !gst_caps_is_fixed(caps)) {
+        guint i;
+
+        caps = gst_caps_make_writable(caps);
+
+        /* Get visualization size */
+        for (i = 0; i < gst_caps_get_size (caps); ++i) {
+            GstStructure *s = gst_caps_get_structure (caps, i);
+
+            /* Fixate */
+            gst_structure_fixate_field_nearest_int(s, "width", width);
+            gst_structure_fixate_field_nearest_int(s, "height", height);
+            gst_structure_fixate_field_nearest_fraction(s, "framerate", fps, 1);
+        }
+
+        /* set this */
+        g_object_set(vis_capsfilter, "caps", caps, NULL);
+    }
+    
+    if (vis_bin != NULL) {
+        g_object_set (G_OBJECT (engine->playbin), "vis-plugin", vis_bin, NULL);
+    }
+}
+
 static gboolean 
 gst_playback_construct(GstPlayback *engine)
 {
@@ -540,9 +442,6 @@
     GstElement *audioconvert;
     GstPad *teepad;
     
+    GList *feature;
+    gchar *default_vis;
+    
     g_return_val_if_fail(IS_GST_PLAYBACK(engine), FALSE);
     
     // create necessary elements
@@ -614,16 +513,6 @@
         }
     }
     
+    engine->visualisations = gst_registry_feature_filter(gst_registry_get_default(),
+                           filter_features, FALSE, NULL);
+    
+    // Set first as default
+    if (engine->visualisations != NULL && g_list_length (engine->visualisations) > 0) {
+        feature = g_list_first (engine->visualisations);
+        default_vis = GST_PLUGIN_FEATURE_NAME (GST_ELEMENT_FACTORY (feature->data));
+        gst_playback_set_active_visualisation (engine, default_vis, DEFAULT_WIDTH, DEFAULT_HEIGHT, DEFAULT_FPS);
+    }
+    
     g_object_set (G_OBJECT (engine->playbin), "video-sink", videosink, NULL);
 
     bus = gst_pipeline_get_bus (GST_PIPELINE (engine->playbin));
@@ -707,8 +596,6 @@
     
     g_mutex_free (engine->mutex);
     
+    g_list_free(engine->visualisations);
+    
     if(GST_IS_OBJECT(engine->playbin)) {
         engine->target_state = GST_STATE_NULL;
         gst_element_set_state(engine->playbin, GST_STATE_NULL);
@@ -970,37 +857,6 @@
     *stream = GST_STREAM_ERROR;
 }
 
+gchar *
+gst_playback_get_visualisation_name (GstPlayback *engine, gint index)
+{
+    GList *feature;
+    gchar *ret;
+    
+    if (engine == NULL || index < 0) {
+        return NULL;
+    }
+
+    //g_debug ("Getting nth feature %d", index);
+    feature = g_list_nth (engine->visualisations, index);
+    if (feature != NULL) {
+        ret = g_strdup (GST_PLUGIN_FEATURE_NAME (GST_ELEMENT_FACTORY (feature->data)));
+    } else {
+        return NULL;
+    }
+    
+    return ret;
+}
+
+gint
+gst_playback_get_visualisation_count (GstPlayback *engine)
+{
+    if (engine == NULL) {
+        return 0;
+    }
+    
+    return g_list_length (engine->visualisations);
+}
+
 /* Region XOverlay */
 
 #ifdef GDK_WINDOWING_X11

Modified: src/Backends/Banshee.GStreamer/Banshee.GStreamer/PlayerEngine.cs
==============================================================================
--- src/Backends/Banshee.GStreamer/Banshee.GStreamer/PlayerEngine.cs      (original)
+++ src/Backends/Banshee.GStreamer/Banshee.GStreamer/PlayerEngine.cs      Mon Mar 24 19:46:10 2008
@@ -280,12 +280,6 @@
             return item;
         }
         
+        public override void SetCurrentVisualisation (string name, int width, int height, int fps)
+        {
+            gst_playback_set_active_visualisation (handle, name, width, height, fps);
+        }
+
+        
         public override ushort Volume {
             get { return (ushort)gst_playback_get_volume (handle); }
             set { 
@@ -348,25 +342,6 @@
         public override IntPtr VideoWindow {
             set { gst_playback_set_video_window (handle, value); }
         }
+
+        public override string [] Visualisations {
+            get {
+                // Yes, this is yucky, but it's *much* cleaner than trying
+                // to marshal string arrays nicely. :)
+                
+                string [] ret = null;
+                int count = gst_playback_get_visualisation_count (handle);
+                
+                if (count > 0) {
+                    ret = new string [count];
+                    for (int i = 0; i < count; i++) {
+                        ret [i] = gst_playback_get_visualisation_name (handle, i);
+                    }
+                }
+                
+                return ret;
+            }
+        }
         
         public double AmplifierLevel {
             set {
@@ -488,16 +463,7 @@
         
         [DllImport ("libbanshee")]
         private static extern void gst_playback_expose_video_window (HandleRef engine, IntPtr window, bool direct);
+        
+        [DllImport ("libbanshee")]
+        private static extern void gst_playback_set_active_visualisation (HandleRef engine, string name, int width, int height, int fps);
+        
+        [DllImport ("libbanshee")]
+        private static extern int gst_playback_get_visualisation_count (HandleRef engine);
+        
+        [DllImport ("libbanshee")]
+        private static extern string gst_playback_get_visualisation_name (HandleRef engine, int count);
+        
-                                                                   
         [DllImport ("libbanshee")]
         private static extern void gst_playback_get_error_quarks (out uint core, out uint library, 
             out uint resource, out uint stream);

Modified: src/Core/Banshee.Services/Banshee.MediaEngine/PlayerEngine.cs
==============================================================================
--- src/Core/Banshee.Services/Banshee.MediaEngine/PlayerEngine.cs (original)
+++ src/Core/Banshee.Services/Banshee.MediaEngine/PlayerEngine.cs Mon Mar 24 19:46:10 2008
@@ -225,10 +225,6 @@
             OnEventChanged (PlayerEngineEvent.TrackInfoUpdated);
         }
         
+        public virtual void SetCurrentVisualisation (string name, int width, int height, int fps)
+        {
+        }
+        
         public TrackInfo CurrentTrack {
             get { return current_track; }
         }
@@ -290,9 +286,5 @@
         public virtual IntPtr VideoWindow {
             set { }
         }
+        
+        public virtual string [] Visualisations {
+            get { return null; }
+        }
     }
 }

Modified: src/Extensions/Banshee.NowPlaying/Banshee.NowPlaying.mdp
==============================================================================
--- src/Extensions/Banshee.NowPlaying/Banshee.NowPlaying.mdp      (original)
+++ src/Extensions/Banshee.NowPlaying/Banshee.NowPlaying.mdp      Mon Mar 24 19:46:10 2008
@@ -12,7 +12,6 @@
     <File name="Banshee.NowPlaying/NowPlayingSource.cs" subtype="Code" buildaction="Compile" />
     <File name="Banshee.NowPlaying/NowPlayingInterface.cs" subtype="Code" buildaction="Compile" />
     <File name="Banshee.NowPlaying/VideoDisplay.cs" subtype="Code" buildaction="Compile" />
+    <File name="Banshee.NowPlaying/VisualisationConfigBox.cs" subtype="Code" buildaction="Compile" />
   </Contents>
   <References>
     <ProjectReference type="Project" localcopy="True" refto="Banshee.Core" />

Modified: src/Extensions/Banshee.NowPlaying/Banshee.NowPlaying/NowPlayingInterface.cs
==============================================================================
--- src/Extensions/Banshee.NowPlaying/Banshee.NowPlaying/NowPlayingInterface.cs   (original)
+++ src/Extensions/Banshee.NowPlaying/Banshee.NowPlaying/NowPlayingInterface.cs   Mon Mar 24 19:46:10 2008
@@ -28,6 +28,7 @@
 
 using System;
 
-using Mono.Unix;
 using Gtk;
 
 using Banshee.Sources;
@@ -41,55 +42,21 @@
         private NowPlayingSource source;
         private VideoDisplay video_display;
         private Hyena.Widgets.RoundedFrame frame;
+        private Hyena.Gui.AnimatedVBox anim_vbox;
+        
+        private VisualisationConfigBox vis_box;
+        private VisualisationConfigBox old_box;
         
         public NowPlayingInterface ()
         {
             video_display = new VideoDisplay ();
             video_display.Show ();
             
+            vis_box = new VisualisationConfigBox ();
+            vis_box.BorderWidth = 6;
+            vis_box.Show ();
+            
+            anim_vbox = new Hyena.Gui.AnimatedVBox ();
+            anim_vbox.Spacing = 6;
+            anim_vbox.Show ();
+            
             frame = new Hyena.Widgets.RoundedFrame ();
             frame.SetFillColor (new Cairo.Color (0, 0, 0));
             frame.DrawBorder = false;
             frame.Add (video_display);
             frame.Show ();
             
+            ShowVisualisationBox ();
+            PackStart (anim_vbox, false, false, 0);
             PackStart (frame, true, true, 0);
         }
         
+        public void ShowVisualisationBox ()
+        {
+            if (!anim_vbox.Contains (vis_box)) {
+                if (old_box != null) {
+                    vis_box = new VisualisationConfigBox (old_box);
+                    old_box.Dispose ();
+                }
+                
+                anim_vbox.Add (vis_box);
+            }
+        }
+        
+        public void HideVisualisationBox ()
+        {
+            if (anim_vbox.Contains (vis_box)) {
+                anim_vbox.Remove (vis_box, Hyena.Gui.Easing.QuadraticOut);
+                old_box = vis_box;
+            }
+        }
+        
 #region ISourceContents
         
         public bool SetSource (ISource src)

Modified: src/Extensions/Banshee.NowPlaying/Banshee.NowPlaying/NowPlayingSource.cs
==============================================================================
--- src/Extensions/Banshee.NowPlaying/Banshee.NowPlaying/NowPlayingSource.cs      (original)
+++ src/Extensions/Banshee.NowPlaying/Banshee.NowPlaying/NowPlayingSource.cs      Mon Mar 24 19:46:10 2008
@@ -42,14 +42,11 @@
     public class NowPlayingSource : Source, IDisposable
     {
         private TrackInfo transitioned_track;
+        private NowPlayingInterface nowplaying_interface;
         
         public NowPlayingSource () : base ("now-playing", Catalog.GetString ("Now Playing"), 0)
         {
+            nowplaying_interface = new NowPlayingInterface ();
+            
             Properties.SetString ("Icon.Name", "media-playback-start");
+            Properties.Set<ISourceContents> ("Nereid.SourceContents", nowplaying_interface);
-            Properties.Set<ISourceContents> ("Nereid.SourceContents", new NowPlayingInterface ());
             Properties.Set<bool> ("Nereid.SourceContents.HeaderVisible", false);
             
             ServiceManager.SourceManager.AddSource (this);
@@ -66,15 +63,9 @@
         private void OnPlaybackControllerTrackStarted (object o, EventArgs args)
         { 
             TrackInfo current_track = ServiceManager.PlaybackController.CurrentTrack;
+            if (current_track != null && 
-            if (current_track != null && transitioned_track != current_track && 
                 (current_track.MediaAttributes & TrackMediaAttributes.VideoStream) != 0) {
+                if (transitioned_track != current_track) {
+                    ServiceManager.SourceManager.SetActiveSource (this);
+                }
+                
+                nowplaying_interface.HideVisualisationBox ();
+            } else {
+                nowplaying_interface.ShowVisualisationBox ();
-                ServiceManager.SourceManager.SetActiveSource (this);
             }
         }
         

Modified: src/Extensions/Banshee.NowPlaying/Makefile.am
==============================================================================
--- src/Extensions/Banshee.NowPlaying/Makefile.am (original)
+++ src/Extensions/Banshee.NowPlaying/Makefile.am Mon Mar 24 19:46:10 2008
@@ -6,8 +6,7 @@
 SOURCES =  \
        Banshee.NowPlaying/NowPlayingInterface.cs \
        Banshee.NowPlaying/NowPlayingSource.cs \
+       Banshee.NowPlaying/VideoDisplay.cs \
+       Banshee.NowPlaying/VisualisationConfigBox.cs
-       Banshee.NowPlaying/VideoDisplay.cs
 
 RESOURCES = Banshee.NowPlaying.addin.xml
Index: src/Extensions/Banshee.NowPlaying/Banshee.NowPlaying/VisualisationConfigBox.cs
===================================================================
--- src/Extensions/Banshee.NowPlaying/Banshee.NowPlaying/VisualisationConfigBox.cs	(revision 3523)
+++ src/Extensions/Banshee.NowPlaying/Banshee.NowPlaying/VisualisationConfigBox.cs	(working copy)
@@ -1,159 +0,0 @@
+//
+// VisualisationConfigBox.cs
+//
+// Author:
+//   Alexander Hixon <hixon.alexander@mediati.org>
+//
+// Copyright (C) 2008 Alexander Hixon
+//
+// 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;
+
+using Mono.Unix;
+using Gtk;
+
+using Banshee.ServiceStack;
+
+namespace Banshee.NowPlaying
+{
+    public class VisualisationConfigBox : HBox
+    {
+        private int height;
+        private int width;
+        private int fps;
+        private string vis_name;
+        private int vis_id;
+        
+        public string ActiveVisualisationName {
+            get { return vis_name; }
+        }
+        
+        public int ActiveVisualisation {
+            get { return vis_id; }
+        }
+        
+        // These match both Totem and Rhythmbox.
+        private int [][] size_matrix = {
+            new int [] { 200, 150, 10 }, /* small */
+            new int [] { 320, 240, 20 }, /* normal */
+            new int [] { 640, 480, 25 }, /* large */
+            new int [] { 800, 600, 30 }  /* extra large */
+        };
+        
+        private int active_size = 1;
+        public int ActiveSize {
+            get { return active_size; }
+        }
+        
+        private string [] visualisations;
+        public string [] Visualisations {
+            get { return visualisations; }
+        }
+        
+        public VisualisationConfigBox ()
+        {
+            vis_id = 0;
+            UpdateQuality ();
+            
+            visualisations = ServiceManager.PlayerEngine.ActiveEngine.Visualisations;
+            if (visualisations != null && visualisations.Length > 0) {
+                BuildBox ();
+                vis_name = visualisations [vis_id];
+            }
+        }
+        
+        public VisualisationConfigBox (VisualisationConfigBox box)
+        {
+            active_size = box.ActiveSize;
+            vis_id = box.ActiveVisualisation;
+            vis_name = box.ActiveVisualisationName;
+            visualisations = box.Visualisations;
+            
+            UpdateQuality ();
+            
+            if (visualisations != null && visualisations.Length > 0) {
+                BuildBox ();
+            }
+        }
+        
+        private void BuildBox ()
+        {
+            Label vis_label = new Label (Catalog.GetString ("Visualisation:"));
+            vis_label.Show ();
+            
+            ComboBox vis_selection = ComboBox.NewText ();
+            foreach (string visualisation in visualisations) {
+                vis_selection.AppendText (visualisation);
+            }
+            
+            vis_selection.Active = vis_id;
+            vis_selection.Changed += OnVisualisationChanged;
+            vis_selection.Show ();
+            
+            Label quality_label = new Label (Catalog.GetString ("Quality:"));
+            quality_label.Show ();
+            
+            ComboBox quality_selection = ComboBox.NewText ();
+            quality_selection.AppendText (Catalog.GetString ("Small"));
+            quality_selection.AppendText (Catalog.GetString ("Normal"));
+            quality_selection.AppendText (Catalog.GetString ("Large"));
+            quality_selection.AppendText (Catalog.GetString ("Extra Large"));
+            quality_selection.Active = active_size;
+            quality_selection.Changed += OnQualityChanged;
+            quality_selection.Show ();
+            
+            Button fullscreen = new Button ("gtk-fullscreen");
+            fullscreen.Show ();
+            
+            PackStart (vis_label, false, false, 6);
+            PackStart (vis_selection, true, true, 6);
+            PackStart (quality_label, false, false, 0);
+            PackStart (quality_selection, true, true, 6);
+            PackStart (fullscreen, false, false, 6);
+        }
+        
+#region Callbacks
+        private void OnVisualisationChanged (object o, EventArgs args)
+        {
+            vis_id = (o as ComboBox).Active;
+            vis_name = visualisations [vis_id];
+            ServiceManager.PlayerEngine.ActiveEngine.SetCurrentVisualisation (vis_name, width, height, fps);
+        }
+        
+        private void OnQualityChanged (object o, EventArgs args)
+        {
+            int idx = (o as ComboBox).Active;
+            active_size = idx;
+            UpdateQuality ();
+            
+            ServiceManager.PlayerEngine.ActiveEngine.SetCurrentVisualisation (vis_name, width, height, fps);
+        }
+        
+        private void UpdateQuality ()
+        {
+            width = size_matrix [active_size][0];
+            height = size_matrix [active_size][1];
+            fps = size_matrix [active_size][2];
+        }
+#endregion
+    }
+}
