banshee r3351 - in trunk/banshee: . src/Core/Banshee.Core/Banshee.Streaming src/Core/Banshee.Services src/Core/Banshee.Services/Banshee.Database src/Core/Banshee.Services/Banshee.ServiceStack src/Core/Banshee.ThickClient src/Core/Banshee.ThickClient/Banshee.Collection.Gui src/Core/Banshee.ThickClient/Banshee.Gui src/Core/Banshee.ThickClient/Banshee.Sources.Gui src/Libraries/Hyena src/Libraries/Hyena.Gui src/Libraries/Hyena.Gui/Hyena.Data.Gui src/Libraries/Hyena.Gui/Hyena.Data.Gui/ListView src/Libraries/Hyena.Gui/Hyena.Gui.Theming src/Libraries/Hyena.Gui/Hyena.Widgets



Author: abock
Date: Thu Feb 28 22:03:14 2008
New Revision: 3351
URL: http://svn.gnome.org/viewvc/banshee?rev=3351&view=rev

Log:
2008-02-28  Aaron Bockover  <abock gnome org>

    * src/Core/Banshee.Core/Banshee.Streaming/StreamTagger.cs: Added a new
    base version of TrackInfoMerge that allows you to switch priority/fallback
    values to prefer either the database track or the taglib file data

    * src/Core/Banshee.Services/Banshee.Database/BansheeDbConnection.cs: Move
    the migration consumer stuff out, make the migrator accessible to others

    * src/Core/Banshee.Services/Banshee.Database/BansheeDbFormatMigrator.cs:
    Use a UserJob to report the migration track scanning progress

    * src/Core/Banshee.Services/Banshee.ServiceStack/IInitializeService.cs:
    A simple interface that will tell the service manager to call initialize
    on it after registering; this allows other objects to listen for the
    service before the service actually does anything

    * src/Core/Banshee.Services/Banshee.ServiceStack/ServiceManager.cs:
    Support IInitializeService.Initialize

    * src/Core/Banshee.Services/Banshee.ServiceStack/UserJob.cs: Added some
    more ctor overrides to make it easier to use

    * src/Core/Banshee.ThickClient/Banshee.Gui/BansheeDbFormatMigratorMonitor.cs:
    A UI for reporting the migration progress in the database layer

    * src/Core/Banshee.ThickClient/Banshee.Gui/GtkBaseClient.cs: Connect
    to the database migration layer and use the new UI to report progress

    * src/Core/Banshee.ThickClient/Banshee.Collection.Gui/TrackListView.cs:
    Draw a bubble, shouldn't commit this, in a hurry

    * src/Libraries/Hyena.Gui/Hyena.Data.Gui/ListView/ListView_Windowing.cs:
    * src/Libraries/Hyena.Gui/Hyena.Data.Gui/ListView/ListView_Rendering.cs:
    * src/Core/Banshee.ThickClient/Banshee.Collection.Gui/ColumnCellAlbum.cs:
    * src/Core/Banshee.ThickClient/Banshee.Sources.Gui/SourceRowRenderer.cs:
    * src/Core/Banshee.ThickClient/Banshee.Sources.Gui/SourceView.cs:
    * src/Libraries/Hyena.Gui/Hyena.Data.Gui/CellContext.cs:
    * src/Libraries/Hyena.Gui/Hyena.Data.Gui/ColumnCellText.cs: Fixed up
    to use the new Hyena.Gui.Theming API

    * src/Libraries/Hyena.Gui/Hyena.Data.Gui/ListViewGraphics.cs: Nuked

    * src/Libraries/Hyena.Gui/Hyena.Gui.Theming/GtkColors.cs:
    * src/Libraries/Hyena.Gui/Hyena.Gui.Theming/GtkTheme.cs:
    * src/Libraries/Hyena.Gui/Hyena.Gui.Theming/Theme.cs:
    * src/Libraries/Hyena.Gui/Hyena.Gui.Theming/ThemeContext.cs: New simple
    theme API that will make doing the custom drawing easier than the crappy
    ListViewGraphics bloated/hard to use API



Added:
   trunk/banshee/src/Core/Banshee.Services/Banshee.ServiceStack/IInitializeService.cs
   trunk/banshee/src/Core/Banshee.ThickClient/Banshee.Gui/BansheeDbFormatMigratorMonitor.cs
   trunk/banshee/src/Libraries/Hyena.Gui/Hyena.Gui.Theming/
   trunk/banshee/src/Libraries/Hyena.Gui/Hyena.Gui.Theming/GtkColors.cs
   trunk/banshee/src/Libraries/Hyena.Gui/Hyena.Gui.Theming/GtkTheme.cs
   trunk/banshee/src/Libraries/Hyena.Gui/Hyena.Gui.Theming/Theme.cs
   trunk/banshee/src/Libraries/Hyena.Gui/Hyena.Gui.Theming/ThemeContext.cs
Removed:
   trunk/banshee/src/Libraries/Hyena.Gui/Hyena.Data.Gui/ListViewGraphics.cs
Modified:
   trunk/banshee/ChangeLog
   trunk/banshee/src/Core/Banshee.Core/Banshee.Streaming/StreamTagger.cs
   trunk/banshee/src/Core/Banshee.Services/Banshee.Database/BansheeDbConnection.cs
   trunk/banshee/src/Core/Banshee.Services/Banshee.Database/BansheeDbFormatMigrator.cs
   trunk/banshee/src/Core/Banshee.Services/Banshee.ServiceStack/ServiceManager.cs
   trunk/banshee/src/Core/Banshee.Services/Banshee.ServiceStack/UserJob.cs
   trunk/banshee/src/Core/Banshee.Services/Banshee.Services.mdp
   trunk/banshee/src/Core/Banshee.Services/Makefile.am
   trunk/banshee/src/Core/Banshee.ThickClient/Banshee.Collection.Gui/ColumnCellAlbum.cs
   trunk/banshee/src/Core/Banshee.ThickClient/Banshee.Collection.Gui/TrackListView.cs
   trunk/banshee/src/Core/Banshee.ThickClient/Banshee.Gui/GtkBaseClient.cs
   trunk/banshee/src/Core/Banshee.ThickClient/Banshee.Sources.Gui/SourceRowRenderer.cs
   trunk/banshee/src/Core/Banshee.ThickClient/Banshee.Sources.Gui/SourceView.cs
   trunk/banshee/src/Core/Banshee.ThickClient/Banshee.ThickClient.mdp
   trunk/banshee/src/Core/Banshee.ThickClient/Makefile.am
   trunk/banshee/src/Libraries/Hyena.Gui/Hyena.Data.Gui/CellContext.cs
   trunk/banshee/src/Libraries/Hyena.Gui/Hyena.Data.Gui/ColumnCellText.cs
   trunk/banshee/src/Libraries/Hyena.Gui/Hyena.Data.Gui/ListView/ListView_Rendering.cs
   trunk/banshee/src/Libraries/Hyena.Gui/Hyena.Data.Gui/ListView/ListView_Windowing.cs
   trunk/banshee/src/Libraries/Hyena.Gui/Hyena.Gui.mdp
   trunk/banshee/src/Libraries/Hyena.Gui/Hyena.Widgets/MessageBar.cs
   trunk/banshee/src/Libraries/Hyena.Gui/Hyena.Widgets/RoundedFrame.cs
   trunk/banshee/src/Libraries/Hyena.Gui/Makefile.am
   trunk/banshee/src/Libraries/Hyena/Hyena.mdp

Modified: trunk/banshee/src/Core/Banshee.Core/Banshee.Streaming/StreamTagger.cs
==============================================================================
--- trunk/banshee/src/Core/Banshee.Core/Banshee.Streaming/StreamTagger.cs	(original)
+++ trunk/banshee/src/Core/Banshee.Core/Banshee.Streaming/StreamTagger.cs	Thu Feb 28 22:03:14 2008
@@ -40,53 +40,80 @@
             TagLib.File file = Banshee.IO.DemuxVfs.OpenFile (uri.IsLocalPath ? uri.LocalPath : uri.AbsoluteUri, 
                 null, TagLib.ReadStyle.Average);
 
-            if (file.Properties.MediaTypes != TagLib.MediaTypes.Audio) {
+            if ((file.Properties.MediaTypes & TagLib.MediaTypes.Audio) != 0 && 
+                file.Properties.MediaTypes != TagLib.MediaTypes.Audio) {
                 throw new TagLib.UnsupportedFormatException ("File contains more than just audio");
             }
             
             return file;
         }
+
+        private static string Choose (string priority, string fallback)
+        {
+            return Choose (priority, fallback, false);
+        }
     
-        private static string Choose(string priority, string fallback)
+        private static string Choose (string priority, string fallback, bool flip)
+        {
+            return flip 
+                ? String.IsNullOrEmpty (fallback) ? priority : fallback
+                : String.IsNullOrEmpty (priority) ? fallback : priority;
+        }
+
+        private static int Choose (int priority, int fallback)
+        {
+            return Choose (priority, fallback, false);
+        }
+
+        private static int Choose (int priority, int fallback, bool flip)
         {
-            return priority == null || priority.Length == 0 ? fallback : priority;
+            return flip 
+                ? (fallback <= 0 ? priority : fallback)
+                : (priority <= 0 ? fallback : priority);
         }
         
-        public static void TrackInfoMerge(TrackInfo track, TagLib.File file)
+        public static void TrackInfoMerge (TrackInfo track, TagLib.File file)
+        {
+            TrackInfoMerge (track, file, false);
+        }
+
+        public static void TrackInfoMerge (TrackInfo track, TagLib.File file, bool preferTrackInfo)
         {
             track.Uri = new SafeUri (file.Name);
             track.MimeType = file.MimeType;
-            track.ArtistName = Choose(file.Tag.JoinedPerformers, track.ArtistName);
-            track.AlbumTitle = Choose(file.Tag.Album, track.AlbumTitle);
-            track.Disc = file.Tag.Disc == 0 ? track.Disc : (int)file.Tag.Disc;
-            track.TrackTitle = Choose(file.Tag.Title, track.TrackTitle);
-            track.Genre = Choose(file.Tag.FirstGenre, track.Genre);
-            track.TrackNumber = file.Tag.Track == 0 ? track.TrackNumber : (int)file.Tag.Track;
-            track.TrackCount = file.Tag.TrackCount == 0 ? track.TrackCount : (int)file.Tag.TrackCount;
-            track.Year = (int)file.Tag.Year;
-            track.Duration = file.Properties.Duration;
             track.FileSize = Banshee.IO.File.GetSize (track.Uri);
+            track.Duration = file.Properties.Duration;
+
+            track.ArtistName = Choose (file.Tag.JoinedPerformers, track.ArtistName, preferTrackInfo);
+            track.AlbumTitle = Choose (file.Tag.Album, track.AlbumTitle, preferTrackInfo);
+            track.TrackTitle = Choose (file.Tag.Title, track.TrackTitle, preferTrackInfo);
+            track.Genre = Choose (file.Tag.FirstGenre, track.Genre, preferTrackInfo);
+
+            track.TrackNumber = Choose ((int)file.Tag.Track, track.TrackNumber, preferTrackInfo);
+            track.TrackCount = Choose ((int)file.Tag.TrackCount, track.TrackCount, preferTrackInfo);
+            track.Disc = Choose ((int)file.Tag.Disc, track.Disc, preferTrackInfo);
+            track.Year = Choose ((int)file.Tag.Year, track.Year, preferTrackInfo);
         }
     
-        public static void TrackInfoMerge(TrackInfo track, StreamTag tag)
+        public static void TrackInfoMerge (TrackInfo track, StreamTag tag)
         {
             try {
-                switch(tag.Name) {
+                switch (tag.Name) {
                     case CommonTags.Artist:
-                        track.ArtistName = Choose((string)tag.Value, track.ArtistName);
+                        track.ArtistName = Choose ((string)tag.Value, track.ArtistName);
                         break;
                     case CommonTags.Title:
-                        track.TrackTitle = Choose((string)tag.Value, track.TrackTitle);
+                        track.TrackTitle = Choose ((string)tag.Value, track.TrackTitle);
                         break;
                     case CommonTags.Album:
-                        track.AlbumTitle = Choose((string)tag.Value, track.AlbumTitle);
+                        track.AlbumTitle = Choose ((string)tag.Value, track.AlbumTitle);
                         break;
                     case CommonTags.Disc:
                         int disc = (int)tag.Value;
                         track.Disc = disc == 0 ? track.Disc : disc;
                         break;
                     case CommonTags.Genre:
-                        track.Genre = Choose((string)tag.Value, track.Genre);
+                        track.Genre = Choose ((string)tag.Value, track.Genre);
                         break;
                     case CommonTags.TrackNumber:
                         int track_number = (int)tag.Value;
@@ -96,10 +123,10 @@
                         track.TrackCount = (int)tag.Value;
                         break;
                     case CommonTags.Duration:
-                        if(tag.Value is TimeSpan) {
+                        if (tag.Value is TimeSpan) {
                             track.Duration = (TimeSpan)tag.Value;
                         } else {
-                            track.Duration = new TimeSpan((uint)tag.Value * TimeSpan.TicksPerMillisecond);
+                            track.Duration = new TimeSpan ((uint)tag.Value * TimeSpan.TicksPerMillisecond);
                         }
                         break;
                     case CommonTags.MoreInfoUri:

Modified: trunk/banshee/src/Core/Banshee.Services/Banshee.Database/BansheeDbConnection.cs
==============================================================================
--- trunk/banshee/src/Core/Banshee.Services/Banshee.Database/BansheeDbConnection.cs	(original)
+++ trunk/banshee/src/Core/Banshee.Services/Banshee.Database/BansheeDbConnection.cs	Thu Feb 28 22:03:14 2008
@@ -4,7 +4,7 @@
 // Author:
 //   Aaron Bockover <abockover novell com>
 //
-// Copyright (C) 2007 Novell, Inc.
+// Copyright (C) 2007-2008 Novell, Inc.
 //
 // Permission is hereby granted, free of charge, to any person obtaining
 // a copy of this software and associated documentation files (the
@@ -40,92 +40,35 @@
 
 namespace Banshee.Database
 {
-    public sealed class BansheeDbConnection : HyenaSqliteConnection, IService
+    public sealed class BansheeDbConnection : HyenaSqliteConnection, IInitializeService
     {
+        private BansheeDbFormatMigrator migrator;
+
         public BansheeDbConnection () : base (DatabaseFile)
         {
             Execute ("PRAGMA synchronous = OFF;");
             Execute ("PRAGMA cache_size = 32768;");
 
-            BansheeDbFormatMigrator migrator = new BansheeDbFormatMigrator (this);
-            migrator.SlowStarted += OnMigrationSlowStarted;
-            migrator.SlowPulse += OnMigrationSlowPulse;
-            migrator.SlowFinished += OnMigrationSlowFinished;
-            migrator.Migrate ();
+            migrator = new BansheeDbFormatMigrator (this);
         }
 
-        //private Gtk.Window slow_window;
-        //private Gtk.ProgressBar slow_progress;
-        
-        /*private void IterateSlow ()
+        void IInitializeService.Initialize ()
         {
-            while (Gtk.Application.EventsPending ()) {
-                Gtk.Application.RunIteration ();
+            lock (this) {
+                migrator.Migrate ();
+                migrator = null;
             }
-        }*/
-        
-        private void OnMigrationSlowStarted (string title, string message)
-        {
-           /* lock (this) {
-                if (slow_window != null) {
-                    slow_window.Destroy ();
-                }
-                
-                Gtk.Application.Init ();
-                
-                slow_window = new Gtk.Window (String.Empty);
-                slow_window.BorderWidth = 10;
-                slow_window.WindowPosition = Gtk.WindowPosition.Center;
-                slow_window.DeleteEvent += delegate (object o, Gtk.DeleteEventArgs args) {
-                    args.RetVal = true;
-                };
-                
-                Gtk.VBox box = new Gtk.VBox ();
-                box.Spacing = 5;
-                
-                Gtk.Label title_label = new Gtk.Label ();
-                title_label.Xalign = 0.0f;
-                title_label.Markup = String.Format ("<b><big>{0}</big></b>",
-                    GLib.Markup.EscapeText (title));
-                
-                Gtk.Label message_label = new Gtk.Label ();
-                message_label.Xalign = 0.0f;
-                message_label.Text = message;
-                message_label.Wrap = true;
-                
-                slow_progress = new Gtk.ProgressBar ();
-                
-                box.PackStart (title_label, false, false, 0);
-                box.PackStart (message_label, false, false, 0);
-                box.PackStart (slow_progress, false, false, 0);
-                
-                slow_window.Add (box);
-                slow_window.ShowAll ();
-                
-                IterateSlow ();
-            }*/
-        }
-        
-        private void OnMigrationSlowPulse (object o, EventArgs args)
-        {
-            /*lock (this) {
-                slow_progress.Pulse ();
-                IterateSlow ();
-            }*/
         }
-        
-        private void OnMigrationSlowFinished (object o, EventArgs args)
-        {
-            /*lock (this) {
-                slow_window.Destroy ();
-                IterateSlow ();
-            }*/
+
+        public BansheeDbFormatMigrator Migrator {
+            get { lock (this) { return migrator; } }
         }
 
         public static string DatabaseFile {
             get {
-                if (ApplicationContext.CommandLine.Contains ("db"))
+                if (ApplicationContext.CommandLine.Contains ("db")) {
                     return ApplicationContext.CommandLine["db"];
+                }
 
                 string dbfile = Path.Combine (Path.Combine (Environment.GetFolderPath (
                     Environment.SpecialFolder.ApplicationData), 

Modified: trunk/banshee/src/Core/Banshee.Services/Banshee.Database/BansheeDbFormatMigrator.cs
==============================================================================
--- trunk/banshee/src/Core/Banshee.Services/Banshee.Database/BansheeDbFormatMigrator.cs	(original)
+++ trunk/banshee/src/Core/Banshee.Services/Banshee.Database/BansheeDbFormatMigrator.cs	Thu Feb 28 22:03:14 2008
@@ -30,6 +30,7 @@
 using System.Data;
 using System.Reflection;
 using System.Threading;
+using Mono.Unix;
 
 using Hyena;
 using Hyena.Data.Sqlite;
@@ -52,6 +53,9 @@
         public event SlowStartedHandler SlowStarted;
         public event EventHandler SlowPulse;
         public event EventHandler SlowFinished;
+
+        public event EventHandler Started;
+        public event EventHandler Finished;
         
         // NOTE: Whenever there is a change in ANY of the database schema,
         //       this version MUST be incremented and a migration method
@@ -102,6 +106,22 @@
                 handler(this, EventArgs.Empty);
             }
         }
+
+        protected virtual void OnStarted ()
+        {
+            EventHandler handler = Started;
+            if (handler != null) {
+                handler (this, EventArgs.Empty);
+            }
+        }
+
+        protected virtual void OnFinished ()
+        {
+            EventHandler handler = Finished;
+            if (handler != null) {
+                handler (this, EventArgs.Empty);
+            }
+        }
         
         public void Migrate()
         {
@@ -114,17 +134,25 @@
                 Console.WriteLine(e);
                 Execute("ROLLBACK");
             }
+
+            OnFinished ();
         }
         
         private void InnerMigrate()
         {   
             MethodInfo [] methods = GetType().GetMethods(BindingFlags.Instance | BindingFlags.NonPublic);
             bool terminate = false;
+            bool ran_migration_step = false;
             
             for(int i = DatabaseVersion + 1; i <= CURRENT_VERSION; i++) {
                 foreach(MethodInfo method in methods) {
                     foreach(Attribute attr in method.GetCustomAttributes(false)) {
                         if(attr is DatabaseVersionAttribute && ((DatabaseVersionAttribute)attr).Version == i) {
+                            if (!ran_migration_step) {
+                                ran_migration_step = true;
+                                OnStarted ();
+                            }
+
                             if(!(bool)method.Invoke(this, null)) {
                                 terminate = true;
                             }
@@ -172,30 +200,32 @@
         // NOTE: Return true if the step should allow the driver to continue
         //       Return false if the step should terminate driver
         
-        [DatabaseVersion(1)]
-        private bool Migrate_1()
+        [DatabaseVersion (1)]
+        private bool Migrate_1 ()
         {   
-            if(TableExists("Tracks")) {
-                InitializeFreshDatabase();
-                
-                using(new Timer("Database Migration")) {
-                    OnSlowStarted("Upgrading your Banshee Database", 
-                        "This operation may take a few minutes, but the wait will be well worth it!");
-                
-                    Thread thread = new Thread(MigrateFromLegacyBanshee);
-                    thread.Start();
+            if (TableExists("Tracks")) {
+                InitializeFreshDatabase ();
                 
-                    while(thread.IsAlive) {
-                        OnSlowPulse();
-                        Thread.Sleep(100);
-                    }
-                
-                    OnSlowFinished();
+                uint timer_id = Log.DebugTimerStart ("Database Schema Migration");
+
+                OnSlowStarted (Catalog.GetString ("Upgrading your Banshee Database"), 
+                    Catalog.GetString ("Please wait while your old Banshee database is migrated to the new format."));
+            
+                Thread thread = new Thread (MigrateFromLegacyBanshee);
+                thread.Start ();
+            
+                while (thread.IsAlive) {
+                    OnSlowPulse ();
+                    Thread.Sleep (100);
                 }
+
+                Log.DebugTimerPrint (timer_id);
+            
+                OnSlowFinished ();
                 
                 return false;
             } else {
-                InitializeFreshDatabase();
+                InitializeFreshDatabase ();
                 return false;
             }
         }   
@@ -373,6 +403,7 @@
         
         private void MigrateFromLegacyBanshee()
         {
+            Thread.Sleep (3000);
             Execute(@"
                 INSERT INTO CoreArtists 
                     SELECT DISTINCT null, 0, null, Artist, 0 
@@ -452,7 +483,7 @@
             if (args.Service is UserJobManager) {
                 ServiceManager.ServiceStarted -= OnServiceStarted;
                 if (ServiceManager.SourceManager.Library != null) {
-                    RefreshMetadata ();
+                    Application.RunTimeout (3000, RefreshMetadata);
                 } else {
                     ServiceManager.SourceManager.SourceAdded += OnSourceAdded;
                 }
@@ -463,32 +494,36 @@
         {
             if (args.Source is Banshee.Library.LibrarySource) {
                 ServiceManager.SourceManager.SourceAdded -= OnSourceAdded;
-                RefreshMetadata ();
+                RefreshMetadataDelayed ();
             }
         }
 
-        private void RefreshMetadata ()
+        private void RefreshMetadataDelayed ()
         {
-            OnSlowStarted("Getting new metadata for existing tracks", 
-                "This operation may take a few minutes, but the wait will be well worth it!");
-        
-            Thread thread = new Thread (RefreshMetadataJob);
-            thread.Start();
-        
-            while (thread.IsAlive) {
-                OnSlowPulse ();
-                Thread.Sleep (100);
-            }
-        
-            OnSlowFinished();
+            Application.RunTimeout (3000, RefreshMetadata);
         }
 
-        private void RefreshMetadataJob ()
+        private bool RefreshMetadata ()
+        {
+            ThreadPool.QueueUserWorkItem (RefreshMetadataThread);
+            return false;
+        }
+
+        private void RefreshMetadataThread (object state)
         {
             Banshee.Library.LibrarySource library = ServiceManager.SourceManager.Library;
             int total = ServiceManager.DbConnection.Query<int> ("SELECT count(*) FROM CoreTracks WHERE SourceID = 1");
             long now = DateTimeUtil.FromDateTime (DateTime.Now);
 
+            if (total <= 0) {
+                return;
+            }
+
+            UserJob job = new UserJob (Catalog.GetString ("Refreshing Metadata"));
+            job.Status = Catalog.GetString ("Scanning...");
+            job.IconNames = new string [] { "system-search", "gtk-find" };
+            job.Register ();
+
             HyenaSqliteCommand select_command = new HyenaSqliteCommand (
                 String.Format (
                     "SELECT {0} FROM {1} WHERE {2} AND CoreTracks.SourceID = 1",
@@ -505,15 +540,23 @@
                     try {
                         track = DatabaseTrackInfo.Provider.Load (reader, 0);
                         TagLib.File file = StreamTagger.ProcessUri (track.Uri);
-                        StreamTagger.TrackInfoMerge (track, file);
+                        StreamTagger.TrackInfoMerge (track, file, true);
                         track.Save ();
+
+                        job.Status = String.Format ("{0} - {1}", track.DisplayArtistName, track.DisplayTrackTitle);
                     } catch (Exception e) {
-                        Log.Warning (String.Format ("Failed to update metadata for {0}", track.Uri), e.GetType ().ToString ());
+                        Log.Warning (String.Format ("Failed to update metadata for {0}", track),
+                            e.GetType ().ToString (), false);
                     }
+
+                    job.Progress = (double)++count / (double)total;
                 }
             }
+
+            job.Finish ();
         }
         
 #endregion
+
     }
 }

Added: trunk/banshee/src/Core/Banshee.Services/Banshee.ServiceStack/IInitializeService.cs
==============================================================================
--- (empty file)
+++ trunk/banshee/src/Core/Banshee.Services/Banshee.ServiceStack/IInitializeService.cs	Thu Feb 28 22:03:14 2008
@@ -0,0 +1,37 @@
+//
+// IInitializeService.cs
+//
+// Author:
+//   Aaron Bockover <abockover novell com>
+//
+// Copyright (C) 2008 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.ServiceStack
+{
+    public interface IInitializeService : IService
+    {
+        void Initialize ();
+    }
+}

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	Thu Feb 28 22:03:14 2008
@@ -103,6 +103,10 @@
                     if (service is IDisposable) {
                         dispose_services.Push (service);
                     }
+
+                    if (service is IInitializeService) {
+                        ((IInitializeService)service).Initialize ();
+                    }
                 }
                 
                 foreach (TypeExtensionNode node in extension_nodes) {

Modified: trunk/banshee/src/Core/Banshee.Services/Banshee.ServiceStack/UserJob.cs
==============================================================================
--- trunk/banshee/src/Core/Banshee.Services/Banshee.ServiceStack/UserJob.cs	(original)
+++ trunk/banshee/src/Core/Banshee.Services/Banshee.ServiceStack/UserJob.cs	Thu Feb 28 22:03:14 2008
@@ -55,12 +55,11 @@
         public UserJob (string name, string title, string status) : this (name, title, status, null)
         {
         }
-        
-        /*public UserJob (string name, string title, string status, string iconName)
-            : this (name, title, status, new string [] { iconName })
+
+        public UserJob (string name) : this (name, name, null, null)
         {
-        }*/
-        
+        }
+
         public UserJob (string name, string title, string status, params string [] iconNames)
         {
             FreezeUpdate ();

Modified: trunk/banshee/src/Core/Banshee.Services/Banshee.Services.mdp
==============================================================================
--- trunk/banshee/src/Core/Banshee.Services/Banshee.Services.mdp	(original)
+++ trunk/banshee/src/Core/Banshee.Services/Banshee.Services.mdp	Thu Feb 28 22:03:14 2008
@@ -124,6 +124,7 @@
     <File name="Banshee.MediaEngine/NullPlayerEngine.cs" subtype="Code" buildaction="Compile" />
     <File name="Banshee.PlayerMigration/AmarokPlayerImportSource.cs" subtype="Code" buildaction="Compile" />
     <File name="Banshee.Library/ThreadPoolImportSource.cs" subtype="Code" buildaction="Compile" />
+    <File name="Banshee.ServiceStack/IInitializeService.cs" subtype="Code" buildaction="Compile" />
   </Contents>
   <References>
     <ProjectReference type="Gac" localcopy="True" refto="System, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089" />
@@ -138,7 +139,6 @@
     <ProjectReference type="Gac" localcopy="True" refto="glib-sharp, Version=2.10.0.0, Culture=neutral, PublicKeyToken=35e10195dab3c99f" />
     <ProjectReference type="Gac" localcopy="True" refto="TagLib, Version=0.0.0.0, Culture=neutral" />
   </References>
-  <Deployment.LinuxDeployData generateScript="False" />
   <MonoDevelop.Autotools.MakefileInfo IntegrationEnabled="True" RelativeMakefileName="Makefile.am">
     <BuildFilesVar Sync="True" Name="SOURCES" />
     <DeployFilesVar />
@@ -148,4 +148,5 @@
     <AsmRefVar />
     <ProjectRefVar />
   </MonoDevelop.Autotools.MakefileInfo>
+  <Deployment.LinuxDeployData generateScript="False" />
 </Project>
\ No newline at end of file

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	Thu Feb 28 22:03:14 2008
@@ -91,6 +91,7 @@
 	Banshee.ServiceStack/DBusServiceManager.cs \
 	Banshee.ServiceStack/IDBusExportable.cs \
 	Banshee.ServiceStack/IExtensionService.cs \
+	Banshee.ServiceStack/IInitializeService.cs \
 	Banshee.ServiceStack/IService.cs \
 	Banshee.ServiceStack/IUserJob.cs \
 	Banshee.ServiceStack/ServiceManager.cs \

Modified: trunk/banshee/src/Core/Banshee.ThickClient/Banshee.Collection.Gui/ColumnCellAlbum.cs
==============================================================================
--- trunk/banshee/src/Core/Banshee.ThickClient/Banshee.Collection.Gui/ColumnCellAlbum.cs	(original)
+++ trunk/banshee/src/Core/Banshee.ThickClient/Banshee.Collection.Gui/ColumnCellAlbum.cs	Thu Feb 28 22:03:14 2008
@@ -78,7 +78,7 @@
             }
             
             ArtworkRenderer.RenderThumbnail (context.Context, pixbuf, true, x, y, pixbuf_size, pixbuf_size, 
-                !is_default, ListViewGraphics.BorderRadius);
+                !is_default, context.Theme.Context.Radius);
                 
             int fl_width = 0, fl_height = 0, sl_width = 0, sl_height = 0;
             

Modified: trunk/banshee/src/Core/Banshee.ThickClient/Banshee.Collection.Gui/TrackListView.cs
==============================================================================
--- trunk/banshee/src/Core/Banshee.ThickClient/Banshee.Collection.Gui/TrackListView.cs	(original)
+++ trunk/banshee/src/Core/Banshee.ThickClient/Banshee.Collection.Gui/TrackListView.cs	Thu Feb 28 22:03:14 2008
@@ -28,8 +28,10 @@
 
 using System;
 using Mono.Unix;
+using Cairo;
 using Gtk;
 
+using Hyena.Gui;
 using Hyena.Data.Gui;
 
 using Banshee.Gui;
@@ -101,6 +103,23 @@
         {
             QueueDraw ();
         }
+
+        protected override void ChildClassPostRender (Gdk.EventExpose evnt, Cairo.Context cr, Gdk.Rectangle clip)
+        {
+            Gdk.Rectangle rect = new Gdk.Rectangle ();
+            rect.Width = (int)Math.Round (Allocation.Width * 0.65);
+            rect.Height = (int)Math.Round (Allocation.Height * 0.50);
+            rect.X = (Allocation.Width - rect.Width) / 2;
+            rect.Y = ((Allocation.Height - rect.Height) / 2) - (int)(rect.Height * .15);
+
+            CairoExtensions.PushGroup (cr);
+            Theme.PushContext ();
+            Theme.Context.Radius = 12;
+            Theme.DrawFrame (cr, rect, true);
+            Theme.PopContext ();
+            CairoExtensions.PopGroupToSource (cr);
+            cr.PaintWithAlpha (0.8);
+        }
         
 #region Drag and Drop
 

Added: trunk/banshee/src/Core/Banshee.ThickClient/Banshee.Gui/BansheeDbFormatMigratorMonitor.cs
==============================================================================
--- (empty file)
+++ trunk/banshee/src/Core/Banshee.ThickClient/Banshee.Gui/BansheeDbFormatMigratorMonitor.cs	Thu Feb 28 22:03:14 2008
@@ -0,0 +1,130 @@
+//
+// BansheeDbFormatMigratorMonitor.cs
+//
+// Author:
+//   Aaron Bockover <abockover novell com>
+//
+// Copyright (C) 2008 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;
+using Gtk;
+
+using Banshee.Database;
+
+namespace Banshee.Gui
+{
+    public class BansheeDbFormatMigratorMonitor
+    {
+        private Gtk.Window slow_window;
+        private Gtk.ProgressBar slow_progress;
+
+        private BansheeDbFormatMigrator migrator;
+
+        public BansheeDbFormatMigratorMonitor (BansheeDbFormatMigrator migrator)
+        {
+            if (migrator == null) {
+                return;
+            }
+
+            this.migrator = migrator;
+            migrator.Finished += OnMigrationFinished;
+            migrator.SlowStarted += OnMigrationSlowStarted;
+            migrator.SlowPulse += OnMigrationSlowPulse;
+            migrator.SlowFinished += OnMigrationSlowFinished;
+        }
+
+        private void OnMigrationFinished (object o, EventArgs args)
+        {
+            migrator.Finished -= OnMigrationFinished;
+            migrator.SlowStarted -= OnMigrationSlowStarted;
+            migrator.SlowPulse -= OnMigrationSlowPulse;
+            migrator.SlowFinished -= OnMigrationSlowFinished;
+            migrator = null;
+        }
+        
+        private void IterateSlow ()
+        {
+            while (Gtk.Application.EventsPending ()) {
+                Gtk.Application.RunIteration ();
+            }
+        }
+        
+        private void OnMigrationSlowStarted (string title, string message)
+        {
+            lock (this) {
+                if (slow_window != null) {
+                    slow_window.Destroy ();
+                }
+                
+                Gtk.Application.Init ();
+                
+                slow_window = new Gtk.Window (String.Empty);
+                slow_window.BorderWidth = 10;
+                slow_window.WindowPosition = Gtk.WindowPosition.Center;
+                slow_window.DeleteEvent += delegate (object o, Gtk.DeleteEventArgs args) {
+                    args.RetVal = true;
+                };
+                
+                Gtk.VBox box = new Gtk.VBox ();
+                box.Spacing = 5;
+                
+                Gtk.Label title_label = new Gtk.Label ();
+                title_label.Xalign = 0.0f;
+                title_label.Markup = String.Format ("<b><big>{0}</big></b>",
+                    GLib.Markup.EscapeText (title));
+                
+                Gtk.Label message_label = new Gtk.Label ();
+                message_label.Xalign = 0.0f;
+                message_label.Text = message;
+                message_label.Wrap = true;
+                
+                slow_progress = new Gtk.ProgressBar ();
+                
+                box.PackStart (title_label, false, false, 0);
+                box.PackStart (message_label, false, false, 0);
+                box.PackStart (slow_progress, false, false, 0);
+                
+                slow_window.Add (box);
+                slow_window.ShowAll ();
+                
+                IterateSlow ();
+            }
+        }
+        
+        private void OnMigrationSlowPulse (object o, EventArgs args)
+        {
+            lock (this) {
+                slow_progress.Pulse ();
+                IterateSlow ();
+            }
+        }
+        
+        private void OnMigrationSlowFinished (object o, EventArgs args)
+        {
+            lock (this) {
+                slow_window.Destroy ();
+                IterateSlow ();
+            }
+        }
+    }
+}

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	Thu Feb 28 22:03:14 2008
@@ -30,6 +30,7 @@
 
 using Hyena;
 using Banshee.Base;
+using Banshee.Database;
 using Banshee.ServiceStack;
 using Banshee.Gui.Dialogs;
 
@@ -80,6 +81,8 @@
             ThreadAssist.InitializeMainThread ();
             
             PlatformHacks.GdkSetProgramClass (Application.InternalName);
+
+            ServiceManager.ServiceStarted += OnServiceStarted;
             
             // Register specific services this client will care about
             if (registerCommonServices) {
@@ -107,7 +110,32 @@
         protected virtual void OnRegisterServices ()
         {
         }
+
+        private void OnServiceStarted (ServiceStartedArgs args)
+        {
+            if (args.Service is BansheeDbConnection) {
+                ServiceManager.ServiceStarted -= OnServiceStarted;
+                BansheeDbFormatMigrator migrator = ((BansheeDbConnection)args.Service).Migrator;
+                if (migrator != null) {
+                    migrator.Started += OnMigratorStarted;
+                    migrator.Finished += OnMigratorFinished;
+                }
+            }
+        }
         
+        private void OnMigratorStarted (object o, EventArgs args)
+        {
+            BansheeDbFormatMigrator migrator = (BansheeDbFormatMigrator)o;
+            new BansheeDbFormatMigratorMonitor (migrator);
+        }
+
+        private void OnMigratorFinished (object o, EventArgs args)
+        {
+            BansheeDbFormatMigrator migrator = (BansheeDbFormatMigrator)o;
+            migrator.Started -= OnMigratorStarted;
+            migrator.Finished -= OnMigratorFinished;
+        }
+
         private void OnLogNotify (LogNotifyArgs args)
         {
             RunIdle (delegate {
@@ -121,8 +149,8 @@
             Gtk.Window window = null;
             Gtk.MessageType mtype;
             
-            if (ServiceManager.Contains ("GtkElementsService")) {
-                window = ServiceManager.Get<GtkElementsService> ("GtkElementsService").PrimaryWindow;
+            if (ServiceManager.Contains<GtkElementsService> ()) {
+                window = ServiceManager.Get<GtkElementsService> ().PrimaryWindow;
             }
             
             switch (entry.Type) {

Modified: trunk/banshee/src/Core/Banshee.ThickClient/Banshee.Sources.Gui/SourceRowRenderer.cs
==============================================================================
--- trunk/banshee/src/Core/Banshee.ThickClient/Banshee.Sources.Gui/SourceRowRenderer.cs	(original)
+++ trunk/banshee/src/Core/Banshee.ThickClient/Banshee.Sources.Gui/SourceRowRenderer.cs	Thu Feb 28 22:03:14 2008
@@ -32,7 +32,7 @@
 using Gdk;
 using Pango;
 
-using Hyena.Data.Gui;
+using Hyena.Gui.Theming;
 using Hyena.Gui.Theatrics;
 
 using Banshee.ServiceStack;
@@ -89,20 +89,20 @@
                 
                 // draw the hot cairo selection
                 if (!view.EditingRow) { 
-                    view.Graphics.DrawRowSelection (view.Cr, background_area.X + 1, background_area.Y + 1, 
+                    view.Theme.DrawRowSelection (view.Cr, background_area.X + 1, background_area.Y + 1, 
                         background_area.Width - 2, background_area.Height - 2);
                 }
             } else if (path != null && path.Equals (view.HighlightedPath) && view.Cr != null) {
-                view.Graphics.DrawRowSelection (view.Cr, background_area.X + 1, background_area.Y + 1, 
+                view.Theme.DrawRowSelection (view.Cr, background_area.X + 1, background_area.Y + 1, 
                     background_area.Width - 2, background_area.Height - 2, false);
             } else if (view.NotifyStage.ActorCount > 0 && view.Cr != null) {
                 TreeIter iter;
                 if (view.Model.GetIter (out iter, path) && view.NotifyStage.Contains (iter)) {
                     Actor<TreeIter> actor = view.NotifyStage[iter];
-                    Cairo.Color color = view.Graphics.GetWidgetColor (GtkColorClass.Background, StateType.Active);
+                    Cairo.Color color = view.Theme.Colors.GetWidgetColor (GtkColorClass.Background, StateType.Active);
                     color.A = Math.Sin (actor.Percent * Math.PI);
                         
-                    view.Graphics.DrawRowSelection (view.Cr, background_area.X + 1, background_area.Y + 1, 
+                    view.Theme.DrawRowSelection (view.Cr, background_area.X + 1, background_area.Y + 1, 
                         background_area.Width - 2, background_area.Height - 2, true, true, color);
                 }
             }

Modified: trunk/banshee/src/Core/Banshee.ThickClient/Banshee.Sources.Gui/SourceView.cs
==============================================================================
--- trunk/banshee/src/Core/Banshee.ThickClient/Banshee.Sources.Gui/SourceView.cs	(original)
+++ trunk/banshee/src/Core/Banshee.ThickClient/Banshee.Sources.Gui/SourceView.cs	Thu Feb 28 22:03:14 2008
@@ -32,7 +32,7 @@
 using Gtk;
 using Cairo;
 
-using Hyena.Data.Gui;
+using Hyena.Gui.Theming;
 using Hyena.Gui.Theatrics;
 
 using Banshee.ServiceStack;
@@ -50,7 +50,7 @@
     public partial class SourceView : TreeView
     {
         private SourceRowRenderer renderer;
-        private ListViewGraphics graphics;
+        private Theme theme;
         private Cairo.Context cr;
         
         private Stage<TreeIter> notify_stage = new Stage<TreeIter> (2000);
@@ -140,8 +140,8 @@
         {
             base.OnRealized ();
             
-            graphics = new ListViewGraphics (this);
-            graphics.RefreshColors ();
+            theme = new GtkTheme (this);
+            // theme.RefreshColors ();
         }
 
         protected override bool OnButtonPressEvent (Gdk.EventButton press)
@@ -542,8 +542,8 @@
             get { return cr; }
         }
         
-        internal ListViewGraphics Graphics {
-            get { return graphics; }
+        internal Theme Theme {
+            get { return theme; }
         }
         
         internal Stage<TreeIter> NotifyStage {

Modified: trunk/banshee/src/Core/Banshee.ThickClient/Banshee.ThickClient.mdp
==============================================================================
--- trunk/banshee/src/Core/Banshee.ThickClient/Banshee.ThickClient.mdp	(original)
+++ trunk/banshee/src/Core/Banshee.ThickClient/Banshee.ThickClient.mdp	Thu Feb 28 22:03:14 2008
@@ -99,6 +99,7 @@
     <File name="Resources/media-repeat-single.png" subtype="Code" buildaction="EmbedAsResource" />
     <File name="Banshee.Gui.Widgets/RepeatActionButton.cs" subtype="Code" buildaction="Compile" />
     <File name="Banshee.Gui/PlaybackRepeatActions.cs" subtype="Code" buildaction="Compile" />
+    <File name="Banshee.Gui/BansheeDbFormatMigratorMonitor.cs" subtype="Code" buildaction="Compile" />
   </Contents>
   <References>
     <ProjectReference type="Project" localcopy="False" refto="Hyena.Gui" />
@@ -114,7 +115,6 @@
     <ProjectReference type="Gac" localcopy="True" refto="glib-sharp, Version=2.10.0.0, Culture=neutral, PublicKeyToken=35e10195dab3c99f" />
     <ProjectReference type="Gac" localcopy="True" refto="pango-sharp, Version=2.10.0.0, Culture=neutral, PublicKeyToken=35e10195dab3c99f" />
   </References>
-  <Deployment.LinuxDeployData generateScript="False" />
   <MonoDevelop.Autotools.MakefileInfo IntegrationEnabled="True" RelativeMakefileName="Makefile.am">
     <BuildFilesVar Sync="True" Name="SOURCES" />
     <DeployFilesVar />
@@ -124,4 +124,5 @@
     <AsmRefVar />
     <ProjectRefVar />
   </MonoDevelop.Autotools.MakefileInfo>
+  <Deployment.LinuxDeployData generateScript="False" />
 </Project>
\ No newline at end of file

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	Thu Feb 28 22:03:14 2008
@@ -49,6 +49,7 @@
 	Banshee.Gui.Widgets/UserJobTile.cs \
 	Banshee.Gui.Widgets/UserJobTileHost.cs \
 	Banshee.Gui/BansheeActionGroup.cs \
+	Banshee.Gui/BansheeDbFormatMigratorMonitor.cs \
 	Banshee.Gui/BansheeIconFactory.cs \
 	Banshee.Gui/BaseClientWindow.cs \
 	Banshee.Gui/CommonServices.cs \

Modified: trunk/banshee/src/Libraries/Hyena.Gui/Hyena.Data.Gui/CellContext.cs
==============================================================================
--- trunk/banshee/src/Libraries/Hyena.Gui/Hyena.Data.Gui/CellContext.cs	(original)
+++ trunk/banshee/src/Libraries/Hyena.Gui/Hyena.Data.Gui/CellContext.cs	Thu Feb 28 22:03:14 2008
@@ -28,6 +28,8 @@
 
 using System;
 
+using Hyena.Gui.Theming;
+
 namespace Hyena.Data.Gui
 {
     public class CellContext
@@ -36,17 +38,17 @@
         private Pango.Layout layout;
         private Gtk.Widget widget;
         private Gdk.Drawable drawable;
-        private ListViewGraphics graphics;
+        private Theme theme;
         private Gdk.Rectangle area;
         
         public CellContext (Cairo.Context context, Pango.Layout layout, Gtk.Widget widget,
-            Gdk.Drawable drawable, ListViewGraphics graphics, Gdk.Rectangle area)
+            Gdk.Drawable drawable, Theme theme, Gdk.Rectangle area)
         {
             this.context = context;
             this.layout = layout;
             this.widget = widget;
             this.drawable = drawable;
-            this.graphics = graphics;
+            this.theme = theme;
             this.area = area;
         }
         
@@ -66,8 +68,8 @@
             get { return drawable; }
         }
 
-        public ListViewGraphics Graphics {
-            get { return graphics; }
+        public Theme Theme {
+            get { return theme; }
         }
 
         public Gdk.Rectangle Area {

Modified: trunk/banshee/src/Libraries/Hyena.Gui/Hyena.Data.Gui/ColumnCellText.cs
==============================================================================
--- trunk/banshee/src/Libraries/Hyena.Gui/Hyena.Data.Gui/ColumnCellText.cs	(original)
+++ trunk/banshee/src/Libraries/Hyena.Gui/Hyena.Data.Gui/ColumnCellText.cs	Thu Feb 28 22:03:14 2008
@@ -30,6 +30,8 @@
 using Gtk;
 using Cairo;
 
+using Hyena.Gui.Theming;
+
 namespace Hyena.Data.Gui
 {
     public class ColumnCellText : ColumnCell
@@ -59,7 +61,7 @@
             if (use_cairo_pango) {
                 context.Context.MoveTo (4, ((int)cellHeight - text_height) / 2);
                 Pango.CairoHelper.LayoutPath (context.Context, context.Layout);
-                context.Context.Color = context.Graphics.GetWidgetColor (GtkColorClass.Text, state);
+                context.Context.Color = context.Theme.Colors.GetWidgetColor (GtkColorClass.Text, state);
                 context.Context.Fill ();
             } else {
                 Style.PaintLayout(context.Widget.Style, context.Drawable, state, true, context.Area,

Modified: trunk/banshee/src/Libraries/Hyena.Gui/Hyena.Data.Gui/ListView/ListView_Rendering.cs
==============================================================================
--- trunk/banshee/src/Libraries/Hyena.Gui/Hyena.Data.Gui/ListView/ListView_Rendering.cs	(original)
+++ trunk/banshee/src/Libraries/Hyena.Gui/Hyena.Data.Gui/ListView/ListView_Rendering.cs	Thu Feb 28 22:03:14 2008
@@ -33,6 +33,8 @@
 using Cairo;
 
 using Hyena.Gui;
+using Hyena.Gui.Theming;
+using GtkColorClass=Hyena.Gui.Theming.GtkColorClass;
 
 namespace Hyena.Data.Gui
 {
@@ -41,8 +43,11 @@
         private const int InnerBorderWidth = 4;
         private const int FooterHeight = InnerBorderWidth;
         
-        private ListViewGraphics graphics;
-        
+        private Theme theme;
+        protected Theme Theme {
+            get { return theme; }
+        }
+
         private Cairo.Context list_cr;
         private Cairo.Context header_cr;
         private Cairo.Context footer_cr;
@@ -51,7 +56,7 @@
         
         private Pango.Layout header_pango_layout;
         private Pango.Layout list_pango_layout;
-        
+
         public new void QueueDraw ()
         {
             base.QueueDraw ();
@@ -60,6 +65,10 @@
             InvalidateListWindow ();
             InvalidateFooterWindow ();
         }
+
+        protected virtual void ChildClassPostRender (Gdk.EventExpose evnt, Cairo.Context cr, Gdk.Rectangle clip)
+        {
+        }
          
         protected override bool OnExposeEvent (Gdk.EventExpose evnt)
         {            
@@ -75,7 +84,7 @@
             Cairo.Context cr = CairoHelper.CreateCairoDrawable (evnt.Window);
             cr.Rectangle (clip.X, clip.Y, clip.Width, clip.Height);
             cr.Clip ();
-            
+
             if (evnt.Window == header_window) {
                 header_cr = cr;
                 if (header_pango_layout == null) {
@@ -98,6 +107,8 @@
                 }
                 PaintList (evnt, clip);
             }
+
+            ChildClassPostRender (evnt, cr, clip);
             
             ((IDisposable)cr.Target).Dispose ();
             ((IDisposable)cr).Dispose ();
@@ -105,7 +116,7 @@
         
         private void PaintHeader (Gdk.Rectangle clip)
         {
-            graphics.DrawHeaderBackground (header_cr, header_alloc, 2, header_visible);
+            Theme.DrawHeaderBackground (header_cr, header_alloc, 2, header_visible);
             
             if (column_controller == null || !header_visible) {
                 return;
@@ -138,14 +149,14 @@
             
             if (dragging) {
                 if (ci < column_cache.Length - 1) {
-                    graphics.DrawHeaderSeparator (header_cr, header_alloc, 
+                    Theme.DrawHeaderSeparator (header_cr, header_alloc, 
                         column_cache[ci].ResizeX1 - 1 + left_border_alloc.Width, 2);
                 }
             
-                graphics.DrawColumnHighlight (header_cr, area, 3, 
-                    CairoExtensions.ColorShade (graphics.GetWidgetColor (GtkColorClass.Dark, StateType.Normal), 0.9));
+                Theme.DrawColumnHighlight (header_cr, area, 3, 
+                    CairoExtensions.ColorShade (Theme.Colors.GetWidgetColor (GtkColorClass.Dark, StateType.Normal), 0.9));
                     
-                Cairo.Color stroke_color = CairoExtensions.ColorShade (graphics.GetWidgetColor (
+                Cairo.Color stroke_color = CairoExtensions.ColorShade (Theme.Colors.GetWidgetColor (
                     GtkColorClass.Base, StateType.Normal), 0.0);
                 stroke_color.A = 0.3;
                 
@@ -162,7 +173,7 @@
                     && column_cache[ci].Column is ISortableColumn;
                 ((ColumnHeaderCellText)cell).HasSort = has_sort;
                 if (has_sort) {
-                    graphics.DrawColumnHighlight (header_cr, area, 3);
+                    Theme.DrawColumnHighlight (header_cr, area, 3);
                 }
             }
             
@@ -170,12 +181,12 @@
                 header_cr.Save ();
                 header_cr.Translate (area.X, area.Y);
                 cell.Render (new CellContext (header_cr, header_pango_layout, this, header_window, 
-                    graphics, area), StateType.Normal, area.Width, area.Height);
+                    theme, area), StateType.Normal, area.Width, area.Height);
                 header_cr.Restore ();
             }
             
             if (!dragging && ci < column_cache.Length - 1) {
-                graphics.DrawHeaderSeparator (header_cr, header_alloc, 
+                Theme.DrawHeaderSeparator (header_cr, header_alloc, 
                     column_cache[ci].ResizeX1 - 1 + left_border_alloc.Width, 2);
             }
         }
@@ -216,7 +227,7 @@
                     }
                 } else {
                     if (rules_hint && ri % 2 != 0) {
-                        graphics.DrawRowRule (list_cr, single_list_alloc.X, single_list_alloc.Y, 
+                        Theme.DrawRowRule (list_cr, single_list_alloc.X, single_list_alloc.Y, 
                             single_list_alloc.Width, single_list_alloc.Height);
                     }
                     
@@ -231,13 +242,13 @@
                             corners ^= CairoCorners.BottomLeft | CairoCorners.BottomRight;
                         }
                         
-                        graphics.DrawRowSelection (list_cr, single_list_alloc.X, single_list_alloc.Y, 
+                        Theme.DrawRowSelection (list_cr, single_list_alloc.X, single_list_alloc.Y, 
                             single_list_alloc.Width, single_list_alloc.Height, false, true, 
-                            graphics.GetWidgetColor (GtkColorClass.Background, StateType.Selected), corners);
+                            Theme.Colors.GetWidgetColor (GtkColorClass.Background, StateType.Selected), corners);
                     }
                     
                     if (selection_height > 0) {
-                        graphics.DrawRowSelection (
+                        Theme.DrawRowSelection (
                             list_cr, list_alloc.X, list_alloc.Y + selection_y, list_alloc.Width, selection_height);
                         selection_height = 0;
                     }
@@ -249,14 +260,14 @@
             }
             
             if (selection_height > 0) {
-                graphics.DrawRowSelection (list_cr, list_alloc.X, list_alloc.Y + selection_y, 
+                Theme.DrawRowSelection (list_cr, list_alloc.X, list_alloc.Y + selection_y, 
                     list_alloc.Width, selection_height);
             }
             
             if (Selection.Count > 1 && !selected_focus_alloc.Equals (Gdk.Rectangle.Zero) && HasFocus) {
-                graphics.DrawRowSelection (list_cr, selected_focus_alloc.X, selected_focus_alloc.Y, 
+                Theme.DrawRowSelection (list_cr, selected_focus_alloc.X, selected_focus_alloc.Y, 
                     selected_focus_alloc.Width, selected_focus_alloc.Height, false, true, 
-                    graphics.GetWidgetColor (GtkColorClass.Dark, StateType.Selected));
+                    Theme.Colors.GetWidgetColor (GtkColorClass.Dark, StateType.Selected));
             }
             
             foreach (int ri in selected_rows) {
@@ -304,7 +315,7 @@
             cell.BindListItem (item);
             
             if (dragging) {
-                Cairo.Color fill_color = graphics.GetWidgetColor (GtkColorClass.Base, StateType.Normal);
+                Cairo.Color fill_color = Theme.Colors.GetWidgetColor (GtkColorClass.Base, StateType.Normal);
                 fill_color.A = 0.5;
                 list_cr.Color = fill_color;
                 list_cr.Rectangle (area.X, area.Y, area.Width, area.Height);
@@ -313,7 +324,7 @@
             
             list_cr.Save ();
             list_cr.Translate (clip.X, clip.Y);
-            cell.Render (new CellContext (list_cr, list_pango_layout, this, list_window, graphics, area), 
+            cell.Render (new CellContext (list_cr, list_pango_layout, this, list_window, theme, area), 
                 dragging? StateType.Normal : state, area.Width, area.Height);
             list_cr.Restore ();
         }
@@ -328,10 +339,10 @@
             
             int x = pressed_column_x_drag;
             
-            Cairo.Color fill_color = graphics.GetWidgetColor (GtkColorClass.Base, StateType.Normal);
+            Cairo.Color fill_color = Theme.Colors.GetWidgetColor (GtkColorClass.Base, StateType.Normal);
             fill_color.A = 0.45;
             
-            Cairo.Color stroke_color = CairoExtensions.ColorShade (graphics.GetWidgetColor (
+            Cairo.Color stroke_color = CairoExtensions.ColorShade (Theme.Colors.GetWidgetColor (
                 GtkColorClass.Base, StateType.Normal), 0.0);
             stroke_color.A = 0.3;
             
@@ -352,17 +363,17 @@
         
         private void PaintLeftBorder (Gdk.EventExpose evnt, Gdk.Rectangle clip)
         {
-            graphics.DrawLeftBorder (left_border_cr, left_border_alloc);
+            Theme.DrawLeftBorder (left_border_cr, left_border_alloc);
         }
         
         private void PaintRightBorder (Gdk.EventExpose evnt, Gdk.Rectangle clip)
         {
-            graphics.DrawRightBorder (right_border_cr, right_border_alloc);
+            Theme.DrawRightBorder (right_border_cr, right_border_alloc);
         }
         
         private void PaintFooter (Gdk.EventExpose evnt, Gdk.Rectangle clip)
         {
-            graphics.DrawFooter (footer_cr, footer_alloc);
+            Theme.DrawFooter (footer_cr, footer_alloc);
         }
         
         protected void InvalidateListWindow ()

Modified: trunk/banshee/src/Libraries/Hyena.Gui/Hyena.Data.Gui/ListView/ListView_Windowing.cs
==============================================================================
--- trunk/banshee/src/Libraries/Hyena.Gui/Hyena.Data.Gui/ListView/ListView_Windowing.cs	(original)
+++ trunk/banshee/src/Libraries/Hyena.Gui/Hyena.Data.Gui/ListView/ListView_Windowing.cs	Thu Feb 28 22:03:14 2008
@@ -29,6 +29,8 @@
 using System;
 using Gtk;
 
+using Hyena.Gui.Theming;
+
 namespace Hyena.Data.Gui
 {
     public partial class ListView<T> : Container
@@ -155,9 +157,9 @@
             
             MoveResizeWindows (Allocation);
             
-            // graphics context for drawing theme parts
-            graphics = new ListViewGraphics (this);
-            graphics.RefreshColors ();
+            // context for drawing theme parts
+            theme = new GtkTheme (this);
+            //graphics.RefreshColors ();
             
             OnDragSourceSet ();
         }

Added: trunk/banshee/src/Libraries/Hyena.Gui/Hyena.Gui.Theming/GtkColors.cs
==============================================================================
--- (empty file)
+++ trunk/banshee/src/Libraries/Hyena.Gui/Hyena.Gui.Theming/GtkColors.cs	Thu Feb 28 22:03:14 2008
@@ -0,0 +1,148 @@
+//
+// GtkColors.cs
+//
+// Author:
+//   Aaron Bockover <abockover novell com>
+//
+// Copyright (C) 2007-2008 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;
+using Cairo;
+using Gtk;
+
+namespace Hyena.Gui.Theming
+{
+    public enum GtkColorClass 
+    {
+        Light,
+        Mid,
+        Dark,
+        Base,
+        Text,
+        Background,
+        Foreground
+    }
+
+    public class GtkColors
+    {
+        private Cairo.Color [] gtk_colors;
+        private Widget widget;
+        private bool refreshing = false;
+
+        public event EventHandler Refreshed;
+
+        public Widget Widget {
+            get { return widget; }
+            set { 
+                if (widget == value) {
+                    return;
+                } else if (widget != null) {
+                    widget.Realized -= OnWidgetRealized;
+                    widget.StyleSet -= OnWidgetStyleSet;
+                }
+
+                widget = value;
+
+                if (widget.IsRealized) {
+                    RefreshColors ();
+                }
+
+                widget.Realized += OnWidgetRealized;
+                widget.StyleSet += OnWidgetStyleSet;
+            }
+        }
+
+        public GtkColors ()
+        {
+        }
+
+        private void OnWidgetRealized (object o, EventArgs args)
+        {
+            RefreshColors ();
+        }
+
+        private void OnWidgetStyleSet (object o, StyleSetArgs args)
+        {
+            RefreshColors ();
+        }
+        
+        public Cairo.Color GetWidgetColor (GtkColorClass @class, StateType state)
+        {
+            if (gtk_colors == null) {
+                RefreshColors ();
+            }
+            
+            return gtk_colors[(int)@class * ((int)StateType.Insensitive + 1) + (int)state];
+        }
+        
+        public void RefreshColors ()
+        {
+            if (refreshing) {
+                return;
+            }
+            
+            refreshing = true;
+            
+            int sn = (int)StateType.Insensitive + 1;
+            int cn = (int)GtkColorClass.Foreground + 1;
+            
+            if (gtk_colors == null) {
+                gtk_colors = new Cairo.Color[sn * cn];
+            }
+                
+            for (int c = 0, i = 0; c < cn; c++) {
+                for (int s = 0; s < sn; s++, i++) {
+                    Gdk.Color color = Gdk.Color.Zero;
+                    
+                    if (widget != null && widget.IsRealized) {
+                        switch ((GtkColorClass)c) {
+                            case GtkColorClass.Light:      color = widget.Style.LightColors[s]; break;
+                            case GtkColorClass.Mid:        color = widget.Style.MidColors[s];   break;
+                            case GtkColorClass.Dark:       color = widget.Style.DarkColors[s];  break;
+                            case GtkColorClass.Base:       color = widget.Style.BaseColors[s];  break;
+                            case GtkColorClass.Text:       color = widget.Style.TextColors[s];  break;
+                            case GtkColorClass.Background: color = widget.Style.Backgrounds[s]; break;
+                            case GtkColorClass.Foreground: color = widget.Style.Foregrounds[s]; break;
+                        }
+                    } else {
+                        color = new Gdk.Color (0, 0, 0);
+                    }
+                    
+                    gtk_colors[c * sn + s] = CairoExtensions.GdkColorToCairoColor (color);
+                }
+            }
+
+            OnRefreshed ();
+            
+            refreshing = false;
+        }
+
+        protected virtual void OnRefreshed ()
+        {
+            EventHandler handler = Refreshed;
+            if (handler != null) {
+                handler (this, EventArgs.Empty);
+            }
+        }
+    }
+}

Added: trunk/banshee/src/Libraries/Hyena.Gui/Hyena.Gui.Theming/GtkTheme.cs
==============================================================================
--- (empty file)
+++ trunk/banshee/src/Libraries/Hyena.Gui/Hyena.Gui.Theming/GtkTheme.cs	Thu Feb 28 22:03:14 2008
@@ -0,0 +1,222 @@
+//
+// GtkTheme.cs
+//
+// Author:
+//   Aaron Bockover <abockover novell com>
+//
+// Copyright (C) 2007-2008 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;
+using Cairo;
+using Gtk;
+
+namespace Hyena.Gui.Theming
+{
+    public class GtkTheme : Theme
+    {
+        private Cairo.Color rule_color;
+        private Cairo.Color border_color;
+
+        public GtkTheme (Widget widget) : base (widget)
+        {
+        }
+
+        protected override void OnColorsRefreshed ()
+        {
+            base.OnColorsRefreshed ();
+
+            rule_color = CairoExtensions.ColorShade (ViewFill, 0.95);
+            border_color = Colors.GetWidgetColor (GtkColorClass.Dark, StateType.Active);
+        }
+
+        public override void DrawHeaderSeparator(Cairo.Context cr, Gdk.Rectangle alloc, int x, int bottom_offset)
+        {
+            Cairo.Color gtk_background_color = Colors.GetWidgetColor(GtkColorClass.Background, StateType.Normal);
+            Cairo.Color dark_color = CairoExtensions.ColorShade(gtk_background_color, 0.80);
+            Cairo.Color light_color = CairoExtensions.ColorShade(gtk_background_color, 1.1);
+            
+            int y_1 = alloc.Y + 2;
+            int y_2 = alloc.Y + alloc.Height - 4 - bottom_offset;
+            
+            cr.LineWidth = 1;
+            cr.Antialias = Cairo.Antialias.None;
+            
+            cr.Color = dark_color;
+            cr.MoveTo(x, y_1);
+            cr.LineTo(x, y_2);
+            cr.Stroke();
+            
+            cr.Color = light_color;
+            cr.MoveTo(x + 1, y_1);
+            cr.LineTo(x + 1, y_2);
+            cr.Stroke();
+            
+            cr.Antialias = Cairo.Antialias.Default;
+        }
+        
+        public override void DrawHeaderBackground(Cairo.Context cr, Gdk.Rectangle alloc, int bottom_offset, bool fill)
+        {
+            Cairo.Color gtk_background_color = Colors.GetWidgetColor(GtkColorClass.Background, StateType.Normal);
+            Cairo.Color gtk_base_color = Colors.GetWidgetColor(GtkColorClass.Base, StateType.Normal);
+            Cairo.Color light_color = CairoExtensions.ColorShade(gtk_background_color, 1.1);
+            Cairo.Color dark_color = CairoExtensions.ColorShade(gtk_background_color, 0.95);
+            
+            CairoCorners corners = CairoCorners.TopLeft | CairoCorners.TopRight;
+            
+            if(fill) {
+                LinearGradient grad = new LinearGradient(alloc.X, alloc.Y, alloc.X, alloc.Y + alloc.Height);
+                grad.AddColorStop(0, light_color);
+                grad.AddColorStop(0.75, dark_color);
+                grad.AddColorStop(0, light_color);
+            
+                cr.Pattern = grad;
+                CairoExtensions.RoundedRectangle(cr, alloc.X, alloc.Y, alloc.Width, 
+                alloc.Height - bottom_offset, Context.Radius, corners);
+                cr.Fill();
+            
+                cr.Color = gtk_base_color;
+                cr.Rectangle(alloc.X, alloc.Y + alloc.Height - bottom_offset, alloc.Width, bottom_offset);
+                cr.Fill();
+            } else {
+                cr.Color = gtk_base_color;
+                CairoExtensions.RoundedRectangle(cr, alloc.X, alloc.Y, alloc.Width, alloc.Height, Context.Radius, corners);
+                cr.Fill();
+            }
+            
+            cr.LineWidth = 1.0;
+            cr.Translate(alloc.X + 0.5, alloc.Y + 0.5);
+            cr.Color = border_color;
+            CairoExtensions.RoundedRectangle(cr, alloc.X, alloc.Y, alloc.Width - 1, 
+                alloc.Height + 4, Context.Radius, corners);
+            cr.Stroke();
+            
+            if(fill) {
+                cr.LineWidth = 1;
+                cr.Antialias = Cairo.Antialias.None;
+                cr.MoveTo(alloc.X + 1, alloc.Y + alloc.Height - 1 - bottom_offset);
+                cr.LineTo(alloc.X + alloc.Width - 1, alloc.Y + alloc.Height - 1 - bottom_offset);
+                cr.Stroke();
+                cr.Antialias = Cairo.Antialias.Default;
+            }
+        }
+        
+        public override void DrawFrame (Cairo.Context cr, Gdk.Rectangle alloc, Cairo.Color color)
+        {
+            CairoCorners corners = CairoCorners.All;
+        
+            cr.Color = color;
+            CairoExtensions.RoundedRectangle (cr, alloc.X, alloc.Y, alloc.Width, alloc.Height, Context.Radius, corners);
+            cr.Fill ();
+            
+            cr.LineWidth = 1.0;
+            cr.Translate (0.5, 0.5);
+            cr.Color = border_color;
+            CairoExtensions.RoundedRectangle (cr, alloc.X, alloc.Y, alloc.Width - 1, alloc.Height - 1, Context.Radius, corners);
+            cr.Stroke();
+        }
+
+        public override void DrawColumnHighlight(Cairo.Context cr, Gdk.Rectangle alloc, int bottom_offset, Cairo.Color color)
+        {
+            Cairo.Color light_color = CairoExtensions.ColorShade(color, 1.6);
+            Cairo.Color dark_color = CairoExtensions.ColorShade(color, 1.3);
+            
+            LinearGradient grad = new LinearGradient(alloc.X, alloc.Y + 2, alloc.X, alloc.Y + alloc.Height - 3 - bottom_offset);
+            grad.AddColorStop(0, light_color);
+            grad.AddColorStop(1, dark_color);
+            
+            cr.Pattern = grad;
+            cr.Rectangle(alloc.X, alloc.Y + 2, alloc.Width - 1, alloc.Height - 3 - bottom_offset);
+            cr.Fill();
+        }
+        
+        public override void DrawFooter(Cairo.Context cr, Gdk.Rectangle alloc)
+        {
+            Cairo.Color gtk_base_color = Colors.GetWidgetColor(GtkColorClass.Base, StateType.Normal);
+            CairoCorners corners = CairoCorners.BottomLeft | CairoCorners.BottomRight;
+            
+            cr.Color = gtk_base_color;
+            CairoExtensions.RoundedRectangle(cr, alloc.X , alloc.Y, alloc.Width, 
+                alloc.Height, Context.Radius, corners);
+            cr.Fill();
+            
+            cr.LineWidth = 1.0;
+            cr.Translate(alloc.Y + 0.5, alloc.Y + 0.5);
+            
+            cr.Color = border_color;
+            CairoExtensions.RoundedRectangle(cr, alloc.X, alloc.Y - 4, alloc.Width - 1, 
+                alloc.Height + 3, Context.Radius, corners);
+            cr.Stroke();
+        }
+        
+        protected override void DrawLeftOrRightBorder(Cairo.Context cr, int x, Gdk.Rectangle alloc)
+        {
+            cr.LineWidth = 1.0;
+            cr.Antialias = Cairo.Antialias.None;
+            
+            cr.Color = border_color;
+            cr.MoveTo(x, alloc.Y);
+            cr.LineTo(x, alloc.Y + alloc.Height);
+            cr.Stroke();
+            
+            cr.Antialias = Cairo.Antialias.Default;
+        }
+        
+        public override void DrawRowSelection(Cairo.Context cr, int x, int y, int width, int height,
+            bool filled, bool stroked, Cairo.Color color, CairoCorners corners)
+        {
+            Cairo.Color selection_color = color;
+            Cairo.Color selection_stroke = CairoExtensions.ColorShade(selection_color, 0.85);
+            selection_stroke.A = color.A;
+            
+            if (filled) {
+                Cairo.Color selection_fill_light = CairoExtensions.ColorShade(selection_color, 1.1);
+                Cairo.Color selection_fill_dark = CairoExtensions.ColorShade(selection_color, 0.90);
+                
+                selection_fill_light.A = color.A;
+                selection_fill_dark.A = color.A;
+                
+                LinearGradient grad = new LinearGradient(x, y, x, y + height);
+                grad.AddColorStop(0, selection_fill_light);
+                grad.AddColorStop(1, selection_fill_dark);
+                
+                cr.Pattern = grad;
+                CairoExtensions.RoundedRectangle(cr, x, y, width, height, Context.Radius, corners, true);
+                cr.Fill();
+            }
+            
+            if (stroked) {
+                cr.LineWidth = 1.0;
+                cr.Color = selection_stroke;
+                CairoExtensions.RoundedRectangle(cr, x + 0.5, y + 0.5, width - 1, height - 1, Context.Radius, corners, true);
+                cr.Stroke();
+            }
+        }
+        
+        public override void DrawRowRule(Cairo.Context cr, int x, int y, int width, int height)
+        {
+            cr.Color = rule_color;
+            cr.Rectangle (x, y, width, height);
+            cr.Fill ();
+        }
+    }
+}

Added: trunk/banshee/src/Libraries/Hyena.Gui/Hyena.Gui.Theming/Theme.cs
==============================================================================
--- (empty file)
+++ trunk/banshee/src/Libraries/Hyena.Gui/Hyena.Gui.Theming/Theme.cs	Thu Feb 28 22:03:14 2008
@@ -0,0 +1,181 @@
+//
+// Theme.cs
+//
+// Author:
+//   Aaron Bockover <abockover novell com>
+//
+// Copyright (C) 2007-2008 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;
+using System.Collections.Generic;
+using Gtk;
+using Gdk;
+using Cairo;
+
+using Hyena.Gui;
+
+namespace Hyena.Gui.Theming
+{
+    public abstract class Theme
+    {
+        private Stack<ThemeContext> contexts = new Stack<ThemeContext> ();
+        private GtkColors colors;
+
+        private Cairo.Color selection_fill;
+        private Cairo.Color selection_stroke;
+        
+        private Cairo.Color view_fill;
+        private Cairo.Color view_fill_transparent;
+
+        public GtkColors Colors {
+            get { return colors; }
+        }
+
+        public Theme (Widget widget) : this (widget, new GtkColors ())
+        {
+        }
+
+        public Theme (Widget widget, GtkColors colors)
+        {
+            this.colors = colors;
+            this.colors.Refreshed += delegate { OnColorsRefreshed (); };
+            this.colors.Widget = widget;
+
+            PushContext ();
+        }
+
+        protected virtual void OnColorsRefreshed ()
+        {
+            selection_fill = colors.GetWidgetColor (GtkColorClass.Dark, StateType.Active);
+            selection_stroke = colors.GetWidgetColor (GtkColorClass.Background, StateType.Selected);
+            
+            view_fill = colors.GetWidgetColor (GtkColorClass.Base, StateType.Normal);
+            view_fill_transparent = view_fill;
+            view_fill_transparent.A = 0;
+        }
+
+#region Drawing
+     
+        public abstract void DrawHeaderSeparator(Cairo.Context cr, Gdk.Rectangle alloc, int x, int bottom_offset);
+        
+        public abstract void DrawHeaderBackground (Cairo.Context cr, Gdk.Rectangle alloc, int bottom_offset, bool fill);
+        
+        public void DrawFrame (Cairo.Context cr, Gdk.Rectangle alloc, bool baseColor)
+        {
+            DrawFrame (cr, alloc,  baseColor 
+                ? colors.GetWidgetColor (GtkColorClass.Base, StateType.Normal)
+                : colors.GetWidgetColor (GtkColorClass.Background, StateType.Normal));
+        }
+        
+        public abstract void DrawFrame (Cairo.Context cr, Gdk.Rectangle alloc, Cairo.Color color);
+        
+        public void DrawColumnHighlight (Cairo.Context cr, Gdk.Rectangle alloc, int bottom_offset)
+        {
+            DrawColumnHighlight (cr, alloc, bottom_offset, colors.GetWidgetColor(GtkColorClass.Background, StateType.Selected));
+        }
+        
+        public abstract void DrawColumnHighlight (Cairo.Context cr, Gdk.Rectangle alloc, int bottom_offset, Cairo.Color color);
+        
+        public abstract void DrawFooter (Cairo.Context cr, Gdk.Rectangle alloc);
+        
+        public void DrawLeftBorder (Cairo.Context cr, Gdk.Rectangle alloc)
+        {
+            DrawLeftOrRightBorder (cr, alloc.X + 1, alloc);
+        }
+        
+        public void DrawRightBorder (Cairo.Context cr, Gdk.Rectangle alloc)
+        {
+            DrawLeftOrRightBorder (cr, alloc.X + alloc.Width, alloc);   
+        }
+        
+        protected abstract void DrawLeftOrRightBorder (Cairo.Context cr, int x, Gdk.Rectangle alloc);
+        
+        public void DrawRowSelection (Cairo.Context cr, int x, int y, int width, int height)
+        {
+            DrawRowSelection (cr, x, y, width, height, true);
+        }
+        
+        public void DrawRowSelection (Cairo.Context cr, int x, int y, int width, int height, bool filled)
+        {
+            DrawRowSelection (cr, x, y, width, height, filled, true, 
+                colors.GetWidgetColor (GtkColorClass.Background, StateType.Selected), CairoCorners.All);
+        }
+        
+        public void DrawRowSelection (Cairo.Context cr, int x, int y, int width, int height,
+            bool filled, bool stroked, Cairo.Color color)
+        {
+            DrawRowSelection (cr, x, y, width, height, filled, stroked, color, CairoCorners.All);
+        }
+        
+        public abstract void DrawRowSelection (Cairo.Context cr, int x, int y, int width, int height,
+            bool filled, bool stroked, Cairo.Color color, CairoCorners corners);
+        
+        public abstract void DrawRowRule (Cairo.Context cr, int x, int y, int width, int height);
+
+        public Cairo.Color ViewFill {
+            get { return view_fill; }
+        }
+        
+        public Cairo.Color ViewFillTransparent {
+            get { return view_fill_transparent; }
+        }
+        
+        public Cairo.Color SelectionFill {
+            get { return selection_fill; }
+        }
+        
+        public Cairo.Color SelectionStroke {
+            get { return selection_stroke; }
+        }
+
+#endregion
+
+#region Contexts
+
+        public void PushContext ()
+        {
+            PushContext (new ThemeContext ());
+        }
+
+        public void PushContext (ThemeContext context)
+        {
+            lock (this) {
+                contexts.Push (context);
+            }
+        }
+        
+        public ThemeContext PopContext ()
+        {
+            lock (this) {
+                return contexts.Pop ();
+            }
+        }
+
+        public ThemeContext Context {
+            get { lock (this) { return contexts.Peek (); } }
+        }
+
+#endregion
+
+    }
+}

Added: trunk/banshee/src/Libraries/Hyena.Gui/Hyena.Gui.Theming/ThemeContext.cs
==============================================================================
--- (empty file)
+++ trunk/banshee/src/Libraries/Hyena.Gui/Hyena.Gui.Theming/ThemeContext.cs	Thu Feb 28 22:03:14 2008
@@ -0,0 +1,41 @@
+//
+// Theme.cs
+//
+// Author:
+//   Aaron Bockover <abockover novell com>
+//
+// Copyright (C) 2007-2008 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 Hyena.Gui.Theming
+{
+    public class ThemeContext
+    {
+        private int radius = 3;
+        public int Radius {
+            get { return radius; }
+            set { radius = value; }
+        }
+    }
+}

Modified: trunk/banshee/src/Libraries/Hyena.Gui/Hyena.Gui.mdp
==============================================================================
--- trunk/banshee/src/Libraries/Hyena.Gui/Hyena.Gui.mdp	(original)
+++ trunk/banshee/src/Libraries/Hyena.Gui/Hyena.Gui.mdp	Thu Feb 28 22:03:14 2008
@@ -13,7 +13,6 @@
     <File name="Hyena.Data.Gui/ColumnCellText.cs" subtype="Code" buildaction="Compile" />
     <File name="Hyena.Data.Gui/ColumnController.cs" subtype="Code" buildaction="Compile" />
     <File name="Hyena.Data.Gui/ColumnHeaderCellText.cs" subtype="Code" buildaction="Compile" />
-    <File name="Hyena.Data.Gui/ListViewGraphics.cs" subtype="Code" buildaction="Compile" />
     <File name="Hyena.Data.Gui/SortableColumn.cs" subtype="Code" buildaction="Compile" />
     <File name="Hyena.Gui/CleanRoomStartup.cs" subtype="Code" buildaction="Compile" />
     <File name="Hyena.Gui.Dialogs/ExceptionDialog.cs" subtype="Code" buildaction="Compile" />
@@ -50,6 +49,11 @@
     <File name="Hyena.Query.Gui/QueryTermsBox.cs" subtype="Code" buildaction="Compile" />
     <File name="Hyena.Widgets/MessageBar.cs" subtype="Code" buildaction="Compile" />
     <File name="Hyena.Widgets/AnimatedImage.cs" subtype="Code" buildaction="Compile" />
+    <File name="Hyena.Gui.Theming" subtype="Directory" buildaction="Compile" />
+    <File name="Hyena.Gui.Theming/Theme.cs" subtype="Code" buildaction="Compile" />
+    <File name="Hyena.Gui.Theming/GtkColors.cs" subtype="Code" buildaction="Compile" />
+    <File name="Hyena.Gui.Theming/ThemeContext.cs" subtype="Code" buildaction="Compile" />
+    <File name="Hyena.Gui.Theming/GtkTheme.cs" subtype="Code" buildaction="Compile" />
   </Contents>
   <References>
     <ProjectReference type="Gac" localcopy="True" refto="System, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089" />
@@ -59,7 +63,6 @@
     <ProjectReference type="Project" localcopy="False" refto="Hyena" />
     <ProjectReference type="Gac" localcopy="True" refto="pango-sharp, Version=2.8.0.0, Culture=neutral, PublicKeyToken=35e10195dab3c99f" />
   </References>
-  <Deployment.LinuxDeployData generateScript="False" />
   <MonoDevelop.Autotools.MakefileInfo IntegrationEnabled="True" RelativeMakefileName="Makefile.am">
     <BuildFilesVar Sync="True" Name="SOURCES" />
     <DeployFilesVar />
@@ -69,4 +72,5 @@
     <AsmRefVar />
     <ProjectRefVar />
   </MonoDevelop.Autotools.MakefileInfo>
+  <Deployment.LinuxDeployData generateScript="False" />
 </Project>
\ No newline at end of file

Modified: trunk/banshee/src/Libraries/Hyena.Gui/Hyena.Widgets/MessageBar.cs
==============================================================================
--- trunk/banshee/src/Libraries/Hyena.Gui/Hyena.Widgets/MessageBar.cs	(original)
+++ trunk/banshee/src/Libraries/Hyena.Gui/Hyena.Widgets/MessageBar.cs	Thu Feb 28 22:03:14 2008
@@ -30,7 +30,7 @@
 using Gtk;
 
 using Hyena.Gui;
-using Hyena.Data.Gui;
+using Hyena.Gui.Theming;
 
 namespace Hyena.Widgets
 {
@@ -42,7 +42,7 @@
         private Button button;
         private Button close_button;
         
-        private ListViewGraphics graphics;
+        private Theme theme;
         
         public event EventHandler ButtonClicked {
             add { button.Clicked += value; }
@@ -104,8 +104,8 @@
         {
             base.OnRealized ();
             
-            graphics = new ListViewGraphics (this);
-            graphics.RefreshColors ();
+            theme = new GtkTheme (this);
+            // theme.RefreshColors ();
         }
         
         protected override bool OnExposeEvent (Gdk.EventExpose evnt)
@@ -118,7 +118,7 @@
                 
             try {
                 Gdk.Color color = Style.Background (StateType.Normal);
-                graphics.DrawFrame (cr, Allocation, CairoExtensions.GdkColorToCairoColor (color));
+                theme.DrawFrame (cr, Allocation, CairoExtensions.GdkColorToCairoColor (color));
                 return base.OnExposeEvent(evnt);
             } finally {
                 ((IDisposable)cr.Target).Dispose ();

Modified: trunk/banshee/src/Libraries/Hyena.Gui/Hyena.Widgets/RoundedFrame.cs
==============================================================================
--- trunk/banshee/src/Libraries/Hyena.Gui/Hyena.Widgets/RoundedFrame.cs	(original)
+++ trunk/banshee/src/Libraries/Hyena.Gui/Hyena.Widgets/RoundedFrame.cs	Thu Feb 28 22:03:14 2008
@@ -31,13 +31,13 @@
 using Cairo;
 
 using Hyena.Gui;
-using Hyena.Data.Gui;
+using Hyena.Gui.Theming;
 
 namespace Hyena.Widgets
 {
     public class RoundedFrame : Bin
     {
-        private ListViewGraphics graphics;
+        private Theme theme;
         private int frame_width = 3;
         
         private Widget child;
@@ -53,8 +53,8 @@
         {
             base.OnRealized ();
             
-            graphics = new ListViewGraphics (this);
-            graphics.RefreshColors ();
+            theme = new GtkTheme (this);
+            //theme.RefreshColors ();
         }
 
         protected override void OnSizeRequested (ref Requisition requisition)
@@ -131,7 +131,7 @@
             int width = child_allocation.Width + 2 * frame_width;
             int height = child_allocation.Height + 2 * frame_width;
             
-            graphics.DrawFrame (cr, new Gdk.Rectangle (x, y, width, height), true);
+            theme.DrawFrame (cr, new Gdk.Rectangle (x, y, width, height), true);
         }
 
 #endregion

Modified: trunk/banshee/src/Libraries/Hyena.Gui/Makefile.am
==============================================================================
--- trunk/banshee/src/Libraries/Hyena.Gui/Makefile.am	(original)
+++ trunk/banshee/src/Libraries/Hyena.Gui/Makefile.am	Thu Feb 28 22:03:14 2008
@@ -16,7 +16,6 @@
 	Hyena.Data.Gui/ListView/ListView_Model.cs \
 	Hyena.Data.Gui/ListView/ListView_Rendering.cs \
 	Hyena.Data.Gui/ListView/ListView_Windowing.cs \
-	Hyena.Data.Gui/ListViewGraphics.cs \
 	Hyena.Data.Gui/ObjectListView.cs \
 	Hyena.Data.Gui/RowActivatedHandler.cs \
 	Hyena.Data.Gui/SortableColumn.cs \
@@ -25,6 +24,10 @@
 	Hyena.Gui.Theatrics/Actor.cs \
 	Hyena.Gui.Theatrics/SingleActorStage.cs \
 	Hyena.Gui.Theatrics/Stage.cs \
+	Hyena.Gui.Theming/GtkColors.cs \
+	Hyena.Gui.Theming/GtkTheme.cs \
+	Hyena.Gui.Theming/Theme.cs \
+	Hyena.Gui.Theming/ThemeContext.cs \
 	Hyena.Gui/CairoExtensions.cs \
 	Hyena.Gui/CleanRoomStartup.cs \
 	Hyena.Gui/EntryEraseAction.cs \

Modified: trunk/banshee/src/Libraries/Hyena/Hyena.mdp
==============================================================================
--- trunk/banshee/src/Libraries/Hyena/Hyena.mdp	(original)
+++ trunk/banshee/src/Libraries/Hyena/Hyena.mdp	Thu Feb 28 22:03:14 2008
@@ -86,7 +86,6 @@
     <ProjectReference type="Gac" localcopy="True" refto="System.Data, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089" />
     <ProjectReference type="Gac" localcopy="True" refto="Mono.Data.Sqlite, Version=2.0.0.0, Culture=neutral, PublicKeyToken=0738eb9f132ed756" />
   </References>
-  <Deployment.LinuxDeployData generateScript="False" />
   <MonoDevelop.Autotools.MakefileInfo IntegrationEnabled="True" RelativeMakefileName="Makefile.am">
     <BuildFilesVar Sync="True" Name="SOURCES" />
     <DeployFilesVar />
@@ -96,4 +95,5 @@
     <AsmRefVar />
     <ProjectRefVar />
   </MonoDevelop.Autotools.MakefileInfo>
+  <Deployment.LinuxDeployData generateScript="False" />
 </Project>
\ No newline at end of file



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