diff -u -u -r1.49 rhythmbox-ui.xml
--- data/ui/rhythmbox-ui.xml	12 Mar 2006 23:00:59 -0000	1.49
+++ data/ui/rhythmbox-ui.xml	18 Mar 2006 05:00:24 -0000
@@ -62,8 +62,9 @@
       <menuitem name="ControlPreviousMenu" action="ControlPrevious"/>
       <menuitem name="ControlNextMenu" action="ControlNext"/>
       <separator name="ControlSep2"/>
-      <menuitem name="ControlShuffleMenu" action="ControlShuffle"/>
-      <menuitem name="ControlRepeatMenu" action="ControlRepeat"/>
+      <menu name="PlayOrderMenu" action="ControlPlayOrder">
+        <placeholder name="PlayOrderActionPlaceholder"/>
+      </menu>
     </menu>
 
     <menu name="HelpMenu" action="Help">
@@ -78,8 +79,11 @@
     <toolitem name="Play" action="ControlPlay"/>
     <toolitem name="Next" action="ControlNext"/>
     <separator/>
-    <toolitem name="Repeat" action="ControlRepeat"/>
-    <toolitem name="Shuffle" action="ControlShuffle"/>
+      <toolitem name="foo">
+        <menu name="ToolbarEditMenu" action="Edit">
+          <menuitem name="EditPluginsMenu" action="EditPlugins"/>
+        </menu>
+      </toolitem>
     <separator/>
     <toolitem name="Browse" action="ViewBrowser"/>
     <separator/>
diff -u -u -r1.69 Makefile.am
--- shell/Makefile.am	11 Mar 2006 05:02:22 -0000	1.69
+++ shell/Makefile.am	18 Mar 2006 05:00:24 -0000
@@ -51,6 +51,8 @@
 	rb-play-order-linear.h				\
 	rb-play-order-linear-loop.c			\
 	rb-play-order-linear-loop.h			\
+	rb-play-order-loop-one.c			\
+	rb-play-order-loop-one.h			\
 	rb-play-order-queue.c				\
 	rb-play-order-queue.h				\
 	rb-play-order-shuffle.c				\
diff -u -u -r1.17 rb-play-order.c
--- shell/rb-play-order.c	13 Mar 2006 22:04:52 -0000	1.17
+++ shell/rb-play-order.c	18 Mar 2006 05:00:25 -0000
@@ -23,6 +23,7 @@
 #include <string.h>
 
 #include <glib/gi18n.h>
+#include <gtk/gtk.h>
 
 #include "rb-play-order.h"
 
@@ -34,6 +35,7 @@
 /* Play Orders */
 #include "rb-play-order-linear.h"
 #include "rb-play-order-linear-loop.h"
+#include "rb-play-order-loop-one.h"
 #include "rb-play-order-shuffle.h"
 #include "rb-play-order-random-equal-weights.h"
 #include "rb-play-order-random-by-age.h"
@@ -85,6 +87,7 @@
 
 #define RB_PLAY_ORDER_GET_PRIVATE(o) (G_TYPE_INSTANCE_GET_PRIVATE ((o), RB_TYPE_PLAY_ORDER, RBPlayOrderPrivate))
 
+
 enum
 {
 	PROP_0,
@@ -268,6 +271,7 @@
 	static const RBPlayOrderDescription orders[] = {
 		{ "linear", N_("Linear"), rb_linear_play_order_new, TRUE, TRUE },
 		{ "linear-loop", N_("Linear looping"), rb_linear_play_order_loop_new, TRUE, FALSE },
+		{ "loop-one", N_("Repeat single track"), rb_loop_one_play_order_new, TRUE, FALSE },
 		{ "shuffle", N_("Shuffle"), rb_shuffle_play_order_new, TRUE, FALSE },
 		{ "random-equal-weights", N_("Random with equal weights"), rb_random_play_order_equal_weights_new, TRUE, FALSE },
 		{ "random-by-age", N_("Random by time since last play"), rb_random_play_order_by_age_new, TRUE, FALSE },
diff -u -u -r1.224 rb-shell-player.c
--- shell/rb-shell-player.c	14 Mar 2006 14:44:09 -0000	1.224
+++ shell/rb-shell-player.c	18 Mar 2006 05:00:26 -0000
@@ -72,6 +72,7 @@
 static const char* const state_to_play_order[2][2] =
 	{{"linear",	"linear-loop"},
 	 {"shuffle",	"random-by-age-and-rating"}};
+const char *PLAY_ORDER_ACTION_NAME = "PlayOrderAction-%s";
 
 static void rb_shell_player_class_init (RBShellPlayerClass *klass);
 static void rb_shell_player_init (RBShellPlayer *shell_player);
@@ -93,10 +94,6 @@
 			              RBShellPlayer *player);
 static void rb_shell_player_cmd_next (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,
-					       RBShellPlayer *player);
 static void rb_shell_player_view_song_position_slider_changed_cb (GtkAction *action,
 								  RBShellPlayer *player);
 static void rb_shell_player_set_playing_source_internal (RBShellPlayer *player,
@@ -136,7 +133,6 @@
 						  RBShellPlayer *player);
 
 static void rb_shell_player_sync_play_order (RBShellPlayer *player);
-static void rb_shell_player_sync_control_state (RBShellPlayer *player);
 static void rb_shell_player_sync_song_position_slider_visibility (RBShellPlayer *player);
 
 static void gconf_play_order_changed (GConfClient *client,guint cnxn_id,
@@ -148,6 +144,7 @@
 						gpointer user_data);
 
 static gboolean rb_shell_player_jump_to_current_idle (RBShellPlayer *player);
+static void rb_shell_player_setup_order_menu (RBShellPlayer *player);
 
 #ifdef HAVE_MMKEYS
 static void grab_mmkey (int key_code, GdkWindow *root);
@@ -234,6 +231,8 @@
 
 static GtkActionEntry rb_shell_player_actions [] =
 {
+	{ "ControlPlayOrder", NULL, N_("Play Order") },
+
 	{ "ControlPrevious", GTK_STOCK_MEDIA_PREVIOUS, N_("P_revious"), "<alt>Left",
 	  N_("Start playing the previous song"),
 	  G_CALLBACK (rb_shell_player_cmd_previous) },
@@ -249,12 +248,6 @@
 	{ "ControlPlay", GTK_STOCK_MEDIA_PLAY, N_("_Play"), "<control>space",
 	  N_("Start playback"),
 	  G_CALLBACK (rb_shell_player_cmd_play) },
-	{ "ControlShuffle", GNOME_MEDIA_SHUFFLE, N_("Sh_uffle"), "<control>U",
-	  N_("Play songs in a random order"),
-	  G_CALLBACK (rb_shell_player_shuffle_changed_cb) },
-	{ "ControlRepeat", GNOME_MEDIA_REPEAT, N_("_Repeat"), "<control>R",
-	  N_("Play first song again after all songs are played"),
-	  G_CALLBACK (rb_shell_player_repeat_changed_cb) },
 	{ "ViewSongPositionSlider", NULL, N_("_Song Position Slider"), NULL,
 	  N_("Change the visibility of the song position slider"),
 	  G_CALLBACK (rb_shell_player_view_song_position_slider_changed_cb), TRUE }
@@ -468,6 +461,8 @@
 					     rb_shell_player_toggle_entries,
 					     rb_shell_player_n_toggle_entries,
 					     player);
+	/* done in an idle function, so that UI and plugins are fully loaded first */
+	g_idle_add ((GSourceFunc)rb_shell_player_setup_order_menu, player);
 
 	action = gtk_action_group_get_action (player->priv->actiongroup,
 					      "ControlPlay");
@@ -476,7 +471,6 @@
 	player->priv->syncing_state = TRUE;
 	rb_shell_player_set_playing_source (player, NULL);
 	rb_shell_player_sync_play_order (player);
-	rb_shell_player_sync_control_state (player);
 	player->priv->syncing_state = FALSE;
 
 	rb_shell_player_sync_song_position_slider_visibility (player);
@@ -1120,7 +1114,6 @@
 	player->priv->syncing_state = TRUE;
 	rb_shell_player_sync_play_order (player);
 	rb_shell_player_sync_buttons (player);
-	rb_shell_player_sync_control_state (player);
 	g_object_notify (G_OBJECT (player), "play-order");
 	player->priv->syncing_state = FALSE;
 }
@@ -1179,6 +1172,8 @@
 	char *new_play_order = eel_gconf_get_string (CONF_STATE_PLAY_ORDER);
 	RhythmDBEntry *playing_entry = NULL;
 	RBSource *source;
+	char *action_name;
+	GtkAction *action;
 
 	if (!new_play_order) {
 		g_warning (CONF_STATE_PLAY_ORDER " gconf key not found!");
@@ -1206,6 +1201,13 @@
 
 	if (playing_entry)
 		rb_play_order_set_playing_entry (player->priv->play_order, playing_entry);
+
+	action_name = g_strdup_printf (PLAY_ORDER_ACTION_NAME, new_play_order);
+	action = gtk_action_group_get_action (player->priv->actiongroup, action_name);
+	g_free (action_name);
+	if (action)
+		gtk_toggle_action_set_active (GTK_TOGGLE_ACTION (action), TRUE);
+
 	g_free (new_play_order);
 }
 
@@ -1610,25 +1612,6 @@
 
 
 static void
-rb_shell_player_sync_control_state (RBShellPlayer *player)
-{
-	gboolean shuffle, repeat;
-	GtkAction *action;
-	rb_debug ("syncing control state");
-
-	if (!rb_shell_player_get_playback_state (player, &shuffle,
-						 &repeat))
-		return;
-
-	action = gtk_action_group_get_action (player->priv->actiongroup,
-					      "ControlShuffle");
-	gtk_toggle_action_set_active (GTK_TOGGLE_ACTION (action), shuffle);
-	action = gtk_action_group_get_action (player->priv->actiongroup,
-					      "ControlRepeat");
-	gtk_toggle_action_set_active (GTK_TOGGLE_ACTION (action), repeat);
-}
-
-static void
 rb_shell_player_sync_volume (RBShellPlayer *player, gboolean notify)
 {
 	if (player->priv->volume < 0.0)
@@ -1735,43 +1718,6 @@
 }
 
 static void
-rb_shell_player_shuffle_changed_cb (GtkAction *action,
-				    RBShellPlayer *player)
-{
-	const char *neworder;
-	gboolean shuffle, repeat;
-
-	if (player->priv->syncing_state)
-		return;
-
-	rb_debug ("shuffle changed");
-
-	if (!rb_shell_player_get_playback_state (player, &shuffle, &repeat))
-		return;
-	shuffle = !shuffle;
-	neworder = state_to_play_order[shuffle ? 1 : 0][repeat ? 1 : 0];
-	rb_shell_player_set_play_order (player, neworder);
-}
-	
-static void
-rb_shell_player_repeat_changed_cb (GtkAction *action,
-				   RBShellPlayer *player)
-{
-	const char *neworder;
-	gboolean shuffle, repeat;
-	rb_debug ("repeat changed");
-
-	if (player->priv->syncing_state)
-		return;
-
-	if (!rb_shell_player_get_playback_state (player, &shuffle, &repeat))
-		return;
-	repeat = !repeat;
-	neworder = state_to_play_order[shuffle ? 1 : 0][repeat ? 1 : 0];
-	rb_shell_player_set_play_order (player, neworder);
-}
-
-static void
 rb_shell_player_view_song_position_slider_changed_cb (GtkAction *action,
 						      RBShellPlayer *player)
 {
@@ -2694,4 +2640,55 @@
 	g_signal_handlers_block_by_func (action, rb_shell_player_cmd_play, player);
 	gtk_toggle_action_set_active (GTK_TOGGLE_ACTION (action), playing);
 	g_idle_add (_idle_unblock_signal_cb, player);
+}
+
+static void
+play_order_changed_cb (GtkRadioAction *action, GtkRadioAction *current, RBShellPlayer *player)
+{
+	const RBPlayOrderDescription *orders;
+	guint i;
+
+	orders = rb_play_order_get_orders ();
+	i = gtk_radio_action_get_current_value (GTK_RADIO_ACTION (action));
+
+	rb_shell_player_set_play_order (player, orders[i].name);
+}
+
+static void
+rb_shell_player_setup_order_menu (RBShellPlayer *player)
+{
+	const RBPlayOrderDescription *orders;
+	guint merge_id;
+	GSList *group = NULL;
+	int i;
+
+	orders = rb_play_order_get_orders ();
+	merge_id = gtk_ui_manager_new_merge_id (player->priv->ui_manager);
+	
+	for (i = 0; orders[i].name != NULL; i++) {
+		char *action_name;
+		GtkRadioAction *action;
+
+		if (!orders[i].is_in_dropdown)
+			continue;
+
+		action_name = g_strdup_printf (PLAY_ORDER_ACTION_NAME, orders[i].name);
+		action = gtk_radio_action_new (action_name,
+					       _(orders[i].description), _(orders[i].description),
+					       NULL, i);
+		gtk_radio_action_set_group (action, group);
+		group = gtk_radio_action_get_group (action);
+		gtk_action_group_add_action_with_accel (player->priv->actiongroup, GTK_ACTION (action), NULL);
+
+		g_signal_connect (G_OBJECT (action),
+				  "changed", G_CALLBACK (play_order_changed_cb),
+				  player);
+
+		gtk_ui_manager_add_ui (player->priv->ui_manager, merge_id,
+				       "/MenuBar/ControlMenu/PlayOrderMenu",
+				       action_name, action_name,
+				       GTK_UI_MANAGER_AUTO, FALSE);
+		g_free (action_name);
+		g_object_unref (action);
+	}
 }
--- /dev/null	2006-03-16 19:06:34.000000000 +1100
+++ shell/rb-play-order-loop-one.c	2006-03-17 22:38:54.000000000 +1100
@@ -0,0 +1,77 @@
+/* 
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program; if not, write to the Free Software
+ *  Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ *
+ */
+
+#include "rb-play-order-loop-one.h"
+
+#include "rb-debug.h"
+#include "rb-preferences.h"
+#include "eel-gconf-extensions.h"
+
+static void rb_loop_one_play_order_class_init (RBLoopOnePlayOrderClass *klass);
+
+static RhythmDBEntry* rb_loop_one_play_order_get_next (RBPlayOrder* method);
+
+G_DEFINE_TYPE (RBLoopOnePlayOrder, rb_loop_one_play_order, RB_TYPE_PLAY_ORDER)
+
+RBPlayOrder *
+rb_loop_one_play_order_new (RBShellPlayer *player)
+{
+	RBLoopOnePlayOrder *lorder;
+
+	lorder = g_object_new (RB_TYPE_LOOP_ONE_PLAY_ORDER,
+			       "player", player,
+			       NULL);
+
+	return RB_PLAY_ORDER (lorder);
+}
+
+static void
+rb_loop_one_play_order_class_init (RBLoopOnePlayOrderClass *klass)
+{
+	RBPlayOrderClass *porder = RB_PLAY_ORDER_CLASS (klass);
+	porder->get_next = rb_loop_one_play_order_get_next;
+	porder->get_previous = rb_loop_one_play_order_get_next;
+}
+
+static void
+rb_loop_one_play_order_init (RBLoopOnePlayOrder *porder)
+{
+}
+
+static RhythmDBEntry* 
+rb_loop_one_play_order_get_next (RBPlayOrder* porder)
+{
+	RhythmDBQueryModel *model;
+	RhythmDBEntry *entry;
+
+	g_return_val_if_fail (porder != NULL, NULL);
+	g_return_val_if_fail (RB_IS_LOOP_ONE_PLAY_ORDER (porder), NULL);
+
+	model = rb_play_order_get_query_model (porder);
+	if (model == NULL)
+		return NULL;
+
+	g_object_get (porder, "playing-entry", &entry, NULL);
+	if (entry) {
+		return entry;
+	} else {
+		GtkTreeIter iter;
+		if (!gtk_tree_model_get_iter_first (GTK_TREE_MODEL (model), &iter))
+			return NULL;
+		return rhythmdb_query_model_iter_to_entry (model, &iter);
+	}
+}
--- /dev/null	2006-03-16 19:06:34.000000000 +1100
+++ shell/rb-play-order-loop-one.h	2006-03-17 22:34:48.000000000 +1100
@@ -0,0 +1,50 @@
+/* 
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program; if not, write to the Free Software
+ *  Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ *
+ */
+
+#ifndef __RB_PLAY_ORDER_LOOP_ONE_H
+#define __RB_PLAY_ORDER_LOOP_ONE_H
+
+#include "rb-play-order.h"
+
+#include "rb-shell-player.h"
+
+G_BEGIN_DECLS
+
+#define RB_TYPE_LOOP_ONE_PLAY_ORDER         (rb_loop_one_play_order_get_type ())
+#define RB_LOOP_ONE_PLAY_ORDER(o)           (G_TYPE_CHECK_INSTANCE_CAST ((o), RB_TYPE_LOOP_ONE_PLAY_ORDER, RBLoopOnePlayOrder))
+#define RB_LOOP_ONE_PLAY_ORDER_CLASS(k)     (G_TYPE_CHECK_CLASS_CAST ((k), RB_TYPE_LOOP_ONE_PLAY_ORDER, RBLoopOnePlayOrderClass))
+#define RB_IS_LOOP_ONE_PLAY_ORDER(o)        (G_TYPE_CHECK_INSTANCE_TYPE ((o), RB_TYPE_LOOP_ONE_PLAY_ORDER))
+#define RB_IS_LOOP_ONE_PLAY_ORDER_CLASS(k)  (G_TYPE_CHECK_CLASS_TYPE ((k), RB_TYPE_LOOP_ONE_PLAY_ORDER))
+#define RB_LOOP_ONE_PLAY_ORDER_GET_CLASS(o) (G_TYPE_INSTANCE_GET_CLASS ((o), RB_TYPE_LOOP_ONE_PLAY_ORDER, RBLoopOnePlayOrderClass))
+
+typedef struct
+{
+	RBPlayOrder parent;
+} RBLoopOnePlayOrder;
+
+typedef struct
+{
+	RBPlayOrderClass parent_class;
+} RBLoopOnePlayOrderClass;
+
+GType			rb_loop_one_play_order_get_type	(void);
+
+RBPlayOrder *		rb_loop_one_play_order_new	(RBShellPlayer *player);
+
+G_END_DECLS
+
+#endif /* __RB_PLAY_ORDER_LOOP_ONE_H */
