Index: shell/rb-shell.c
===================================================================
--- shell/rb-shell.c	(revision 4829)
+++ shell/rb-shell.c	(working copy)
@@ -371,6 +371,8 @@
 	GtkWidget *volume_button;
 	gboolean syncing_volume;
 
+	GtkWidget *rating;
+
 	char *cached_title;
 	char *cached_duration;
 	gboolean cached_playing;
@@ -413,6 +415,7 @@
 	{ "Edit", NULL, N_("_Edit") },
 	{ "View", NULL, N_("_View") },
 	{ "Control", NULL, N_("_Control") },
+	{ "Rating", NULL, N_("_Rating") },
 	{ "Tools", NULL, N_("_Tools") },
 	{ "Help", NULL, N_("_Help") },
 
Index: shell/rb-shell-player.c
===================================================================
--- shell/rb-shell-player.c	(revision 4829)
+++ shell/rb-shell-player.c	(working copy)
@@ -92,6 +92,11 @@
 					   RBShellPlayer *player);
 static void rb_shell_player_cmd_volume_down (GtkAction *action,
 					     RBShellPlayer *player);
+static void rb_shell_player_rating_change (RBShellPlayer *player,
+					   double change,
+					   double absolute);
+static void rb_shell_player_update_rating (GtkAction *action,
+					   RBShellPlayer *player);
 static void rb_shell_player_shuffle_changed_cb (GtkAction *action,
 						RBShellPlayer *player);
 static void rb_shell_player_repeat_changed_cb (GtkAction *action,
@@ -239,6 +244,30 @@
 	{ "ControlVolumeDown", NULL, N_("_Decrease Volume"), "<control>Down",
 	  N_("Decrease playback volume"),
 	  G_CALLBACK (rb_shell_player_cmd_volume_down) },
+	{ "RatingUp", NULL, N_("_Increase Rating"), "<control>Right",
+	  N_("Increase the Rating of the song"),
+	  G_CALLBACK (rb_shell_player_update_rating) },
+	{ "RatingDown", NULL, N_("_Decrease Rating"), "<control>Left",
+	  N_("Decrease the Rating of the song"),
+	  G_CALLBACK (rb_shell_player_update_rating) },
+	{ "Rating0", NULL, N_("Set _0 Rating"), "<control>0",
+	  N_("Set the song rating to 0"),
+	  G_CALLBACK (rb_shell_player_update_rating) },
+	{ "Rating1", NULL, N_("Set _1 Rating"), "<control>1",
+	  N_("Set the song rating to 1"),
+	  G_CALLBACK (rb_shell_player_update_rating) },
+	{ "Rating2", NULL, N_("Set _2 Rating"), "<control>2",
+	  N_("Set the song rating to 2"),
+	  G_CALLBACK (rb_shell_player_update_rating) },
+	{ "Rating3", NULL, N_("Set _3 Rating"), "<control>3",
+	  N_("Set the song rating to 3"),
+	  G_CALLBACK (rb_shell_player_update_rating) },
+	{ "Rating4", NULL, N_("Set _4 Rating"), "<control>4",
+	  N_("Set the song rating to 4"),
+	  G_CALLBACK (rb_shell_player_update_rating) },
+	{ "Rating5", NULL, N_("Set _5 Rating"), "<control>5",
+	  N_("Set the song rating to 5"),
+	  G_CALLBACK (rb_shell_player_update_rating) },
 };
 static guint rb_shell_player_n_actions = G_N_ELEMENTS (rb_shell_player_actions);
 
@@ -1798,6 +1827,74 @@
 }
 
 static void
+rb_shell_player_update_rating (GtkAction *action,
+			       RBShellPlayer *player)
+{
+	const gchar *name = gtk_action_get_name(action);
+
+	if ( strcmp(name, "RatingDown") == 0) {
+		rb_shell_player_rating_change (player, -1.0, 0.0);
+	} else if ( strcmp(name, "RatingUp") == 0) {
+		rb_shell_player_rating_change (player, 1.0, 0.0);
+	} else if ( strcmp(name, "Rating0") == 0) {
+		rb_shell_player_rating_change (player, 0.0, 0.0);
+	} else if ( strcmp(name, "Rating1") == 0) {
+		rb_shell_player_rating_change (player, 0.0, 1.0);
+	} else if ( strcmp(name, "Rating2") == 0) {
+		rb_shell_player_rating_change (player, 0.0, 2.0);
+	} else if ( strcmp(name, "Rating3") == 0) {
+		rb_shell_player_rating_change (player, 0.0, 3.0);
+	} else if ( strcmp(name, "Rating4") == 0) {
+		rb_shell_player_rating_change (player, 0.0, 4.0);
+	} else if ( strcmp(name, "Rating5") == 0) {
+		rb_shell_player_rating_change (player, 0.0, 5.0);
+	} else {
+		rb_debug("Hit a function that isn't for Ratings");
+	}
+}
+
+static void
+rb_shell_player_rating_change (RBShellPlayer *player,
+			       double change,
+			       double absolute)
+{
+	RhythmDBEntry *entry;
+	double score;
+
+	GValue value = {0, };
+
+	entry = rb_shell_player_get_playing_entry (player);
+
+	if (!entry)
+		return;
+
+	/* We're not changing a value already there, we're setting it absolutely */
+	if (change == 0.0) {
+		score = absolute;
+	} else if (change == 0.0 && absolute == 0.0) {
+		/* We're setting a zero rating */
+		score = 0.0;
+	} else {
+		score = rhythmdb_entry_get_double (entry, RHYTHMDB_PROP_RATING);
+		score = score + change;
+	}
+
+	g_return_if_fail (score >= 0 && score <= 5);
+
+	g_value_init (&value, G_TYPE_DOUBLE);
+	g_value_set_double (&value, score);
+
+	/* set the new value for the song */
+	rhythmdb_entry_set (player->priv->db,
+			    entry,
+			    RHYTHMDB_PROP_RATING,
+			    &value);
+	g_value_unset (&value);
+	rhythmdb_commit (player->priv->db);
+	rb_header_sync (player->priv->header_widget);
+}
+
+static void
 rb_shell_player_cmd_play (GtkAction *action,
 			  RBShellPlayer *player)
 {
Index: data/ui/rhythmbox-ui.xml
===================================================================
--- data/ui/rhythmbox-ui.xml	(revision 4829)
+++ data/ui/rhythmbox-ui.xml	(working copy)
@@ -74,6 +74,18 @@
       <placeholder name="ToolsOps_5" />
     </menu>
 
+    <menu name="RatingMenu" action="Rating">
+      <menuitem name="RatingUpMenu" action="RatingUp"/>
+      <menuitem name="RatingDownMenu" action="RatingDown"/>
+      <separator/>
+      <menuitem name="Rating0Menu" action="Rating0"/>
+      <menuitem name="Rating1Menu" action="Rating1"/>
+      <menuitem name="Rating2Menu" action="Rating2"/>
+      <menuitem name="Rating3Menu" action="Rating3"/>
+      <menuitem name="Rating4Menu" action="Rating4"/>
+      <menuitem name="Rating5Menu" action="Rating5"/>
+    </menu>
+ 
     <menu name="ControlMenu" action="Control">
       <menuitem name="ControlPlayMenu" action="ControlPlay"/>
       <separator name="ControlSep1"/>
Index: widgets/rb-header.c
===================================================================
--- widgets/rb-header.c	(revision 4829)
+++ widgets/rb-header.c	(working copy)
@@ -37,6 +37,7 @@
 #include "eel-gconf-extensions.h"
 #include "rb-util.h"
 #include "rhythmdb.h"
+#include "rb-rating.h"
 
 static void rb_header_class_init (RBHeaderClass *klass);
 static void rb_header_init (RBHeader *header);
@@ -59,6 +60,10 @@
 
 static void rb_header_elapsed_changed_cb (RBShellPlayer *player, guint elapsed, RBHeader *header);
 
+static void rb_header_rated_cb (RBRating *rating, double score, RBHeader *header);
+
+static void rb_header_set_entry_rating (RBHeader *header, double trouble);
+
 struct RBHeaderPrivate
 {
 	RhythmDB *db;
@@ -69,6 +74,8 @@
 	GtkWidget *image;
 	GtkWidget *song;
 
+	GtkWidget *rating;
+
 	GtkWidget *timeline;
 	GtkWidget *scaleline;
 	gboolean scaleline_shown;
@@ -183,6 +190,13 @@
 	gtk_box_pack_start (GTK_BOX (hbox), header->priv->song, TRUE, TRUE, 0);
 	gtk_widget_show (header->priv->song);
 
+	header->priv->rating = GTK_WIDGET (rb_rating_new ());
+	g_signal_connect_object (header->priv->rating, "rated",
+				 G_CALLBACK (rb_header_rated_cb),
+				 G_OBJECT (header), 0);
+	gtk_box_pack_start (GTK_BOX (hbox), header->priv->rating, FALSE, FALSE, 0);
+	gtk_widget_show (GTK_WIDGET (header->priv->rating));
+
 	/* construct the time display */
 	header->priv->timeline = gtk_hbox_new (FALSE, 3);
 	header->priv->elapsed = gtk_label_new ("");
@@ -221,6 +235,39 @@
 }
 
 static void
+rb_header_rated_cb (RBRating *rating,
+		    double score,
+		    RBHeader *header)
+{
+	g_return_if_fail (RB_IS_RATING (rating));
+	g_return_if_fail (score >= 0 && score <= 5 );
+
+	rb_header_set_entry_rating (header, score);
+	rhythmdb_commit (header->priv->db);
+
+	g_object_set (G_OBJECT (header->priv->rating),
+		      "rating", score,
+		      NULL);
+}
+
+static void
+rb_header_set_entry_rating (RBHeader *header,
+			    double trouble)
+{
+	RhythmDBEntry *playing_entry;
+
+	playing_entry = rb_shell_player_get_playing_entry (header->priv->shell_player);
+
+	GValue value = {0, };
+
+	/* set the new value for the song */
+	g_value_init (&value, G_TYPE_DOUBLE);
+	g_value_set_double (&value, trouble);
+	rhythmdb_entry_set (header->priv->db, playing_entry, RHYTHMDB_PROP_RATING, &value);
+	g_value_unset (&value);
+}
+
+static void
 rb_header_finalize (GObject *object)
 {
 	RBHeader *header;
@@ -322,6 +369,12 @@
 		      "entry", entry,
 		      "seekable", seekable,
 		      NULL);
+
+	double score = rhythmdb_entry_get_double (entry, RHYTHMDB_PROP_RATING);
+
+	g_object_set (G_OBJECT (header->priv->rating),
+		      "rating", score,
+		      NULL);
 }
 
 static void
@@ -363,6 +416,7 @@
 		char *streaming_artist;
 		char *streaming_album;
 		GString *label_str;
+		double score;
 
 		gboolean have_duration = (header->priv->duration > 0);
 
@@ -411,6 +465,12 @@
 		if (stream_name && stream_name[0] != '\0')
 			append_and_free (label_str, STREAM_MARKUP (stream_name));
 
+		score = rhythmdb_entry_get_double (header->priv->entry, RHYTHMDB_PROP_RATING);
+
+		g_object_set (G_OBJECT (header->priv->rating),
+					"rating", score,
+					NULL);
+
 		label_text = g_string_free (label_str, FALSE);
 		gtk_label_set_markup (GTK_LABEL (header->priv->song), label_text);
 		g_free (label_text);
