banshee r4372 - in trunk/banshee: . libbanshee src/Backends/Banshee.GStreamer/Banshee.GStreamer src/Core/Banshee.Services/Banshee.Preferences src/Core/Banshee.ThickClient/Banshee.Preferences.Gui
- From: abock svn gnome org
- To: svn-commits-list gnome org
- Subject: banshee r4372 - in trunk/banshee: . libbanshee src/Backends/Banshee.GStreamer/Banshee.GStreamer src/Core/Banshee.Services/Banshee.Preferences src/Core/Banshee.ThickClient/Banshee.Preferences.Gui
- Date: Thu, 14 Aug 2008 23:23:47 +0000 (UTC)
Author: abock
Date: Thu Aug 14 23:23:47 2008
New Revision: 4372
URL: http://svn.gnome.org/viewvc/banshee?rev=4372&view=rev
Log:
2008-08-14 Aaron Bockover <abock gnome org>
* src/Backends/Banshee.GStreamer/Banshee.GStreamer/PlayerEngine.cs:
Implement ReplayGain preference and cope with the volume format change
* libbanshee/banshee-player.c:
* libbanshee/banshee-player-pipeline.c:
* libbanshee/banshee-player-private.h: Integrate the ReplayGain support
into the pipeline/player object; store user volume in the player object
since the pipeline volume may have a ReplayGain scale factor; use a
double [0..1] to store the volume to make life easier
* libbanshee/banshee-player-replaygain.c:
* libbanshee/banshee-player-replaygain.h: Implemented ReplayGain volume
scaling, reading data from GST_TAG_[TRACK|ALBUM]_[GAIN|PEAK] tags;
implemented based on the http://replaygain.hydrogenaudio.org/ spec,
including the 10 track scale history to implement average scale on
tracks without ReplayGain data
* src/Core/Banshee.ThickClient/Banshee.Preferences.Gui/NotebookPage.cs:
Do not show empty sections
* src/Core/Banshee.Services/Banshee.Preferences/Page.cs: Add an empty
playback section
* src/Core/Banshee.Services/Banshee.Preferences/SchemaPreference.cs:
Support a notification callback when the schema value is toggled
Added:
trunk/banshee/libbanshee/banshee-player-replaygain.c
trunk/banshee/libbanshee/banshee-player-replaygain.h
Modified:
trunk/banshee/ChangeLog
trunk/banshee/libbanshee/Makefile.am
trunk/banshee/libbanshee/banshee-player-pipeline.c
trunk/banshee/libbanshee/banshee-player-private.h
trunk/banshee/libbanshee/banshee-player.c
trunk/banshee/libbanshee/libbanshee.mdp
trunk/banshee/src/Backends/Banshee.GStreamer/Banshee.GStreamer/PlayerEngine.cs
trunk/banshee/src/Core/Banshee.Services/Banshee.Preferences/Page.cs
trunk/banshee/src/Core/Banshee.Services/Banshee.Preferences/SchemaPreference.cs
trunk/banshee/src/Core/Banshee.ThickClient/Banshee.Preferences.Gui/NotebookPage.cs
Modified: trunk/banshee/libbanshee/Makefile.am
==============================================================================
--- trunk/banshee/libbanshee/Makefile.am (original)
+++ trunk/banshee/libbanshee/Makefile.am Thu Aug 14 23:23:47 2008
@@ -17,6 +17,7 @@
banshee-player-equalizer.c \
banshee-player-missing-elements.c \
banshee-player-pipeline.c \
+ banshee-player-replaygain.c \
banshee-player-video.c \
banshee-ripper.c \
banshee-tagger.c \
@@ -29,6 +30,7 @@
banshee-player-missing-elements.h \
banshee-player-pipeline.h \
banshee-player-private.h \
+ banshee-player-replaygain.h \
banshee-player-video.h \
banshee-tagger.h
Modified: trunk/banshee/libbanshee/banshee-player-pipeline.c
==============================================================================
--- trunk/banshee/libbanshee/banshee-player-pipeline.c (original)
+++ trunk/banshee/libbanshee/banshee-player-pipeline.c Thu Aug 14 23:23:47 2008
@@ -31,6 +31,7 @@
#include "banshee-player-video.h"
#include "banshee-player-equalizer.h"
#include "banshee-player-missing-elements.h"
+#include "banshee-player-replaygain.h"
// ---------------------------------------------------------------------------
// Private Functions
@@ -51,8 +52,12 @@
value = gst_tag_list_get_value_index (tag_list, tag_name, 0);
- if (value != NULL && player->tag_found_cb != NULL) {
- player->tag_found_cb (player, tag_name, value);
+ if (value != NULL) {
+ _bp_replaygain_process_tag (player, tag_name, value);
+
+ if (player->tag_found_cb != NULL) {
+ player->tag_found_cb (player, tag_name, value);
+ }
}
}
@@ -77,6 +82,7 @@
gst_message_parse_state_changed (message, &old, &new, &pending);
_bp_missing_elements_handle_state_changed (player, old, new);
+ _bp_replaygain_handle_state_changed (player, old, new, pending);
if (player->state_changed_cb != NULL) {
player->state_changed_cb (player, old, new, pending);
Modified: trunk/banshee/libbanshee/banshee-player-private.h
==============================================================================
--- trunk/banshee/libbanshee/banshee-player-private.h (original)
+++ trunk/banshee/libbanshee/banshee-player-private.h Thu Aug 14 23:23:47 2008
@@ -82,6 +82,7 @@
GstElement *equalizer;
GstElement *preamp;
gint equalizer_status;
+ gdouble current_volume;
// Pipeline/Playback State
GMutex *mutex;
@@ -104,6 +105,24 @@
#ifdef HAVE_GST_PBUTILS
GstInstallPluginsContext *install_plugins_context;
#endif
+
+ // ReplayGain State
+ gboolean replaygain_enabled;
+
+ // ReplayGain history: stores the previous 10 scale factors
+ // and the current scale factor with the current at index 0
+ // and the oldest at index 10. History is used to compute
+ // gain on a track where no adjustment information is present.
+ // http://replaygain.hydrogenaudio.org/player_scale.html
+ gdouble volume_scale_history[11];
+ gboolean volume_scale_history_shift;
+ gboolean current_scale_from_history;
+
+ // ReplayGain cache
+ gdouble album_gain;
+ gdouble album_peak;
+ gdouble track_gain;
+ gdouble track_peak;
};
#endif /* _BANSHEE_PLAYER_PRIVATE_H */
Added: trunk/banshee/libbanshee/banshee-player-replaygain.c
==============================================================================
--- (empty file)
+++ trunk/banshee/libbanshee/banshee-player-replaygain.c Thu Aug 14 23:23:47 2008
@@ -0,0 +1,173 @@
+//
+// banshee-player-replaygain.c
+//
+// 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.
+//
+
+#include <math.h>
+#include "banshee-player-replaygain.h"
+
+// ---------------------------------------------------------------------------
+// Private Functions
+// ---------------------------------------------------------------------------
+
+static inline void
+bp_replaygain_debug (BansheePlayer *player)
+{
+ gint i;
+ for (i = 0; i < 11; i++) {
+ printf ("%g ", player->volume_scale_history[i]);
+ }
+ printf ("\n");
+}
+
+static void
+bp_replaygain_update_pipeline (BansheePlayer *player,
+ gdouble album_gain, gdouble album_peak,
+ gdouble track_gain, gdouble track_peak)
+{
+ gdouble gain = album_gain == 0.0 ? album_gain : track_gain;
+ gdouble peak = album_peak == 0.0 ? album_peak : track_peak;
+ gdouble scale = 0.0;
+
+ g_return_if_fail (IS_BANSHEE_PLAYER (player));
+
+ if (gain == 0.0) {
+ gint i;
+ player->current_scale_from_history = TRUE;
+ // Compute the average scale from history
+ for (i = 1; i <= 10; i++) {
+ scale += player->volume_scale_history[i] / 10.0;
+ }
+ } else {
+ player->current_scale_from_history = FALSE;
+ scale = pow (10.0, gain / 20.0);
+
+ if (peak != 0.0 && scale * peak > 1.0) {
+ scale = 1.0 / peak;
+ }
+
+ if (scale > 15.0) {
+ scale = 15.0;
+ }
+ }
+
+ player->volume_scale_history[0] = scale;
+ _bp_replaygain_update_volume (player);
+}
+
+// ---------------------------------------------------------------------------
+// Internal Functions
+// ---------------------------------------------------------------------------
+
+void
+_bp_replaygain_process_tag (BansheePlayer *player, const gchar *tag_name, const GValue *value)
+{
+ if (strcmp (tag_name, GST_TAG_ALBUM_GAIN) == 0) {
+ player->album_gain = g_value_get_double (value);
+ } else if (strcmp (tag_name, GST_TAG_ALBUM_PEAK) == 0) {
+ player->album_peak = g_value_get_double (value);
+ } else if (strcmp (tag_name, GST_TAG_TRACK_GAIN) == 0) {
+ player->track_gain = g_value_get_double (value);
+ } else if (strcmp (tag_name, GST_TAG_TRACK_PEAK) == 0) {
+ player->track_peak = g_value_get_double (value);
+ }
+}
+
+void
+_bp_replaygain_handle_state_changed (BansheePlayer *player, GstState old, GstState new, GstState pending)
+{
+ if (old == GST_STATE_READY && new == GST_STATE_NULL &&
+ pending == GST_STATE_VOID_PENDING && player->volume_scale_history_shift) {
+
+ memmove (player->volume_scale_history + 1,
+ player->volume_scale_history, sizeof (gdouble) * 10);
+
+ if (player->current_scale_from_history) {
+ player->volume_scale_history[1] = 1.0;
+ }
+
+ player->volume_scale_history[0] = 1.0;
+ player->volume_scale_history_shift = FALSE;
+
+ player->album_gain = player->album_peak = 0.0;
+ player->track_gain = player->track_peak = 0.0;
+ } else if (old == GST_STATE_READY && new == GST_STATE_PAUSED &&
+ pending == GST_STATE_PLAYING && !player->volume_scale_history_shift) {
+
+ player->volume_scale_history_shift = TRUE;
+
+ bp_replaygain_update_pipeline (player,
+ player->album_gain, player->album_peak,
+ player->track_gain, player->track_peak);
+ }
+}
+
+void
+_bp_replaygain_update_volume (BansheePlayer *player)
+{
+ GParamSpec *volume_spec;
+ GValue value = { 0, };
+ gdouble scale;
+
+ if (player == NULL || player->playbin == NULL) {
+ return;
+ }
+
+ scale = player->replaygain_enabled ? player->volume_scale_history[0] : 1.0;
+
+ volume_spec = g_object_class_find_property (G_OBJECT_GET_CLASS (player->playbin), "volume");
+ g_value_init (&value, G_TYPE_DOUBLE);
+ g_value_set_double (&value, player->current_volume * scale);
+ g_param_value_validate (volume_spec, &value);
+
+ if (player->replaygain_enabled) {
+ bp_debug ("scaled volume: %f (ReplayGain) * %f (User) = %f", scale, player->current_volume,
+ g_value_get_double (&value));
+ }
+
+ g_object_set_property (G_OBJECT (player->playbin), "volume", &value);
+ g_value_unset (&value);
+}
+
+// ---------------------------------------------------------------------------
+// Public Functions
+// ---------------------------------------------------------------------------
+
+P_INVOKE void
+bp_replaygain_set_enabled (BansheePlayer *player, gboolean enabled)
+{
+ g_return_if_fail (IS_BANSHEE_PLAYER (player));
+ player->replaygain_enabled = enabled;
+ bp_debug ("%s ReplayGain", enabled ? "Enabled" : "Disabled");
+ _bp_replaygain_update_volume (player);
+}
+
+P_INVOKE gboolean
+bp_replaygain_get_enabled (BansheePlayer *player)
+{
+ g_return_val_if_fail (IS_BANSHEE_PLAYER (player), FALSE);
+ return player->replaygain_enabled;
+}
Added: trunk/banshee/libbanshee/banshee-player-replaygain.h
==============================================================================
--- (empty file)
+++ trunk/banshee/libbanshee/banshee-player-replaygain.h Thu Aug 14 23:23:47 2008
@@ -0,0 +1,48 @@
+//
+// banshee-player-replaygain.h
+//
+// 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.
+//
+
+#ifndef _BANSHEE_PLAYER_REPLAYGAIN_H
+#define _BANSHEE_PLAYER_REPLAYGAIN_H
+
+#include "banshee-player-private.h"
+
+void _bp_replaygain_process_tag (BansheePlayer *player, const gchar *tag_name, const GValue *value);
+void _bp_replaygain_handle_state_changed (BansheePlayer *player, GstState old, GstState new, GstState pending);
+void _bp_replaygain_update_volume (BansheePlayer *player);
+
+static inline void
+_bp_replaygain_init (BansheePlayer *player)
+{
+ gint i;
+ for (i = 0; i < 11; i++) {
+ player->volume_scale_history[i] = 1.0;
+ }
+
+}
+
+#endif /* _BANSHEE_PLAYER_REPLAYGAIN_H */
Modified: trunk/banshee/libbanshee/banshee-player.c
==============================================================================
--- trunk/banshee/libbanshee/banshee-player.c (original)
+++ trunk/banshee/libbanshee/banshee-player.c Thu Aug 14 23:23:47 2008
@@ -30,6 +30,7 @@
#include "banshee-player-pipeline.h"
#include "banshee-player-cdda.h"
#include "banshee-player-missing-elements.h"
+#include "banshee-player-replaygain.h"
// ---------------------------------------------------------------------------
// Private Functions
@@ -123,6 +124,8 @@
player->mutex = g_mutex_new ();
+ _bp_replaygain_init (player);
+
if (!_bp_pipeline_construct (player)) {
bp_destroy (player);
return NULL;
@@ -268,19 +271,18 @@
}
P_INVOKE void
-bp_set_volume (BansheePlayer *player, gint volume)
+bp_set_volume (BansheePlayer *player, gdouble volume)
{
g_return_if_fail (IS_BANSHEE_PLAYER (player));
- g_object_set (G_OBJECT (player->playbin), "volume", CLAMP (volume, 0, 100) / 100.0, NULL);
+ player->current_volume = CLAMP (volume, 0.0, 1.0);
+ _bp_replaygain_update_volume (player);
}
-P_INVOKE gint
+P_INVOKE gdouble
bp_get_volume (BansheePlayer *player)
{
- gdouble volume = 0.0;
- g_return_val_if_fail (IS_BANSHEE_PLAYER (player), 0);
- g_object_get (player->playbin, "volume", &volume, NULL);
- return (gint)(volume * 100.0);
+ g_return_val_if_fail (IS_BANSHEE_PLAYER (player), 0.0);
+ return player->current_volume;
}
P_INVOKE gboolean
Modified: trunk/banshee/libbanshee/libbanshee.mdp
==============================================================================
--- trunk/banshee/libbanshee/libbanshee.mdp (original)
+++ trunk/banshee/libbanshee/libbanshee.mdp Thu Aug 14 23:23:47 2008
@@ -26,6 +26,8 @@
<File name="banshee-tagger.h" subtype="Code" buildaction="Nothing" />
<File name="banshee-gst.h" subtype="Code" buildaction="Nothing" />
<File name="banshee-player-equalizer.h" subtype="Code" buildaction="Nothing" />
+ <File name="banshee-player-replaygain.c" subtype="Code" buildaction="Compile" />
+ <File name="banshee-player-replaygain.h" subtype="Code" buildaction="Nothing" />
</Contents>
<compiler ctype="GccCompiler" />
<MonoDevelop.Autotools.MakefileInfo IntegrationEnabled="True" RelativeMakefileName="Makefile.am">
Modified: trunk/banshee/src/Backends/Banshee.GStreamer/Banshee.GStreamer/PlayerEngine.cs
==============================================================================
--- trunk/banshee/src/Backends/Banshee.GStreamer/Banshee.GStreamer/PlayerEngine.cs (original)
+++ trunk/banshee/src/Backends/Banshee.GStreamer/Banshee.GStreamer/PlayerEngine.cs Thu Aug 14 23:23:47 2008
@@ -37,6 +37,8 @@
using Banshee.Streaming;
using Banshee.MediaEngine;
using Banshee.ServiceStack;
+using Banshee.Configuration;
+using Banshee.Preferences;
namespace Banshee.GStreamer
{
@@ -74,7 +76,7 @@
private GstTaggerTagFoundCallback tag_found_callback;
private bool buffering_finished;
- private short pending_volume = -1;
+ private int pending_volume = -1;
private bool xid_is_set = false;
public PlayerEngine ()
@@ -126,10 +128,14 @@
if (pending_volume >= 0) {
Volume = (ushort)pending_volume;
}
+
+ InstallPreferences ();
+ ReplayGainEnabled = ReplayGainEnabledSchema.Get ();
}
public override void Dispose ()
{
+ UninstallPreferences ();
base.Dispose ();
bp_destroy (handle);
}
@@ -314,14 +320,14 @@
}
public override ushort Volume {
- get { return (ushort)bp_get_volume (handle); }
+ get { return (ushort)Math.Round (bp_get_volume (handle) * 100.0); }
set {
if ((IntPtr)handle == IntPtr.Zero) {
- pending_volume = (short)value;
+ pending_volume = value;
return;
}
- bp_set_volume (handle, (int)value);
+ bp_set_volume (handle, value / 100.0);
OnEventChanged (PlayerEvent.Volume);
}
}
@@ -329,7 +335,7 @@
public override uint Position {
get { return (uint)bp_get_position(handle); }
set {
- bp_set_position(handle, (ulong)value);
+ bp_set_position (handle, (ulong)value);
OnEventChanged (PlayerEvent.Seek);
}
}
@@ -425,6 +431,49 @@
get { return decoder_capabilities; }
}
+ private bool ReplayGainEnabled {
+ get { return bp_replaygain_get_enabled (handle); }
+ set { bp_replaygain_set_enabled (handle, value); }
+ }
+
+#region Preferences
+
+ private PreferenceBase replaygain_preference;
+
+ private void InstallPreferences ()
+ {
+ PreferenceService service = ServiceManager.Get<PreferenceService> ();
+ if (service == null) {
+ return;
+ }
+
+ replaygain_preference = service["general"]["playback"].Add (new SchemaPreference<bool> (ReplayGainEnabledSchema,
+ Catalog.GetString ("_Enable ReplayGain Correction"),
+ Catalog.GetString ("For tracks that have ReplayGain data, automatically scale (normalize) playback volume."),
+ delegate { ReplayGainEnabled = ReplayGainEnabledSchema.Get (); }
+ ));
+ }
+
+ private void UninstallPreferences ()
+ {
+ PreferenceService service = ServiceManager.Get<PreferenceService> ();
+ if (service == null) {
+ return;
+ }
+
+ service["general"]["playback"].Remove (replaygain_preference);
+ replaygain_preference = null;
+ }
+
+ public static readonly SchemaEntry<bool> ReplayGainEnabledSchema = new SchemaEntry<bool> (
+ "player_engine", "replay_gain_enabled",
+ false,
+ "Enable ReplayGain",
+ "If ReplayGain data is present on tracks when playing, allow volume scaling"
+ );
+
+#endregion
+
[DllImport ("libbanshee")]
private static extern IntPtr bp_new ();
@@ -466,10 +515,10 @@
private static extern void bp_play (HandleRef player);
[DllImport ("libbanshee")]
- private static extern void bp_set_volume (HandleRef player, int volume);
+ private static extern void bp_set_volume (HandleRef player, double volume);
[DllImport("libbanshee")]
- private static extern int bp_get_volume (HandleRef player);
+ private static extern double bp_get_volume (HandleRef player);
[DllImport ("libbanshee")]
private static extern bool bp_can_seek (HandleRef player);
@@ -521,5 +570,11 @@
[DllImport ("libbanshee")]
private static extern void bp_equalizer_get_frequencies (HandleRef player,
[MarshalAs (UnmanagedType.LPArray)] out double [] freq);
+
+ [DllImport ("libbanshee")]
+ private static extern void bp_replaygain_set_enabled (HandleRef player, bool enabled);
+
+ [DllImport ("libbanshee")]
+ private static extern bool bp_replaygain_get_enabled (HandleRef player);
}
}
Modified: trunk/banshee/src/Core/Banshee.Services/Banshee.Preferences/Page.cs
==============================================================================
--- trunk/banshee/src/Core/Banshee.Services/Banshee.Preferences/Page.cs (original)
+++ trunk/banshee/src/Core/Banshee.Services/Banshee.Preferences/Page.cs Thu Aug 14 23:23:47 2008
@@ -73,6 +73,8 @@
file_system.Add (new SchemaPreference<string> (LibrarySchema.FilePattern,
Catalog.GetString ("File _name")));
+
+ general.Add (new Section ("playback", Catalog.GetString ("Playback"), 20));
service.Add (new Page ("extensions", Catalog.GetString ("Extensions"), 10));
}
Modified: trunk/banshee/src/Core/Banshee.Services/Banshee.Preferences/SchemaPreference.cs
==============================================================================
--- trunk/banshee/src/Core/Banshee.Services/Banshee.Preferences/SchemaPreference.cs (original)
+++ trunk/banshee/src/Core/Banshee.Services/Banshee.Preferences/SchemaPreference.cs Thu Aug 14 23:23:47 2008
@@ -32,22 +32,37 @@
namespace Banshee.Preferences
{
+ public delegate void SchemaPreferenceUpdatedHandler ();
+
public class SchemaPreference<T> : Preference<T>
{
private SchemaEntry<T> schema;
+ private SchemaPreferenceUpdatedHandler handler;
public SchemaPreference (SchemaEntry<T> schema, string name) : this (schema, name, null)
{
}
- public SchemaPreference (SchemaEntry<T> schema, string name, string description) : base (schema.Key, name, description)
+ public SchemaPreference (SchemaEntry<T> schema, string name, string description)
+ : this (schema, name, description, null)
+ {
+ }
+
+ public SchemaPreference (SchemaEntry<T> schema, string name, string description, SchemaPreferenceUpdatedHandler handler)
+ : base (schema.Key, name, description)
{
this.schema = schema;
+ this.handler = handler;
}
public override T Value {
get { return schema.Get (); }
- set { schema.Set (value); }
+ set {
+ schema.Set (value);
+ if (handler != null) {
+ handler ();
+ }
+ }
}
}
}
Modified: trunk/banshee/src/Core/Banshee.ThickClient/Banshee.Preferences.Gui/NotebookPage.cs
==============================================================================
--- trunk/banshee/src/Core/Banshee.ThickClient/Banshee.Preferences.Gui/NotebookPage.cs (original)
+++ trunk/banshee/src/Core/Banshee.ThickClient/Banshee.Preferences.Gui/NotebookPage.cs Thu Aug 14 23:23:47 2008
@@ -70,6 +70,10 @@
{
Frame frame = null;
+ if (section.Count == 0) {
+ return;
+ }
+
if (section.ShowLabel) {
frame = new Frame ();
Label label = new Label ();
[
Date Prev][
Date Next] [
Thread Prev][
Thread Next]
[
Thread Index]
[
Date Index]
[
Author Index]