]> Pileus Git - ~andy/gtk/commitdiff
Bug 442042 – GtkScaleButton is too limited
authorMichael Natterer <mitch@imendio.com>
Fri, 27 Jun 2008 09:33:32 +0000 (09:33 +0000)
committerMichael Natterer <mitch@src.gnome.org>
Fri, 27 Jun 2008 09:33:32 +0000 (09:33 +0000)
2008-06-27  Michael Natterer  <mitch@imendio.com>

Bug 442042 – GtkScaleButton is too limited

* gtk/gtkscalebutton.c: add "orientation" property. Make sure the
stuff that is part of the public API continues to be created in
init() to stay compatible. Move creating of the popup scale to
constructor(). Add an internal HScale class. Changed popup
positioning for horizontal scales accordingly.

svn path=/trunk/; revision=20692

ChangeLog
gtk/gtkscalebutton.c

index 1e04c5cefc5306060708dec8e719c0012f7c6000..ee2b99e91b070485a920053a2975a5ec6c9ef846 100644 (file)
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,13 @@
+2008-06-27  Michael Natterer  <mitch@imendio.com>
+
+       Bug 442042 – GtkScaleButton is too limited
+
+       * gtk/gtkscalebutton.c: add "orientation" property. Make sure the
+       stuff that is part of the public API continues to be created in
+       init() to stay compatible. Move creating of the popup scale to
+       constructor(). Add an internal HScale class. Changed popup
+       positioning for horizontal scales accordingly.
+
 2008-06-26  Michael Natterer  <mitch@imendio.com>
 
        * gtk/gtkscalebutton.c
index daefdeeab338805e77ff0f86c370aea5a8f2bbdf..9455295d85759e1f50d400ef6b30633d81a1149e 100644 (file)
@@ -46,6 +46,7 @@
 #include "gtkmain.h"
 #include "gtkintl.h"
 #include "gtkbindings.h"
+#include "gtkhscale.h"
 #include "gtkvscale.h"
 #include "gtkframe.h"
 #include "gtkvbox.h"
@@ -73,6 +74,7 @@ enum
 {
   PROP_0,
 
+  PROP_ORIENTATION,
   PROP_VALUE,
   PROP_SIZE,
   PROP_ADJUSTMENT,
@@ -88,6 +90,7 @@ struct _GtkScaleButtonPrivate
   GtkWidget *image;
 
   GtkIconSize size;
+  GtkOrientation orientation;
 
   guint click_id;
   gint click_timeout;
@@ -96,8 +99,13 @@ struct _GtkScaleButtonPrivate
   guint32 pop_time;
 
   gchar **icon_list;
+
+  GtkAdjustment *adjustment; /* needed because it must be settable in init() */
 };
 
+static GObject* gtk_scale_button_constructor    (GType                  type,
+                                                 guint                  n_construct_properties,
+                                                 GObjectConstructParam *construct_params);
 static void    gtk_scale_button_dispose        (GObject             *object);
 static void     gtk_scale_button_finalize       (GObject             *object);
 static void    gtk_scale_button_set_property   (GObject             *object,
@@ -143,10 +151,10 @@ static void gtk_scale_button_update_icon  (GtkScaleButton      *button);
 static void gtk_scale_button_scale_value_changed(GtkRange            *range);
 
 /* see below for scale definitions */
-static GtkWidget *gtk_scale_button_scale_new   (GtkScaleButton      *button,
-                                                gdouble              min,
-                                                gdouble              max,
-                                                gdouble              step);
+static GtkWidget *gtk_scale_button_scale_new    (GtkScaleButton      *button,
+                                                 gdouble              min,
+                                                 gdouble              max,
+                                                 gdouble              step);
 
 static guint signals[LAST_SIGNAL] = { 0, };
 
@@ -161,6 +169,7 @@ gtk_scale_button_class_init (GtkScaleButtonClass *klass)
 
   g_type_class_add_private (klass, sizeof (GtkScaleButtonPrivate));
 
+  gobject_class->constructor = gtk_scale_button_constructor;
   gobject_class->finalize = gtk_scale_button_finalize;
   gobject_class->dispose = gtk_scale_button_dispose;
   gobject_class->set_property = gtk_scale_button_set_property;
@@ -171,6 +180,16 @@ gtk_scale_button_class_init (GtkScaleButtonClass *klass)
   widget_class->scroll_event = gtk_scale_button_scroll;
   widget_class->screen_changed = gtk_scale_button_screen_changed;
 
+  g_object_class_install_property (gobject_class,
+                                  PROP_ORIENTATION,
+                                  g_param_spec_enum ("orientation",
+                                                      P_("Orientation"),
+                                                      P_("The orientation of the scale"),
+                                                      GTK_TYPE_ORIENTATION,
+                                                      GTK_ORIENTATION_VERTICAL,
+                                                      GTK_PARAM_READWRITE |
+                                                      G_PARAM_CONSTRUCT_ONLY));
+
   g_object_class_install_property (gobject_class,
                                   PROP_VALUE,
                                   g_param_spec_double ("value",
@@ -308,7 +327,6 @@ gtk_scale_button_class_init (GtkScaleButtonClass *klass)
 static void
 gtk_scale_button_init (GtkScaleButton *button)
 {
-  GtkWidget *frame, *box;
   GtkScaleButtonPrivate *priv;
 
   button->priv = priv = GET_PRIVATE (button);
@@ -337,6 +355,42 @@ gtk_scale_button_init (GtkScaleButton *button)
                    G_CALLBACK (cb_dock_grab_broken_event), button);
   gtk_window_set_decorated (GTK_WINDOW (priv->dock), FALSE);
 
+  /* + */
+  button->plus_button = gtk_button_new_with_label ("+");
+  gtk_button_set_relief (GTK_BUTTON (button->plus_button), GTK_RELIEF_NONE);
+  g_signal_connect (button->plus_button, "button-press-event",
+                   G_CALLBACK (cb_button_press), button);
+  g_signal_connect (button->plus_button, "button-release-event",
+                   G_CALLBACK (cb_button_release), button);
+
+  /* - */
+  button->minus_button = gtk_button_new_with_label ("-");
+  gtk_button_set_relief (GTK_BUTTON (button->minus_button), GTK_RELIEF_NONE);
+  g_signal_connect (button->minus_button, "button-press-event",
+                  G_CALLBACK (cb_button_press), button);
+  g_signal_connect (button->minus_button, "button-release-event",
+                   G_CALLBACK (cb_button_release), button);
+
+  priv->adjustment = GTK_ADJUSTMENT (gtk_adjustment_new (0.0, 0.0, 100.0, 2, 20, 0));
+  g_object_ref_sink (priv->adjustment);
+}
+
+static GObject *
+gtk_scale_button_constructor (GType                  type,
+                              guint                  n_construct_properties,
+                              GObjectConstructParam *construct_params)
+{
+  GObject *object;
+  GtkScaleButton *button;
+  GtkWidget *frame, *box;
+  GtkScaleButtonPrivate *priv;
+
+  object = G_OBJECT_CLASS (gtk_scale_button_parent_class)->constructor (type, n_construct_properties, construct_params);
+
+  button = GTK_SCALE_BUTTON (object);
+
+  priv = button->priv;
+
   /* frame */
   frame = gtk_frame_new (NULL);
   gtk_frame_set_shadow_type (GTK_FRAME (frame), GTK_SHADOW_OUT);
@@ -345,35 +399,33 @@ gtk_scale_button_init (GtkScaleButton *button)
   gtk_container_add (GTK_CONTAINER (frame), box);
 
   /* + */
-  button->plus_button = gtk_button_new_with_label ("+");
-  gtk_button_set_relief (GTK_BUTTON (button->plus_button), GTK_RELIEF_NONE);
-  g_signal_connect (button->plus_button, "button-press-event",
-                   G_CALLBACK (cb_button_press), button);
-  g_signal_connect (button->plus_button, "button-release-event",
-                   G_CALLBACK (cb_button_release), button);
   gtk_box_pack_start (GTK_BOX (box), button->plus_button, TRUE, FALSE, 0);
 
   /* scale */
   priv->scale = gtk_scale_button_scale_new (button, 0., 100., 2.);
-  gtk_widget_set_size_request (priv->scale, -1, SCALE_SIZE);
+  if (priv->orientation == GTK_ORIENTATION_VERTICAL)
+    {
+      gtk_widget_set_size_request (priv->scale, -1, SCALE_SIZE);
+      gtk_range_set_inverted (GTK_RANGE (priv->scale), TRUE);
+    }
+  else
+    {
+      gtk_widget_set_size_request (priv->scale, SCALE_SIZE, -1);
+    }
+
   gtk_scale_set_draw_value (GTK_SCALE (priv->scale), FALSE);
-  gtk_range_set_inverted (GTK_RANGE (priv->scale), TRUE);
   gtk_box_pack_start (GTK_BOX (box), priv->scale, TRUE, FALSE, 0);
   g_signal_connect (priv->scale, "grab-notify",
                    G_CALLBACK (cb_scale_grab_notify), button);
 
   /* - */
-  button->minus_button = gtk_button_new_with_label ("-");
-  gtk_button_set_relief (GTK_BUTTON (button->minus_button), GTK_RELIEF_NONE);
-  g_signal_connect (button->minus_button, "button-press-event",
-                  G_CALLBACK (cb_button_press), button);
-  g_signal_connect (button->minus_button, "button-release-event",
-                   G_CALLBACK (cb_button_release), button);
   gtk_box_pack_start (GTK_BOX (box), button->minus_button, TRUE, FALSE, 0);
 
   /* set button text and size */
   priv->size = GTK_ICON_SIZE_SMALL_TOOLBAR;
   gtk_scale_button_update_icon (button);
+
+  return object;
 }
 
 static void
@@ -388,6 +440,9 @@ gtk_scale_button_set_property (GObject       *object,
 
   switch (prop_id)
     {
+    case PROP_ORIENTATION:
+      button->priv->orientation = g_value_get_enum (value);
+      break;
     case PROP_VALUE:
       gtk_scale_button_set_value (button, g_value_get_double (value));
       break;
@@ -429,6 +484,9 @@ gtk_scale_button_get_property (GObject     *object,
 
   switch (prop_id)
     {
+    case PROP_ORIENTATION:
+      g_value_set_enum (value, priv->orientation);
+      break;
     case PROP_VALUE:
       g_value_set_double (value, gtk_scale_button_get_value (button));
       break;
@@ -459,6 +517,12 @@ gtk_scale_button_finalize (GObject *object)
       priv->icon_list = NULL;
     }
 
+  if (priv->adjustment)
+    {
+      g_object_unref (priv->adjustment);
+      priv->adjustment = NULL;
+    }
+
   G_OBJECT_CLASS (gtk_scale_button_parent_class)->finalize (object);
 }
 
@@ -540,7 +604,7 @@ gtk_scale_button_get_value (GtkScaleButton * button)
 
   priv = button->priv;
 
-  return gtk_range_get_value (GTK_RANGE (priv->scale));
+  return gtk_adjustment_get_value (priv->adjustment);
 }
 
 /**
@@ -611,14 +675,9 @@ gtk_scale_button_set_icons (GtkScaleButton  *button,
 GtkAdjustment*
 gtk_scale_button_get_adjustment        (GtkScaleButton *button)
 {
-  GtkRange *range;
-
   g_return_val_if_fail (GTK_IS_SCALE_BUTTON (button), NULL);
 
-  range = GTK_RANGE (button->priv->scale);
-  g_return_val_if_fail (range != NULL, NULL);
-
-  return gtk_range_get_adjustment (range);
+  return button->priv->adjustment;
 }
 
 /**
@@ -639,8 +698,12 @@ gtk_scale_button_set_adjustment    (GtkScaleButton *button,
   g_return_if_fail (GTK_IS_SCALE_BUTTON (button));
   g_return_if_fail (GTK_IS_ADJUSTMENT (adjustment));
 
-  gtk_range_set_adjustment (GTK_RANGE (button->priv->scale),
-                           adjustment);
+  if (button->priv->adjustment)
+    g_object_unref (button->priv->adjustment);
+  button->priv->adjustment = g_object_ref_sink (adjustment);
+
+  if (button->priv->scale)
+    gtk_range_set_adjustment (GTK_RANGE (button->priv->scale), adjustment);
 
   g_object_notify (G_OBJECT (button), "adjustment");
 }
@@ -660,7 +723,7 @@ gtk_scale_button_scroll (GtkWidget      *widget,
 
   button = GTK_SCALE_BUTTON (widget);
   priv = button->priv;
-  adj = gtk_range_get_adjustment (GTK_RANGE (priv->scale));
+  adj = priv->adjustment;
 
   if (event->type != GDK_SCROLL)
     return FALSE;
@@ -718,14 +781,14 @@ gtk_scale_popup (GtkWidget *widget,
   GtkScaleButton *button;
   GtkScaleButtonPrivate *priv;
   GtkAdjustment *adj;
-  gint x, y, m, dx, dy, sx, sy, ystartoff;
+  gint x, y, m, dx, dy, sx, sy, startoff;
   gdouble v;
   GdkDisplay *display;
   GdkScreen *screen;
 
   button = GTK_SCALE_BUTTON (widget);
   priv = button->priv;
-  adj = gtk_range_get_adjustment (GTK_RANGE (priv->scale));
+  adj = priv->adjustment;
 
   display = gtk_widget_get_display (widget);
   screen = gtk_widget_get_screen (widget);
@@ -736,23 +799,49 @@ gtk_scale_popup (GtkWidget *widget,
   gdk_window_get_origin (widget->window, &x, &y);
   x += widget->allocation.x;
   y += widget->allocation.y;
-  gtk_window_move (GTK_WINDOW (priv->dock), x, y - (SCALE_SIZE / 2));
+
+  if (priv->orientation == GTK_ORIENTATION_VERTICAL)
+    gtk_window_move (GTK_WINDOW (priv->dock), x, y - (SCALE_SIZE / 2));
+  else
+    gtk_window_move (GTK_WINDOW (priv->dock), x - (SCALE_SIZE / 2), y);
+
   gtk_widget_show_all (priv->dock);
+
   gdk_window_get_origin (priv->dock->window, &dx, &dy);
+  dx += priv->dock->allocation.x;
   dy += priv->dock->allocation.y;
+
   gdk_window_get_origin (priv->scale->window, &sx, &sy);
+  sx += priv->scale->allocation.x;
   sy += priv->scale->allocation.y;
-  ystartoff = sy - dy;
+
   priv->timeout = TRUE;
 
   /* position (needs widget to be shown already) */
   v = gtk_scale_button_get_value (button) / (adj->upper - adj->lower);
-  x += (widget->allocation.width - priv->dock->allocation.width) / 2;
-  y -= ystartoff;
-  y -= GTK_RANGE (priv->scale)->min_slider_size / 2;
-  m = priv->scale->allocation.height -
-      GTK_RANGE (priv->scale)->min_slider_size;
-  y -= m * (1.0 - v);
+
+  if (priv->orientation == GTK_ORIENTATION_VERTICAL)
+    {
+      startoff = sy - dy;
+
+      x += (widget->allocation.width - priv->dock->allocation.width) / 2;
+      y -= startoff;
+      y -= GTK_RANGE (priv->scale)->min_slider_size / 2;
+      m = priv->scale->allocation.height -
+          GTK_RANGE (priv->scale)->min_slider_size;
+      y -= m * (1.0 - v);
+    }
+  else
+    {
+      startoff = sx - dx;
+
+      x -= startoff;
+      y += (widget->allocation.height - priv->dock->allocation.height) / 2;
+      x -= GTK_RANGE (priv->scale)->min_slider_size / 2;
+      m = priv->scale->allocation.width -
+          GTK_RANGE (priv->scale)->min_slider_size;
+      x -= m * v;
+    }
 
   /* Make sure the dock stays inside the monitor */
   if (event->type == GDK_BUTTON_PRESS)
@@ -768,7 +857,11 @@ gtk_scale_popup (GtkWidget *widget,
                                                 button_event->y_root);
       gdk_screen_get_monitor_geometry (screen, monitor, &rect);
 
-      y += button_event->y;
+      if (priv->orientation == GTK_ORIENTATION_VERTICAL)
+        y += button_event->y;
+      else
+        x += button_event->x;
+
       if (y < rect.y)
        y = rect.y;
       else if (y + d->allocation.height > rect.height + rect.y)
@@ -820,11 +913,23 @@ gtk_scale_popup (GtkWidget *widget,
       /* position: the X position isn't relevant, halfway will work just fine.
        * The vertical position should be *exactly* in the middle of the slider
        * of the scale; if we don't do that correctly, it'll move from its current
-       * position, which means a position change on-click, which is bad. */
-      e->x = priv->scale->allocation.width / 2;
-      m = priv->scale->allocation.height -
-       GTK_RANGE (priv->scale)->min_slider_size;
-      e->y = ((1.0 - v) * m) + GTK_RANGE (priv->scale)->min_slider_size / 2;
+       * position, which means a position change on-click, which is bad.
+       */
+      if (priv->orientation == GTK_ORIENTATION_VERTICAL)
+        {
+          e->x = priv->scale->allocation.width / 2;
+          m = priv->scale->allocation.height -
+              GTK_RANGE (priv->scale)->min_slider_size;
+          e->y = ((1.0 - v) * m) + GTK_RANGE (priv->scale)->min_slider_size / 2;
+        }
+      else
+        {
+          e->y = priv->scale->allocation.height / 2;
+          m = priv->scale->allocation.width -
+              GTK_RANGE (priv->scale)->min_slider_size;
+          e->x = (v * m) + GTK_RANGE (priv->scale)->min_slider_size / 2;
+        }
+
       gtk_widget_event (priv->scale, (GdkEvent *) e);
       e->window = button_event->window;
       gdk_event_free ((GdkEvent *) e);
@@ -910,7 +1015,7 @@ cb_button_timeout (gpointer user_data)
   if (priv->click_id == 0)
     return FALSE;
 
-  adj = gtk_range_get_adjustment (GTK_RANGE (priv->scale));
+  adj = priv->adjustment;
 
   val = gtk_scale_button_get_value (button);
   val += priv->direction;
@@ -946,7 +1051,7 @@ cb_button_press (GtkWidget      *widget,
 
   button = GTK_SCALE_BUTTON (user_data);
   priv = button->priv;
-  adj = gtk_range_get_adjustment (GTK_RANGE (priv->scale));
+  adj = priv->adjustment;
 
   if (priv->click_id != 0)
     g_source_remove (priv->click_id);
@@ -1109,30 +1214,54 @@ cb_scale_grab_notify (GtkWidget *widget,
  * Scale stuff.
  */
 
-#define GTK_TYPE_SCALE_BUTTON_SCALE \
-  (gtk_scale_button_scale_get_type ())
-#define GTK_SCALE_BUTTON_SCALE(obj) \
-  (G_TYPE_CHECK_INSTANCE_CAST ((obj), GTK_TYPE_SCALE_BUTTON_SCALE, \
-                              GtkScaleButtonScale))
+#define GTK_TYPE_SCALE_BUTTON_VSCALE    (gtk_scale_button_vscale_get_type ())
+#define GTK_SCALE_BUTTON_VSCALE(obj)    (G_TYPE_CHECK_INSTANCE_CAST ((obj), GTK_TYPE_SCALE_BUTTON_VSCALE, GtkScaleButtonVScale))
+#define GTK_IS_SCALE_BUTTON_VSCALE(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), GTK_TYPE_SCALE_BUTTON_VSCALE))
 
-typedef struct _GtkScaleButtonScaleClass {
+typedef struct _GtkScaleButtonVScale {
+  GtkVScale parent;
+  GtkScaleButton *button;
+} GtkScaleButtonVScale;
+
+typedef struct _GtkScaleButtonVScaleClass {
   GtkVScaleClass parent_class;
-} GtkScaleButtonScaleClass;
+} GtkScaleButtonVScaleClass;
+
+#define GTK_TYPE_SCALE_BUTTON_HSCALE    (gtk_scale_button_hscale_get_type ())
+#define GTK_SCALE_BUTTON_HSCALE(obj)    (G_TYPE_CHECK_INSTANCE_CAST ((obj), GTK_TYPE_SCALE_BUTTON_HSCALE, GtkScaleButtonHScale))
+#define GTK_IS_SCALE_BUTTON_HSCALE(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), GTK_TYPE_SCALE_BUTTON_HSCALE))
 
-typedef struct _GtkScaleButtonScale {
+typedef struct _GtkScaleButtonHScale {
   GtkVScale parent;
   GtkScaleButton *button;
-} GtkScaleButtonScale;
+} GtkScaleButtonHScale;
 
-static gboolean gtk_scale_button_scale_press   (GtkWidget      *widget,
+typedef struct _GtkScaleButtonHScaleClass {
+  GtkVScaleClass parent_class;
+} GtkScaleButtonHScaleClass;
+
+static gboolean        gtk_scale_button_scale_press   (GtkWidget      *widget,
                                                 GdkEventButton *event);
 static gboolean gtk_scale_button_scale_release (GtkWidget      *widget,
                                                 GdkEventButton *event);
 
-G_DEFINE_TYPE (GtkScaleButtonScale, gtk_scale_button_scale, GTK_TYPE_VSCALE)
+G_DEFINE_TYPE (GtkScaleButtonVScale, gtk_scale_button_vscale, GTK_TYPE_VSCALE)
+
+G_DEFINE_TYPE (GtkScaleButtonHScale, gtk_scale_button_hscale, GTK_TYPE_HSCALE)
+
+static void
+gtk_scale_button_vscale_class_init (GtkScaleButtonVScaleClass *klass)
+{
+  GtkWidgetClass *gtkwidget_class = GTK_WIDGET_CLASS (klass);
+  GtkRangeClass *gtkrange_class = GTK_RANGE_CLASS (klass);
+
+  gtkwidget_class->button_press_event = gtk_scale_button_scale_press;
+  gtkwidget_class->button_release_event = gtk_scale_button_scale_release;
+  gtkrange_class->value_changed = gtk_scale_button_scale_value_changed;
+}
 
 static void
-gtk_scale_button_scale_class_init (GtkScaleButtonScaleClass *klass)
+gtk_scale_button_hscale_class_init (GtkScaleButtonHScaleClass *klass)
 {
   GtkWidgetClass *gtkwidget_class = GTK_WIDGET_CLASS (klass);
   GtkRangeClass *gtkrange_class = GTK_RANGE_CLASS (klass);
@@ -1143,24 +1272,32 @@ gtk_scale_button_scale_class_init (GtkScaleButtonScaleClass *klass)
 }
 
 static void
-gtk_scale_button_scale_init (GtkScaleButtonScale *scale)
+gtk_scale_button_vscale_init (GtkScaleButtonVScale *scale)
+{
+}
+
+static void
+gtk_scale_button_hscale_init (GtkScaleButtonHScale *scale)
 {
 }
 
 static GtkWidget *
 gtk_scale_button_scale_new (GtkScaleButton *button,
-                           gdouble         min,
-                           gdouble         max,
-                           gdouble         step)
+                            gdouble         min,
+                            gdouble         max,
+                            gdouble         step)
 {
-  GtkScaleButtonScale *scale;
-  GtkScaleButtonPrivate *priv;
-  GtkObject *adj;
+  GtkScaleButtonPrivate *priv = button->priv;
+  GtkScaleButtonVScale *scale;
+
+  if (priv->orientation == GTK_ORIENTATION_VERTICAL)
+    scale = g_object_new (GTK_TYPE_SCALE_BUTTON_VSCALE, NULL);
+  else
+    scale = g_object_new (GTK_TYPE_SCALE_BUTTON_HSCALE, NULL);
+
+  gtk_range_set_adjustment (GTK_RANGE (scale),
+                            GTK_ADJUSTMENT (priv->adjustment));
 
-  priv = button->priv;
-  scale = g_object_new (GTK_TYPE_SCALE_BUTTON_SCALE, NULL);
-  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);
@@ -1170,46 +1307,59 @@ static gboolean
 gtk_scale_button_scale_press (GtkWidget      *widget,
                              GdkEventButton *event)
 {
-  GtkScaleButtonScale *scale;
   GtkScaleButtonPrivate *priv;
+  GtkWidgetClass *widget_class;
 
-  scale = GTK_SCALE_BUTTON_SCALE (widget);
-  priv = scale->button->priv;
+  if (GTK_IS_SCALE_BUTTON_VSCALE (widget))
+    {
+      priv = GTK_SCALE_BUTTON_VSCALE (widget)->button->priv;
+      widget_class = GTK_WIDGET_CLASS (gtk_scale_button_vscale_parent_class);
+    }
+  else
+    {
+      priv = GTK_SCALE_BUTTON_HSCALE (widget)->button->priv;
+      widget_class = GTK_WIDGET_CLASS (gtk_scale_button_hscale_parent_class);
+    }
 
   /* the scale will grab input; if we have input grabbed, all goes
    * horribly wrong, so let's not do that. */
   gtk_grab_remove (priv->dock);
 
-  return GTK_WIDGET_CLASS (gtk_scale_button_scale_parent_class)->button_press_event (widget, event);
+  return widget_class->button_press_event (widget, event);
 }
 
 static gboolean
 gtk_scale_button_scale_release (GtkWidget      *widget,
                                GdkEventButton *event)
 {
-  GtkScaleButtonScale *scale;
-  GtkScaleButtonPrivate *priv;
+  GtkScaleButton *button;
   GtkWidgetClass *widget_class;
   gboolean res;
 
-  scale = GTK_SCALE_BUTTON_SCALE (widget);
-  priv = scale->button->priv;
-
-  widget_class = GTK_WIDGET_CLASS (gtk_scale_button_scale_parent_class);
+  if (GTK_IS_SCALE_BUTTON_VSCALE (widget))
+    {
+      button = GTK_SCALE_BUTTON_VSCALE (widget)->button;
+      widget_class = GTK_WIDGET_CLASS (gtk_scale_button_vscale_parent_class);
+    }
+  else
+    {
+      button = GTK_SCALE_BUTTON_HSCALE (widget)->button;
+      widget_class = GTK_WIDGET_CLASS (gtk_scale_button_hscale_parent_class);
+    }
 
-  if (priv->timeout)
+  if (button->priv->timeout)
     {
       /* if we did a quick click, leave the window open; else, hide it */
-      if (event->time > priv->pop_time + priv->click_timeout)
+      if (event->time > button->priv->pop_time + button->priv->click_timeout)
         {
 
-         gtk_scale_button_release_grab (scale->button, event);
+         gtk_scale_button_release_grab (button, event);
          widget_class->button_release_event (widget, event);
 
          return TRUE;
        }
 
-      priv->timeout = FALSE;
+      button->priv->timeout = FALSE;
     }
 
   res = widget_class->button_release_event (widget, event);
@@ -1218,8 +1368,9 @@ gtk_scale_button_scale_release (GtkWidget      *widget,
    * 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 (priv->dock);
+   * action' thingy...
+   */
+  gtk_grab_add (button->priv->dock);
 
   return res;
 }
@@ -1256,7 +1407,7 @@ gtk_scale_button_update_icon (GtkScaleButton *button)
     }
 
   range = GTK_RANGE (priv->scale);
-  adj = gtk_range_get_adjustment (range);
+  adj = priv->adjustment;
   value = gtk_scale_button_get_value (button);
 
   /* The 2-icons special case */
@@ -1303,10 +1454,14 @@ gtk_scale_button_update_icon (GtkScaleButton *button)
 static void
 gtk_scale_button_scale_value_changed (GtkRange *range)
 {
-  GtkScaleButtonScale *scale = GTK_SCALE_BUTTON_SCALE (range);
-  GtkScaleButton *button = scale->button;
+  GtkScaleButton *button;
   gdouble value;
 
+  if (GTK_IS_SCALE_BUTTON_VSCALE (range))
+    button = GTK_SCALE_BUTTON_VSCALE (range)->button;
+  else
+    button = GTK_SCALE_BUTTON_HSCALE (range)->button;
+
   value = gtk_range_get_value (range);
 
   gtk_scale_button_update_icon (button);