Index: data/totem.glade
===================================================================
RCS file: /cvs/gnome/totem/data/totem.glade,v
retrieving revision 1.102
diff -u -r1.102 totem.glade
--- data/totem.glade	10 Apr 2005 15:09:33 -0000	1.102
+++ data/totem.glade	6 May 2005 10:09:55 -0000
@@ -2957,96 +2829,18 @@
 		  </child>
 
 		  <child>
-		    <widget class="GtkVSeparator" id="tmw_buttons_vseparator">
+		    <widget class="Custom" id="tcw_volume_button">
 		      <property name="visible">True</property>
+		      <property name="creation_function">totem_volume_create</property>
+		      <property name="int1">0</property>
+		      <property name="int2">0</property>
+		      <property name="last_modification_time">Fri, 06 May 2005 09:19:48 GMT</property>
 		    </widget>
 		    <packing>
 		      <property name="padding">0</property>
 		      <property name="expand">False</property>
-		      <property name="fill">True</property>
-		    </packing>
-		  </child>
-
-		  <child>
-		    <widget class="GtkHBox" id="tmw_volume_hbox">
-		      <property name="visible">True</property>
-		      <property name="sensitive">False</property>
-		      <property name="homogeneous">False</property>
-		      <property name="spacing">0</property>
-
-		      <child>
-			<widget class="GtkButton" id="tmw_volume_mute_button">
-			  <property name="visible">True</property>
-			  <property name="can_focus">True</property>
-			  <property name="relief">GTK_RELIEF_NONE</property>
-			  <property name="focus_on_click">True</property>
-
-			  <child>
-			    <widget class="GtkImage" id="image8">
-			      <property name="visible">True</property>
-			      <property name="pixbuf">rhythmbox-volume-zero.png</property>
-			      <property name="xalign">0.5</property>
-			      <property name="yalign">0.5</property>
-			      <property name="xpad">0</property>
-			      <property name="ypad">0</property>
-			    </widget>
-			  </child>
-			</widget>
-			<packing>
-			  <property name="padding">0</property>
-			  <property name="expand">False</property>
-			  <property name="fill">False</property>
-			</packing>
-		      </child>
-
-		      <child>
-			<widget class="GtkHScale" id="tmw_volume_hscale">
-			  <property name="width_request">100</property>
-			  <property name="visible">True</property>
-			  <property name="can_focus">True</property>
-			  <property name="draw_value">False</property>
-			  <property name="value_pos">GTK_POS_TOP</property>
-			  <property name="digits">1</property>
-			  <property name="update_policy">GTK_UPDATE_CONTINUOUS</property>
-			  <property name="inverted">False</property>
-			  <property name="adjustment">0 0 100 1 10 0</property>
-			</widget>
-			<packing>
-			  <property name="padding">0</property>
-			  <property name="expand">True</property>
-			  <property name="fill">True</property>
-			</packing>
-		      </child>
-
-		      <child>
-			<widget class="GtkButton" id="tmw_volume_max_button">
-			  <property name="visible">True</property>
-			  <property name="can_focus">True</property>
-			  <property name="relief">GTK_RELIEF_NONE</property>
-			  <property name="focus_on_click">True</property>
-
-			  <child>
-			    <widget class="GtkImage" id="image9">
-			      <property name="visible">True</property>
-			      <property name="pixbuf">rhythmbox-volume-max.png</property>
-			      <property name="xalign">0.5</property>
-			      <property name="yalign">0.5</property>
-			      <property name="xpad">0</property>
-			      <property name="ypad">0</property>
-			    </widget>
-			  </child>
-			</widget>
-			<packing>
-			  <property name="padding">0</property>
-			  <property name="expand">False</property>
-			  <property name="fill">False</property>
-			</packing>
-		      </child>
-		    </widget>
-		    <packing>
-		      <property name="padding">0</property>
-		      <property name="expand">True</property>
-		      <property name="fill">True</property>
+		      <property name="fill">False</property>
+		      <property name="pack_type">GTK_PACK_END</property>
 		    </packing>
 		  </child>
 		</widget>
Index: src/Makefile.am
===================================================================
RCS file: /cvs/gnome/totem/src/Makefile.am,v
retrieving revision 1.141
diff -u -r1.141 Makefile.am
--- src/Makefile.am	30 Apr 2005 23:46:12 -0000	1.141
+++ src/Makefile.am	6 May 2005 10:09:55 -0000
@@ -90,7 +90,8 @@
 	totem-uri.c totem-uri.h		\
 	totem-statusbar.c		\
 	totem-statusbar.h		\
-	totem-gromit.c totem-gromit.h
+	totem-gromit.c totem-gromit.h	\
+	totem-volume.c totem-volume.h
 
 totem_LDADD = \
 	$(X_LIBS) $(EXTRA_GNOME_LIBS) $(XTEST_LIBS) $(REMOTE_LIBS) \
Index: src/totem-private.h
===================================================================
RCS file: /cvs/gnome/totem/src/totem-private.h,v
retrieving revision 1.30
diff -u -r1.30 totem-private.h
--- src/totem-private.h	1 Apr 2005 14:56:47 -0000	1.30
+++ src/totem-private.h	6 May 2005 10:09:56 -0000
@@ -83,7 +83,6 @@
 
 	/* Volume */
 	GtkWidget *volume;
-	GtkAdjustment *voladj;
 	gboolean vol_lock;
 	gboolean vol_fs_lock;
 	gfloat prev_volume;
Index: src/totem.c
===================================================================
RCS file: /cvs/gnome/totem/src/totem.c,v
retrieving revision 1.432
diff -u -r1.432 totem.c
--- src/totem.c	6 May 2005 08:02:06 -0000	1.432
+++ src/totem.c	6 May 2005 10:09:59 -0000
@@ -57,6 +57,7 @@
 #include "totem-options.h"
 #include "totem-uri.h"
 #include "totem-interface.h"
+#include "totem-volume.h"
 #include "video-utils.h"
 
 #include "totem.h"
@@ -639,11 +640,7 @@
 		update_seekable (totem, FALSE);
 
 		/* Volume */
-		widget = glade_xml_get_widget (totem->xml, "tmw_volume_hbox");
-		gtk_widget_set_sensitive (widget, FALSE);
-		widget = glade_xml_get_widget (totem->xml, "tmw_volume_up_menu_item");
-		gtk_widget_set_sensitive (widget, FALSE);
-		widget = glade_xml_get_widget (totem->xml, "tmw_volume_down_menu_item");
+		widget = glade_xml_get_widget (totem->xml, "tcw_volume_button");
 		gtk_widget_set_sensitive (widget, FALSE);
 		widget = glade_xml_get_widget (totem->xml_popup, "trcm_volume_up");
 		gtk_widget_set_sensitive (widget, FALSE);
@@ -705,11 +702,7 @@
 
 		/* Volume */
 		caps = bacon_video_widget_can_set_volume (totem->bvw);
-		widget = glade_xml_get_widget (totem->xml, "tmw_volume_hbox");
-		gtk_widget_set_sensitive (widget, caps);
-		widget = glade_xml_get_widget (totem->xml, "tmw_volume_up_menu_item");
-		gtk_widget_set_sensitive (widget, caps);
-		widget = glade_xml_get_widget (totem->xml, "tmw_volume_down_menu_item");
+		widget = glade_xml_get_widget (totem->xml, "tcw_volume_button");
 		gtk_widget_set_sensitive (widget, caps);
 		widget = glade_xml_get_widget (totem->xml, "tcw_volume_hbox");
 		gtk_widget_set_sensitive (widget, caps);
@@ -1299,8 +1292,8 @@
 				totem->prev_volume != -1 && volume != -1))
 	{
 		totem->volume_first_time = 0;
-		gtk_adjustment_set_value (totem->voladj,
-				(float) volume);
+		totem_volume_button_set_value (
+			TOTEM_VOLUME_BUTTON (totem->volume), (float) volume);
 		gtk_adjustment_set_value (totem->fs_voladj,
 				(float) volume);
 	}
@@ -1380,17 +1373,16 @@
 				(totem->bvw, (gint) totem->fs_voladj->value);
 
 			/* Update the fullscreen volume adjustment */
-			gtk_adjustment_set_value (totem->voladj, 
-					gtk_adjustment_get_value
-					(totem->fs_voladj));
+			totem_volume_button_set_value (
+				TOTEM_VOLUME_BUTTON (totem->volume),
+				gtk_adjustment_get_value (totem->fs_voladj));
 		} else {
-			bacon_video_widget_set_volume
-				(totem->bvw, (gint) totem->voladj->value);
-			/* Update the volume adjustment */
-			gtk_adjustment_set_value (totem->fs_voladj, 
-					gtk_adjustment_get_value
-					(totem->voladj));
+			int value = totem_volume_button_get_value (
+				TOTEM_VOLUME_BUTTON (totem->volume));
 
+			bacon_video_widget_set_volume (totem->bvw, value);
+			/* Update the volume adjustment */
+			gtk_adjustment_set_value (totem->fs_voladj, value);
 		}
 
 		totem->vol_lock = FALSE;
@@ -3300,6 +3292,17 @@
 }
 
 GtkWidget *
+totem_volume_create (void)
+{
+	GtkWidget *widget;
+
+	widget = totem_volume_button_new (0, 100, -1);
+	gtk_widget_show (widget);
+
+	return widget;
+}
+
+GtkWidget *
 totem_statusbar_create (void)
 {
 	GtkWidget *widget;
@@ -3438,8 +3441,7 @@
 	totem->seek = glade_xml_get_widget (totem->xml, "tmw_seek_hscale");
 	totem->seekadj = gtk_range_get_adjustment (GTK_RANGE (totem->seek));
 	g_object_set_data (G_OBJECT (totem->seek), "fs", GINT_TO_POINTER (0));
-	totem->volume = glade_xml_get_widget (totem->xml, "tmw_volume_hscale");
-	totem->voladj = gtk_range_get_adjustment (GTK_RANGE (totem->volume));
+	totem->volume = glade_xml_get_widget (totem->xml, "tcw_volume_button");
 	g_object_set_data (G_OBJECT (totem->volume), "fs", GINT_TO_POINTER (0));
 	totem->exit_popup = glade_xml_get_widget
 		(totem->xml, "totem_exit_fullscreen_window");
--- /dev/null	2005-05-06 11:42:19.422308544 +0200
+++ src/totem-volume.c	2005-05-06 12:09:16.657814608 +0200
@@ -0,0 +1,436 @@
+/* 
+ * (c) bla
+ */
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#define _GNU_SOURCE
+#include <math.h>
+#include <string.h>
+#include <gtk/gtk.h>
+#include "totem-volume.h"
+
+enum {
+  SIGNAL_VALUE_CHANGED,
+  NUM_SIGNALS
+};
+
+static void	totem_volume_button_class_init	(TotemVolumeButtonClass * klass);
+static void	totem_volume_button_init	(TotemVolumeButton * button);
+static void	totem_volume_button_dispose	(GObject        * object);
+
+static gboolean	totem_volume_button_scroll	(GtkWidget      * widget,
+						 GdkEventScroll * event);
+static gboolean	totem_volume_button_press	(GtkWidget      * widget,
+						 GdkEventButton * event);
+
+/* see below for scale definitions */
+static GtkWidget *totem_volume_scale_new	(TotemVolumeButton * button,
+						 float min, float max,
+						 float step);
+
+static GtkButtonClass *parent_class = NULL;
+static guint signals[NUM_SIGNALS] = { 0 };
+
+GType
+totem_volume_button_get_type (void)
+{
+  static GType totem_volume_button_type = 0;
+
+  if (!totem_volume_button_type) {
+    static const GTypeInfo totem_volume_button_info = {
+      sizeof (TotemVolumeButtonClass),
+      NULL,
+      NULL,
+      (GClassInitFunc) totem_volume_button_class_init,
+      NULL,
+      NULL,
+      sizeof (TotemVolumeButton),
+      0,
+      (GInstanceInitFunc) totem_volume_button_init,
+      NULL
+    };
+
+    totem_volume_button_type =
+	g_type_register_static (GTK_TYPE_BUTTON, 
+				"TotemVolumeButton",
+				&totem_volume_button_info, 0);
+  }
+
+  return totem_volume_button_type;
+}
+
+static void
+totem_volume_button_class_init (TotemVolumeButtonClass *klass)
+{
+  GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
+  GtkWidgetClass *gtkwidget_class = GTK_WIDGET_CLASS (klass);
+
+  parent_class = g_type_class_ref (GTK_TYPE_BUTTON);
+
+  /* events */
+  gobject_class->dispose = totem_volume_button_dispose;
+  gtkwidget_class->button_press_event = totem_volume_button_press;
+  gtkwidget_class->scroll_event = totem_volume_button_scroll;
+
+  /* signals */
+  signals[SIGNAL_VALUE_CHANGED] = g_signal_new ("value-changed",
+      G_TYPE_FROM_CLASS (klass), G_SIGNAL_RUN_LAST,
+      G_STRUCT_OFFSET (TotemVolumeButtonClass, value_changed),
+      NULL, NULL, g_cclosure_marshal_VOID__VOID, G_TYPE_NONE, 0);
+}
+
+static void
+totem_volume_button_init (TotemVolumeButton *button)
+{
+  button->timeout = FALSE;
+  button->dock = button->scale = NULL;
+  button->theme = gtk_icon_theme_get_default ();
+}
+
+static void
+totem_volume_button_dispose (GObject *object)
+{
+  TotemVolumeButton *button = TOTEM_VOLUME_BUTTON (object);
+
+  if (button->dock) {
+    gtk_widget_destroy (button->dock);
+    button->dock = NULL;
+  }
+
+  if (button->theme) {
+    g_object_unref (G_OBJECT (button->theme));
+    button->theme = NULL;
+  }
+
+  G_OBJECT_CLASS (parent_class)->dispose (object);
+}
+
+/*
+ * public API.
+ */
+
+GtkWidget *
+totem_volume_button_new (float min, float max,
+			 float step)
+{
+  TotemVolumeButton *button;
+  GtkWidget *frame;
+
+  button = g_object_new (TOTEM_TYPE_VOLUME_BUTTON, NULL);
+  button->min = min;
+  button->max = max;
+
+  /* image */
+  button->image = gtk_image_new ();
+  gtk_container_add (GTK_CONTAINER (button), button->image);
+  //gtk_button_set_image (GTK_BUTTON (button), button->image);
+  gtk_widget_show_all (button->image);
+
+  /* window */
+  button->dock = gtk_window_new (GTK_WINDOW_POPUP);
+  gtk_window_set_decorated (GTK_WINDOW (button->dock), FALSE);
+
+  /* frame */
+  frame = gtk_frame_new (NULL);
+  gtk_frame_set_shadow_type (GTK_FRAME (frame), GTK_SHADOW_OUT);
+  gtk_container_add (GTK_CONTAINER (button->dock), frame);
+
+  /* scale */
+  button->scale = totem_volume_scale_new (button, min, max, step);
+  gtk_widget_set_size_request (button->scale, -1, 100);
+  gtk_scale_set_draw_value (GTK_SCALE (button->scale), FALSE);
+  gtk_range_set_inverted (GTK_RANGE (button->scale), TRUE);
+  gtk_container_add (GTK_CONTAINER (frame), button->scale);
+
+  return GTK_WIDGET (button);
+}
+
+float
+totem_volume_button_get_value (TotemVolumeButton * button)
+{
+  g_return_val_if_fail (button != NULL, 0);
+
+  return gtk_range_get_value (GTK_RANGE (button->scale));
+}
+
+void
+totem_volume_button_set_value (TotemVolumeButton * button,
+			       float value)
+{
+  g_return_if_fail (button != NULL);
+
+  gtk_range_set_value (GTK_RANGE (button->scale), value);
+}
+
+/*
+ * button callbacks.
+ */
+
+static gboolean
+totem_volume_button_scroll (GtkWidget      * widget,
+			    GdkEventScroll * event)
+{
+  TotemVolumeButton *button = TOTEM_VOLUME_BUTTON (widget);
+  float d;
+
+  if (event->type != GDK_SCROLL)
+    return FALSE;
+
+  d = totem_volume_button_get_value (button);
+  if (event->direction == GDK_SCROLL_UP) {
+    d += 5;
+    if (d > button->max)
+      d = button->max;
+  } else {
+    d -= 5;
+    if (d < button->min)
+      d = button->min;
+  }
+  totem_volume_button_set_value (button, d);
+
+  return TRUE;
+}
+
+static gboolean
+totem_volume_button_press (GtkWidget      * widget,
+			   GdkEventButton * event)
+{
+  TotemVolumeButton *button = TOTEM_VOLUME_BUTTON (widget);
+  gint x, y, m, sx, sy, v;
+  GdkEventButton *e;
+
+  /* position roughly */
+  gdk_window_get_origin (widget->window, &x, &y);
+  gtk_window_move (GTK_WINDOW (button->dock), x, y - 50);
+  gtk_widget_show_all (button->dock);
+  button->timeout = TRUE;
+
+  /* position (needs widget to be shown already) */
+  v = lrintf (totem_volume_button_get_value (button));
+  x += widget->allocation.x;
+  x -= (widget->allocation.width - button->dock->allocation.width) / 2;
+  y += widget->allocation.y;
+  m = button->dock->allocation.height - widget->allocation.height;
+  y -= m;
+  y += m * v / 100;
+  gtk_window_move (GTK_WINDOW (button->dock), x, y);
+  gdk_window_get_origin (button->scale->window, &sx, &sy);
+
+  GTK_WIDGET_CLASS (parent_class)->button_press_event (widget, event);
+
+  /* grab focus */
+  gtk_widget_grab_focus (button->scale);
+  gtk_grab_add (button->scale);
+  gdk_pointer_grab (button->scale->window, TRUE,
+      GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK |
+      GDK_POINTER_MOTION_MASK, NULL, NULL, GDK_CURRENT_TIME);
+  gdk_keyboard_grab (button->scale->window, TRUE, GDK_CURRENT_TIME);
+
+  /* forward event to the slider */
+  e = (GdkEventButton *) gdk_event_copy ((GdkEvent *) event);
+  e->window = button->scale->window;
+  e->x = button->scale->allocation.width / 2;
+  /* FIXME: those magic numbers are numbers in the GtkScaleClass */
+  e->y = ((10 + (80 - v * 0.8)) / 100.0) * button->scale->allocation.height;
+  gtk_widget_event (button->scale, (GdkEvent *) e);
+  e->window = event->window;
+  gdk_event_free ((GdkEvent *) e);
+
+  g_get_current_time (&button->pop_time);
+
+  return TRUE;
+}
+
+/*
+ * Scale callbacks.
+ */
+
+static void
+totem_volume_release_grab (TotemVolumeButton *button,
+			   GdkEventButton * event)
+{
+  GdkEventButton *e;
+
+  /* ungrab focus */
+  gdk_keyboard_ungrab (GDK_CURRENT_TIME);
+  gdk_pointer_ungrab (GDK_CURRENT_TIME);
+  gtk_grab_remove (button->scale);
+
+  /* hide again */
+  gtk_widget_hide (button->dock);
+  button->timeout = FALSE;
+
+  e = (GdkEventButton *) gdk_event_copy ((GdkEvent *) event);
+  e->window = GTK_WIDGET (button)->window;
+  e->type = GDK_BUTTON_RELEASE;
+  gtk_widget_event (GTK_WIDGET (button), (GdkEvent *) e);
+  e->window = event->window;
+  gdk_event_free ((GdkEvent *) e);
+}
+
+/*
+ * Scale stuff.
+ */
+
+#define TOTEM_TYPE_VOLUME_SCALE \
+  (totem_volume_scale_get_type ())
+#define TOTEM_VOLUME_SCALE(obj) \
+  (G_TYPE_CHECK_INSTANCE_CAST ((obj), TOTEM_TYPE_VOLUME_SCALE, \
+			       TotemVolumeScale))
+
+typedef struct _TotemVolumeScale {
+  GtkVScale parent;
+  TotemVolumeButton *button;
+} TotemVolumeScale;
+
+static void	totem_volume_scale_class_init    (GtkVScaleClass * klass);
+
+static gboolean	totem_volume_scale_press	 (GtkWidget      * widget,
+						  GdkEventButton * event);
+static gboolean totem_volume_scale_release	 (GtkWidget      * widget,
+						  GdkEventButton * event);
+static void	totem_volume_scale_value_changed (GtkRange      * range);
+
+static GtkVScaleClass *scale_parent_class = NULL;
+
+GType
+totem_volume_scale_get_type (void)
+{
+  static GType totem_volume_scale_type = 0;
+
+  if (!totem_volume_scale_type) {
+    static const GTypeInfo totem_volume_scale_info = {
+      sizeof (GtkVScaleClass),
+      NULL,
+      NULL,
+      (GClassInitFunc) totem_volume_scale_class_init,
+      NULL,
+      NULL,
+      sizeof (TotemVolumeScale),
+      0,
+      NULL,
+      NULL
+    };
+
+    totem_volume_scale_type =
+        g_type_register_static (GTK_TYPE_VSCALE,
+				"TotemVolumeScale",
+				&totem_volume_scale_info, 0);
+  }
+
+  return totem_volume_scale_type;
+}
+
+static void
+totem_volume_scale_class_init (GtkVScaleClass * klass)
+{
+  GtkWidgetClass *gtkwidget_class = GTK_WIDGET_CLASS (klass);
+  GtkRangeClass *gtkrange_class = GTK_RANGE_CLASS (klass);
+
+  scale_parent_class = g_type_class_ref (GTK_TYPE_VSCALE);
+
+  gtkwidget_class->button_press_event = totem_volume_scale_press;
+  gtkwidget_class->button_release_event = totem_volume_scale_release;
+  gtkrange_class->value_changed = totem_volume_scale_value_changed;
+}
+
+static GtkWidget *
+totem_volume_scale_new (TotemVolumeButton * button,
+			float min, float max,
+			float step)
+{
+  TotemVolumeScale *scale = g_object_new (TOTEM_TYPE_VOLUME_SCALE, NULL);
+  GtkObject *adj;
+
+  adj = gtk_adjustment_new (min, min, max, step, 10 * step, 0);
+  gtk_range_set_adjustment (GTK_RANGE (scale), GTK_ADJUSTMENT (adj));
+  scale->button = button;
+
+  return GTK_WIDGET (scale);
+}
+
+static gboolean
+totem_volume_scale_press (GtkWidget      * widget,
+			  GdkEventButton * event)
+{
+  TotemVolumeScale *scale = TOTEM_VOLUME_SCALE (widget);
+  TotemVolumeButton *button = scale->button;
+
+  /* if input is grabbed and we click outside the window, popdown */
+  if (gdk_window_get_parent (event->window) != button->scale->window &&
+      !(event->window == button->scale->window && button->timeout) &&
+      event->type == GDK_BUTTON_PRESS) {
+    totem_volume_release_grab (button, event);
+    return TRUE;
+  }
+
+  /* the scale will grab input; if we have input grabbed, all goes
+   * horribly wrong, so let's not do that. */
+  gtk_grab_remove (button->scale);
+
+  return GTK_WIDGET_CLASS (scale_parent_class)->button_press_event (widget, event);
+}
+
+static gboolean
+totem_volume_scale_release (GtkWidget      * widget,
+			    GdkEventButton * event)
+{
+  TotemVolumeScale *scale = TOTEM_VOLUME_SCALE (widget);
+  TotemVolumeButton *button = scale->button;
+  gboolean res;
+
+  if (button->timeout) {
+    GTimeVal unclick_tv;
+
+    /* if we did a quick click, leave the window open; else, hide it */
+    g_get_current_time (&unclick_tv);
+    if ((guint64) unclick_tv.tv_usec +
+        (guint64) unclick_tv.tv_sec * 1000000 >
+        (guint64) button->pop_time.tv_usec +
+        (guint64) button->pop_time.tv_sec * 1000000 + 200000) {
+      totem_volume_release_grab (button, event);
+      return TRUE;
+    }
+    button->timeout = FALSE;
+  }
+
+  res = GTK_WIDGET_CLASS (scale_parent_class)->button_release_event (widget, event);
+
+  /* the scale will release input; right after that, we *have to* grab
+   * it back so we can catch out-of-scale clicks and hide the popup,
+   * so I basically want a g_signal_connect_after_always(), but I can't
+   * find that, so we do this complex 'first-call-parent-then-do-actual-
+   * action' thingy... */
+  gtk_grab_add (button->scale);
+
+  return res;
+}
+
+static void
+totem_volume_scale_value_changed (GtkRange * range)
+{
+  TotemVolumeScale *scale = TOTEM_VOLUME_SCALE (range);
+  TotemVolumeButton *button = scale->button;
+  const char *s;
+  float val = gtk_range_get_value (range);
+  GdkPixbuf *buf;
+
+  if (val >= 0 && val < 25)
+    s = "stock_volume-0";
+  else if (val >= 25 && val < 50)
+    s = "stock_volume-min";
+  else if (val >= 50 && val < 75)
+    s = "stock_volume-med";
+  else
+    s = "stock_volume-max";
+
+  /* update label */
+  buf = gtk_icon_theme_load_icon (button->theme, s, 16, 0, NULL);
+  gtk_image_set_from_pixbuf (GTK_IMAGE (button->image), buf);
+
+  /* signal */
+  g_signal_emit (button, signals[SIGNAL_VALUE_CHANGED], 0);
+}
--- /dev/null	2005-05-06 11:42:19.422308544 +0200
+++ src/totem-volume.h	2005-05-06 12:07:58.146750104 +0200
@@ -0,0 +1,48 @@
+/*
+ * (c) bla
+ */
+
+#ifndef __BUTTON_H__
+#define __BUTTON_H__
+
+#include <gtk/gtkbutton.h>
+
+G_BEGIN_DECLS
+
+#define TOTEM_TYPE_VOLUME_BUTTON \
+  (totem_volume_button_get_type ())
+#define TOTEM_VOLUME_BUTTON(obj) \
+  (G_TYPE_CHECK_INSTANCE_CAST ((obj), TOTEM_TYPE_VOLUME_BUTTON, \
+			       TotemVolumeButton))
+
+typedef struct _TotemVolumeButton {
+  GtkButton parent;
+
+  /* popup */
+  GtkWidget *dock, *scale, *image;
+  float min, max;
+  gboolean timeout;
+  GTimeVal pop_time;
+  GtkIconTheme *theme;
+} TotemVolumeButton;
+
+typedef struct _TotemVolumeButtonClass {
+  GtkButtonClass parent_class;
+
+  /* signals */
+  void	(* value_changed)	(TotemVolumeButton * button);
+
+  gpointer __bla[4];
+} TotemVolumeButtonClass;
+
+GType		totem_volume_button_get_type	(void);
+
+GtkWidget *	totem_volume_button_new		(float min, float max,
+						 float step);
+float		totem_volume_button_get_value	(TotemVolumeButton * button);
+void		totem_volume_button_set_value	(TotemVolumeButton * button,
+						 float value);
+
+G_END_DECLS
+
+#endif /* __BUTTON_H__ */
