]> Pileus Git - ~andy/gtk/blobdiff - gtk/gtkrange.c
Practically everything changed.
[~andy/gtk] / gtk / gtkrange.c
index 696198a1be4cb62d1339a423a35d4eec8686852c..3ade7d4a386f9c7dce56df203f4e9fb9f4f5c197 100644 (file)
@@ -1,4 +1,4 @@
-/* GTK - The GIMP Toolkit
+/* GTK - The GTK+ Toolkit
  * Copyright (C) 1995-1997 Peter Mattis, Spencer Kimball and Josh MacDonald
  * Copyright (C) 2001 Red Hat, Inc.
  *
@@ -25,7 +25,7 @@
  * GTK+ at ftp://ftp.gtk.org/pub/gtk/. 
  */
 
-#include <config.h>
+#include "config.h"
 #include <stdio.h>
 #include <math.h>
 #include <gdk/gdkkeysyms.h>
@@ -107,6 +107,7 @@ struct _GtkRangeLayout
 
   GtkSensitivityType lower_sensitivity;
   GtkSensitivityType upper_sensitivity;
+  guint repaint_id;
 
   gdouble fill_level;
 };
@@ -129,17 +130,17 @@ static void gtk_range_realize        (GtkWidget        *widget);
 static void gtk_range_unrealize      (GtkWidget        *widget);
 static void gtk_range_map            (GtkWidget        *widget);
 static void gtk_range_unmap          (GtkWidget        *widget);
-static gint gtk_range_expose         (GtkWidget        *widget,
+static gboolean gtk_range_expose         (GtkWidget        *widget,
                                       GdkEventExpose   *event);
-static gint gtk_range_button_press   (GtkWidget        *widget,
+static gboolean gtk_range_button_press   (GtkWidget        *widget,
                                       GdkEventButton   *event);
-static gint gtk_range_button_release (GtkWidget        *widget,
+static gboolean gtk_range_button_release (GtkWidget        *widget,
                                       GdkEventButton   *event);
-static gint gtk_range_motion_notify  (GtkWidget        *widget,
+static gboolean gtk_range_motion_notify  (GtkWidget        *widget,
                                       GdkEventMotion   *event);
-static gint gtk_range_enter_notify   (GtkWidget        *widget,
+static gboolean gtk_range_enter_notify   (GtkWidget        *widget,
                                       GdkEventCrossing *event);
-static gint gtk_range_leave_notify   (GtkWidget        *widget,
+static gboolean gtk_range_leave_notify   (GtkWidget        *widget,
                                       GdkEventCrossing *event);
 static gboolean gtk_range_grab_broken (GtkWidget          *widget,
                                       GdkEventGrabBroken *event);
@@ -147,7 +148,7 @@ static void gtk_range_grab_notify    (GtkWidget          *widget,
                                      gboolean            was_grabbed);
 static void gtk_range_state_changed  (GtkWidget          *widget,
                                      GtkStateType        previous_state);
-static gint gtk_range_scroll_event   (GtkWidget        *widget,
+static gboolean gtk_range_scroll_event   (GtkWidget        *widget,
                                       GdkEventScroll   *event);
 static void gtk_range_style_set      (GtkWidget        *widget,
                                       GtkStyle         *previous_style);
@@ -162,7 +163,7 @@ static void gtk_range_move_slider              (GtkRange         *range,
                                                 GtkScrollType     scroll);
 
 /* Internals */
-static void          gtk_range_scroll                   (GtkRange      *range,
+static gboolean      gtk_range_scroll                   (GtkRange      *range,
                                                          GtkScrollType  scroll);
 static gboolean      gtk_range_update_mouse_location    (GtkRange      *range);
 static void          gtk_range_calc_layout              (GtkRange      *range,
@@ -251,6 +252,12 @@ gtk_range_class_init (GtkRangeClass *class)
   class->slider_detail = "slider";
   class->stepper_detail = "stepper";
 
+  /**
+   * GtkRange::value-changed:
+   * @range: the #GtkRange
+   *
+   * Emitted when the range value changes.
+   */
   signals[VALUE_CHANGED] =
     g_signal_new (I_("value_changed"),
                   G_TYPE_FROM_CLASS (gobject_class),
@@ -270,6 +277,13 @@ gtk_range_class_init (GtkRangeClass *class)
                   G_TYPE_NONE, 1,
                   G_TYPE_DOUBLE);
   
+  /**
+   * GtkRange::move-slider:
+   * @range: the #GtkRange
+   * @step: how to move the slider
+   *
+   * Virtual function that moves the slider. Used for keybindings.
+   */
   signals[MOVE_SLIDER] =
     g_signal_new (I_("move_slider"),
                   G_TYPE_FROM_CLASS (gobject_class),
@@ -282,11 +296,11 @@ gtk_range_class_init (GtkRangeClass *class)
 
   /**
    * GtkRange::change-value:
-   * @range: the range that received the signal.
-   * @scroll: the type of scroll action that was performed.
-   * @value: the new value resulting from the scroll action.
+   * @range: the range that received the signal
+   * @scroll: the type of scroll action that was performed
+   * @value: the new value resulting from the scroll action
    * @returns: %TRUE to prevent other handlers from being invoked for the
-   * signal.  %FALSE to propagate the signal further.
+   * signal, %FALSE to propagate the signal further
    *
    * The ::change-value signal is emitted when a scroll action is
    * performed on a range.  It allows an application to determine the
@@ -316,7 +330,7 @@ gtk_range_class_init (GtkRangeClass *class)
                   G_TYPE_BOOLEAN, 2,
                   GTK_TYPE_SCROLL_TYPE,
                   G_TYPE_DOUBLE);
-  
+
   g_object_class_install_property (gobject_class,
                                    PROP_UPDATE_POLICY,
                                    g_param_spec_enum ("update-policy",
@@ -363,7 +377,7 @@ gtk_range_class_init (GtkRangeClass *class)
   /**
    * GtkRange:show-fill-level:
    *
-   * The show-fill-level property controls wether fill level indicator
+   * The show-fill-level property controls whether fill level indicator
    * graphics are displayed on the trough. See
    * gtk_range_set_show_fill_level().
    *
@@ -380,9 +394,9 @@ gtk_range_class_init (GtkRangeClass *class)
   /**
    * GtkRange:restrict-to-fill-level:
    *
-   * The restrict-to-fill-level proeprty controls whether slider
+   * The restrict-to-fill-level property controls whether slider
    * movement is restricted to an upper boundary set by the
-   * fill-level. See gtk_range_set_restrict_to_fill_level().
+   * fill level. See gtk_range_set_restrict_to_fill_level().
    *
    * Since: 2.12
    **/
@@ -441,7 +455,7 @@ gtk_range_class_init (GtkRangeClass *class)
    *
    * The spacing between the stepper buttons and thumb. Note that
    * setting this value to anything > 0 will automatically set the
-   * trough-under-steppers style property to TRUE as well. Also,
+   * trough-under-steppers style property to %TRUE as well. Also,
    * stepper-spacing won't have any effect if there are no steppers.
    */
   gtk_widget_class_install_style_property (widget_class,
@@ -479,6 +493,9 @@ gtk_range_class_init (GtkRangeClass *class)
   /**
    * GtkRange:trough-side-details:
    *
+   * When %TRUE, the parts of the trough on the two sides of the 
+   * slider are drawn with different details.
+   *
    * Since: 2.10
    */
   gtk_widget_class_install_style_property (widget_class,
@@ -493,7 +510,7 @@ gtk_range_class_init (GtkRangeClass *class)
    *
    * Whether to draw the trough across the full length of the range or
    * to exclude the steppers and their spacing. Note that setting the
-   * stepper-spacing style property to any value > 0 will
+   * #GtkRange:stepper-spacing style property to any value > 0 will
    * automatically enable trough-under-steppers too.
    *
    * Since: 2.10
@@ -501,7 +518,7 @@ gtk_range_class_init (GtkRangeClass *class)
   gtk_widget_class_install_style_property (widget_class,
                                            g_param_spec_boolean ("trough-under-steppers",
                                                                  P_("Trough Under Steppers"),
-                                                                 P_("Whether to draw trought for full length of range or exclude the steppers and spacing"),
+                                                                 P_("Whether to draw trough for full length of range or exclude the steppers and spacing"),
                                                                  TRUE,
                                                                  GTK_PARAM_READABLE));
 
@@ -659,7 +676,6 @@ gtk_range_get_adjustment (GtkRange *range)
  * continuous. #GTK_UPDATE_DISCONTINUOUS means that the value will only
  * be updated when the user releases the button and ends the slider
  * drag operation.
- * 
  **/
 void
 gtk_range_set_update_policy (GtkRange      *range,
@@ -702,7 +718,6 @@ gtk_range_get_update_policy (GtkRange *range)
  * is normally 0 for #GtkScale and nonzero for #GtkScrollbar, and
  * indicates the size of the visible area of the widget being scrolled.
  * The page size affects the size of the scrollbar slider.
- * 
  **/
 void
 gtk_range_set_adjustment (GtkRange      *range,
@@ -752,7 +767,6 @@ gtk_range_set_adjustment (GtkRange      *range,
  * slider moves from top to bottom or left to right. Inverted
  * ranges have higher values at the top or on the right rather than
  * on the bottom or left.
- * 
  **/
 void
 gtk_range_set_inverted (GtkRange *range,
@@ -890,7 +904,6 @@ gtk_range_get_upper_stepper_sensitivity (GtkRange *range)
  * The step size is used when the user clicks the #GtkScrollbar
  * arrows or moves #GtkScale via arrow keys. The page size
  * is used for example when moving via Page Up or Page Down keys.
- * 
  **/
 void
 gtk_range_set_increments (GtkRange *range,
@@ -948,9 +961,8 @@ gtk_range_set_range (GtkRange *range,
  *
  * Sets the current value of the range; if the value is outside the
  * minimum or maximum range values, it will be clamped to fit inside
- * them. The range emits the "value_changed" signal if the value
- * changes.
- * 
+ * them. The range emits the #GtkRange::value-changed signal if the 
+ * value changes.
  **/
 void
 gtk_range_set_value (GtkRange *range,
@@ -1015,7 +1027,9 @@ gtk_range_set_show_fill_level (GtkRange *range,
  * gtk_range_get_show_fill_level:
  * @range: A #GtkRange
  *
- * Return value: Whether GtkRange displays a fill level graphics.
+ * Gets whether the range displays the fill level graphically.
+ *
+ * Return value: %TRUE if @range shows the fill level.
  *
  * Since: 2.12
  **/
@@ -1059,7 +1073,9 @@ gtk_range_set_restrict_to_fill_level (GtkRange *range,
  * gtk_range_get_restrict_to_fill_level:
  * @range: A #GtkRange
  *
- * Return value: Whether GtkRange is restricted to the fill level.
+ * Gets whether the range is restricted to the fill level.
+ *
+ * Return value: %TRUE if @range is restricted to the fill level.
  *
  * Since: 2.12
  **/
@@ -1073,8 +1089,8 @@ gtk_range_get_restrict_to_fill_level (GtkRange *range)
 
 /**
  * gtk_range_set_fill_level:
- * @range:   A #GtkRange
- * @positon: The new position of the fill level indicator
+ * @range: a #GtkRange
+ * @fill_level: the new position of the fill level indicator
  *
  * Set the new position of the fill level indicator.
  *
@@ -1119,7 +1135,9 @@ gtk_range_set_fill_level (GtkRange *range,
  * gtk_range_get_fill_level:
  * @range : A #GtkRange
  *
- * Return value: The current position of the fill level indicator.
+ * Gets the current position of the fill level indicator.
+ *
+ * Return value: The current fill level
  *
  * Since: 2.12
  **/
@@ -1150,7 +1168,11 @@ gtk_range_destroy (GtkObject *object)
 
   gtk_range_remove_step_timer (range);
   gtk_range_remove_update_timer (range);
-  
+
+  if (range->layout->repaint_id)
+    g_source_remove (range->layout->repaint_id);
+  range->layout->repaint_id = 0;
+
   if (range->adjustment)
     {
       g_signal_handlers_disconnect_by_func (range->adjustment,
@@ -1381,11 +1403,11 @@ draw_stepper (GtkRange     *range,
                   arrow_x, arrow_y, arrow_width, arrow_height);
 }
 
-static gint
+static gboolean
 gtk_range_expose (GtkWidget      *widget,
                  GdkEventExpose *event)
 {
-  GtkRange *range;
+  GtkRange *range = GTK_RANGE (widget);
   gboolean sensitive;
   GtkStateType state;
   GtkShadowType shadow_type;
@@ -1398,17 +1420,17 @@ gtk_range_expose (GtkWidget      *widget,
   g_object_get (gtk_widget_get_settings (widget),
                 "gtk-touchscreen-mode", &touchscreen,
                 NULL);
+  if (GTK_WIDGET_CAN_FOCUS (range))
+    gtk_widget_style_get (GTK_WIDGET (range),
+                          "focus-line-width", &focus_line_width,
+                          "focus-padding", &focus_padding,
+                          NULL);
 
-  range = GTK_RANGE (widget);
+  /* we're now exposing, so there's no need to force early repaints */
+  if (range->layout->repaint_id)
+    g_source_remove (range->layout->repaint_id);
+  range->layout->repaint_id = 0;
 
-  if (GTK_WIDGET_CAN_FOCUS (range))
-    {
-      gtk_widget_style_get (GTK_WIDGET (range),
-                           "focus-line-width", &focus_line_width,
-                           "focus-padding", &focus_padding,
-                           NULL);
-    }
-  
   expose_area = event->area;
   expose_area.x -= widget->allocation.x;
   expose_area.y -= widget->allocation.y;
@@ -1705,12 +1727,16 @@ range_grab_add (GtkRange      *range,
 static void
 range_grab_remove (GtkRange *range)
 {
+  MouseLocation location;
+
   gtk_grab_remove (GTK_WIDGET (range));
-  
+  location = range->layout->grab_location; 
   range->layout->grab_location = MOUSE_OUTSIDE;
   range->layout->grab_button = 0;
 
-  if (gtk_range_update_mouse_location (range))
+  if (gtk_range_update_mouse_location (range) ||
+      location != MOUSE_OUTSIDE)
     gtk_widget_queue_draw (GTK_WIDGET (range));
 }
 
@@ -2011,11 +2037,6 @@ stop_scrolling (GtkRange *range)
   gtk_range_remove_step_timer (range);
   /* Flush any pending discontinuous/delayed updates */
   gtk_range_update_value (range);
-  
-  /* Just be lazy about this, if we scrolled it will all redraw anyway,
-   * so no point optimizing the button deactivate case
-   */
-  gtk_widget_queue_draw (GTK_WIDGET (range));
 }
 
 static gboolean
@@ -2102,7 +2123,7 @@ _gtk_range_get_wheel_delta (GtkRange           *range,
   return delta;
 }
       
-static gint
+static gboolean
 gtk_range_scroll_event (GtkWidget      *widget,
                        GdkEventScroll *event)
 {
@@ -2131,7 +2152,7 @@ gtk_range_scroll_event (GtkWidget      *widget,
   return TRUE;
 }
 
-static gint
+static gboolean
 gtk_range_motion_notify (GtkWidget      *widget,
                         GdkEventMotion *event)
 {
@@ -2155,7 +2176,7 @@ gtk_range_motion_notify (GtkWidget      *widget,
   return range->layout->mouse_location != MOUSE_OUTSIDE;
 }
 
-static gint
+static gboolean
 gtk_range_enter_notify (GtkWidget        *widget,
                        GdkEventCrossing *event)
 {
@@ -2170,7 +2191,7 @@ gtk_range_enter_notify (GtkWidget        *widget,
   return TRUE;
 }
 
-static gint
+static gboolean
 gtk_range_leave_notify (GtkWidget        *widget,
                        GdkEventCrossing *event)
 {
@@ -2250,6 +2271,16 @@ gtk_range_adjustment_changed (GtkAdjustment *adjustment,
    */
 }
 
+static gboolean
+force_repaint (gpointer data)
+{
+  GtkRange *range = GTK_RANGE (data);
+  range->layout->repaint_id = 0;
+  if (GTK_WIDGET_DRAWABLE (range))
+    gdk_window_process_updates (GTK_WIDGET (range)->window, FALSE);
+  return FALSE;
+}
+
 static void
 gtk_range_adjustment_value_changed (GtkAdjustment *adjustment,
                                    gpointer       data)
@@ -2265,10 +2296,9 @@ gtk_range_adjustment_value_changed (GtkAdjustment *adjustment,
   if (layout_changed (range->layout, &layout))
     {
       gtk_widget_queue_draw (GTK_WIDGET (range));
-      
-      /* This is so we don't lag the widget being scrolled. */
-      if (GTK_WIDGET_REALIZED (range))
-        gdk_window_process_updates (GTK_WIDGET (range)->window, FALSE);
+      /* setup a timer to ensure the range isn't lagging too much behind the scroll position */
+      if (!range->layout->repaint_id)
+        range->layout->repaint_id = gdk_threads_add_timeout_full (GDK_PRIORITY_EVENTS, 181, force_repaint, range, NULL);
     }
   
   /* Note that we don't round off to range->round_digits here.
@@ -2358,10 +2388,12 @@ scroll_end (GtkRange *range)
                  &handled);
 }
 
-static void
+static gboolean
 gtk_range_scroll (GtkRange     *range,
                   GtkScrollType scroll)
 {
+  gdouble old_value = range->adjustment->value;
+
   switch (scroll)
     {
     case GTK_SCROLL_STEP_LEFT:
@@ -2451,6 +2483,8 @@ gtk_range_scroll (GtkRange     *range,
     case GTK_SCROLL_NONE:
       break;
     }
+
+  return range->adjustment->value != old_value;
 }
 
 static void
@@ -2493,7 +2527,8 @@ gtk_range_move_slider (GtkRange     *range,
         }
     }
 
-  gtk_range_scroll (range, scroll);
+  if (! gtk_range_scroll (range, scroll))
+    gtk_widget_error_bell (GTK_WIDGET (range));
 
   /* Policy DELAYED makes sense with key events,
    * but DISCONTINUOUS doesn't, so we update immediately