]> Pileus Git - ~andy/gtk/blobdiff - gtk/gtkrange.c
stylecontext: Do invalidation on first resize container
[~andy/gtk] / gtk / gtkrange.c
index d9acee88ec29e161b272e5c8dfa6d6e873f98aaf..8339e52b70c195a829185fd0ddad7217012e3d79 100644 (file)
@@ -116,8 +116,6 @@ struct _GtkRangePrivate
   gint  slider_start;                /* Slider range along the long dimension, in widget->window coords */
   gint  slider_end;
 
-  guint repaint_id;
-
   /* Steppers are: < > ---- < >
    *               a b      c d
    */
@@ -140,6 +138,9 @@ struct _GtkRangePrivate
   /* The range has an origin, should be drawn differently. Used by GtkScale */
   guint has_origin             : 1;
 
+  /* Whether we're doing fine adjustment */
+  guint zoom                   : 1;
+
   /* Fill level */
   guint show_fill_level        : 1;
   guint restrict_to_fill_level : 1;
@@ -1499,10 +1500,6 @@ gtk_range_destroy (GtkWidget *widget)
 
   gtk_range_remove_step_timer (range);
 
-  if (priv->repaint_id)
-    g_source_remove (priv->repaint_id);
-  priv->repaint_id = 0;
-
   if (priv->adjustment)
     {
       g_signal_handlers_disconnect_by_func (priv->adjustment,
@@ -1741,7 +1738,7 @@ gtk_range_realize (GtkWidget *widget)
 
   priv->event_window = gdk_window_new (gtk_widget_get_parent_window (widget),
                                        &attributes, attributes_mask);
-  gdk_window_set_user_data (priv->event_window, range);
+  gtk_widget_register_window (widget, priv->event_window);
 }
 
 static void
@@ -1752,7 +1749,7 @@ gtk_range_unrealize (GtkWidget *widget)
 
   gtk_range_remove_step_timer (range);
 
-  gdk_window_set_user_data (priv->event_window, NULL);
+  gtk_widget_unregister_window (widget, priv->event_window);
   gdk_window_destroy (priv->event_window);
   priv->event_window = NULL;
 
@@ -2013,6 +2010,7 @@ gtk_range_draw (GtkWidget *widget,
   gboolean draw_trough = TRUE;
   gboolean draw_slider = TRUE;
   GtkStyleContext *context;
+  GtkBorder margin;
 
   context = gtk_widget_get_style_context (widget);
 
@@ -2034,11 +2032,6 @@ gtk_range_draw (GtkWidget *widget,
                           "focus-padding", &focus_padding,
                           NULL);
 
-  /* we're now exposing, so there's no need to force early repaints */
-  if (priv->repaint_id)
-    g_source_remove (priv->repaint_id);
-  priv->repaint_id = 0;
-
   gtk_range_calc_marks (range);
   gtk_range_calc_layout (range, gtk_adjustment_get_value (priv->adjustment));
 
@@ -2115,10 +2108,16 @@ gtk_range_draw (GtkWidget *widget,
 
       gtk_style_context_save (context);
       gtk_style_context_add_class (context, GTK_STYLE_CLASS_TROUGH);
+      gtk_style_context_get_margin (context, widget_state, &margin);
+
+      x += margin.left;
+      y += margin.top;
+      width -= margin.left + margin.right;
+      height -= margin.top + margin.bottom;
 
       if (draw_trough)
         {
-          if (!priv->has_origin)
+          if (!priv->has_origin || !draw_slider)
             {
               gtk_render_background (context, cr,
                                      x, y, width, height);
@@ -2244,13 +2243,6 @@ gtk_range_draw (GtkWidget *widget,
                 fill_y += priv->trough.height - fill_height;
             }
 
-#if 0
-          if (fill_level < gtk_adjustment_get_upper (priv->adjustment) - gtk_adjustment_get_page_size (priv->adjustment))
-            fill_detail = "trough-fill-level-full";
-          else
-            fill_detail = "trough-fill-level";
-#endif
-
           gtk_render_activity (context, cr,
                                fill_x, fill_y,
                                fill_width, fill_height);
@@ -2365,9 +2357,10 @@ range_grab_remove (GtkRange *range)
 
   if (priv->grab_device)
     {
-      gtk_device_grab_remove (GTK_WIDGET (range),
-                              priv->grab_device);
+      GdkDevice *grab_device = priv->grab_device;
+
       priv->grab_device = NULL;
+      gtk_device_grab_remove (GTK_WIDGET (range), grab_device);
     }
 
   location = priv->grab_location;
@@ -2377,6 +2370,8 @@ range_grab_remove (GtkRange *range)
   if (gtk_range_update_mouse_location (range) ||
       location != MOUSE_OUTSIDE)
     gtk_widget_queue_draw (GTK_WIDGET (range));
+
+  priv->zoom = FALSE;
 }
 
 static GtkScrollType
@@ -2443,7 +2438,7 @@ range_get_scroll_for_grab (GtkRange      *range)
 
 static gdouble
 coord_to_value (GtkRange *range,
-                gint      coord)
+                gdouble   coord)
 {
   GtkRangePrivate *priv = range->priv;
   gdouble frac;
@@ -2527,6 +2522,8 @@ gtk_range_button_press (GtkWidget      *widget,
   GtkRangePrivate *priv = range->priv;
   GdkDevice *device, *source_device;
   GdkInputSource source;
+  gboolean primary_warps;
+  gint page_increment_button, warp_button;
 
   if (!gtk_widget_has_focus (widget))
     gtk_widget_grab_focus (widget);
@@ -2545,6 +2542,20 @@ gtk_range_button_press (GtkWidget      *widget,
   if (gtk_range_update_mouse_location (range))
     gtk_widget_queue_draw (widget);
 
+  g_object_get (gtk_widget_get_settings (widget),
+                "gtk-primary-button-warps-slider", &primary_warps,
+                NULL);
+  if (primary_warps)
+    {
+      warp_button = GDK_BUTTON_PRIMARY;
+      page_increment_button = GDK_BUTTON_SECONDARY;
+    }
+  else
+    {
+      warp_button = GDK_BUTTON_MIDDLE;
+      page_increment_button = GDK_BUTTON_PRIMARY;
+    }
+
   if (priv->mouse_location == MOUSE_SLIDER &&
       gdk_event_triggers_context_menu ((GdkEvent *)event))
     {
@@ -2557,9 +2568,9 @@ gtk_range_button_press (GtkWidget      *widget,
 
   if (source != GDK_SOURCE_TOUCHSCREEN &&
       priv->mouse_location == MOUSE_TROUGH &&
-      event->button == GDK_BUTTON_PRIMARY)
+      event->button == page_increment_button)
     {
-      /* button 1 steps by page increment, as with button 2 on a stepper
+      /* button 2 steps by page increment, as with button 2 on a stepper
        */
       GtkScrollType scroll;
       gdouble click_value;
@@ -2607,17 +2618,17 @@ gtk_range_button_press (GtkWidget      *widget,
       return TRUE;
     }
   else if ((priv->mouse_location == MOUSE_TROUGH &&
-            (source == GDK_SOURCE_TOUCHSCREEN || event->button == GDK_BUTTON_MIDDLE)) ||
+            (source == GDK_SOURCE_TOUCHSCREEN ||
+             event->button == warp_button)) ||
            priv->mouse_location == MOUSE_SLIDER)
     {
       gboolean need_value_update = FALSE;
 
       /* Any button can be used to drag the slider, but you can start
-       * dragging the slider with a trough click using button 2;
-       * On button 2 press and touch devices, we warp the slider to
-       * mouse position, then begin the slider drag.
+       * dragging the slider with a trough click using button 1;
+       * we warp the slider to mouse position, then begin the slider drag.
        */
-      if (event->button == GDK_BUTTON_MIDDLE || source == GDK_SOURCE_TOUCHSCREEN)
+      if (priv->mouse_location != MOUSE_SLIDER)
         {
           gdouble slider_low_value, slider_high_value, new_value;
           
@@ -2645,6 +2656,12 @@ gtk_range_button_press (GtkWidget      *widget,
           */
          need_value_update = TRUE;
         }
+      else
+        {
+          /* Shift-click in the slider = fine adjustment */
+          if (event->state & GDK_SHIFT_MASK)
+            priv->zoom = TRUE;
+        }
 
       if (priv->orientation == GTK_ORIENTATION_VERTICAL)
         {
@@ -2677,13 +2694,14 @@ update_slider_position (GtkRange *range,
                         gint      mouse_y)
 {
   GtkRangePrivate *priv = range->priv;
-  gint delta;
-  gint c;
+  gdouble delta;
+  gdouble c;
   gdouble new_value;
   gboolean handled;
   gdouble next_value;
   gdouble mark_value;
   gdouble mark_delta;
+  gdouble zoom;
   gint i;
 
   if (priv->orientation == GTK_ORIENTATION_VERTICAL)
@@ -2691,11 +2709,25 @@ update_slider_position (GtkRange *range,
   else
     delta = mouse_x - priv->slide_initial_coordinate;
 
-  c = priv->slide_initial_slider_position + delta;
+  if (priv->zoom)
+    {
+      zoom = MIN(1.0, (priv->orientation == GTK_ORIENTATION_VERTICAL ?
+                       priv->trough.height : priv->trough.width) /
+                       (gtk_adjustment_get_upper (priv->adjustment) -
+                        gtk_adjustment_get_lower (priv->adjustment) -
+                        gtk_adjustment_get_page_size (priv->adjustment)));
+      /* the above is ineffective for scales, so just set a zoom factor */
+      if (zoom == 1.0)
+        zoom = 0.25;
+    }
+  else
+    zoom = 1.0;
+
+  c = priv->slide_initial_slider_position + zoom * delta;
 
   new_value = coord_to_value (range, c);
   next_value = coord_to_value (range, c + 1);
-  mark_delta = fabs (next_value - new_value); 
+  mark_delta = fabs (next_value - new_value);
 
   for (i = 0; i < priv->n_marks; i++)
     {
@@ -2709,13 +2741,13 @@ update_slider_position (GtkRange *range,
               break;
             }
         }
-    }  
+    }
 
   g_signal_emit (range, signals[CHANGE_VALUE], 0, GTK_SCROLL_JUMP, new_value,
                  &handled);
 }
 
-static void 
+static void
 stop_scrolling (GtkRange *range)
 {
   range_grab_remove (range);
@@ -2736,7 +2768,7 @@ gtk_range_grab_broken (GtkWidget          *widget,
       priv->grab_location != MOUSE_OUTSIDE)
     {
       if (priv->grab_location == MOUSE_SLIDER)
-       update_slider_position (range, priv->mouse_x, priv->mouse_y);
+        update_slider_position (range, priv->mouse_x, priv->mouse_y);
 
       stop_scrolling (range);
       
@@ -2788,11 +2820,11 @@ gtk_range_button_release (GtkWidget      *widget,
  * _gtk_range_get_wheel_delta:
  * @range: a #GtkRange
  * @event: A #GdkEventScroll
- * 
+ *
  * Returns a good step value for the mouse wheel.
- * 
- * Return value: A good step value for the mouse wheel. 
- * 
+ *
+ * Return value: A good step value for the mouse wheel.
+ *
  * Since: 2.4
  **/
 gdouble
@@ -2804,49 +2836,32 @@ _gtk_range_get_wheel_delta (GtkRange       *range,
   gdouble dx, dy;
   gdouble delta;
   gdouble page_size;
-  gdouble size;
+  gdouble page_increment;
+  gdouble scroll_unit;
 
   page_size = gtk_adjustment_get_page_size (adjustment);
+  page_increment = gtk_adjustment_get_page_increment (adjustment);
+
+  if (GTK_IS_SCROLLBAR (range))
+    scroll_unit = pow (page_size, 2.0 / 3.0);
+  else
+    scroll_unit = page_increment;
 
   if (gdk_event_get_scroll_deltas ((GdkEvent *) event, &dx, &dy))
     {
-      GtkAllocation allocation;
-
-      gtk_widget_get_allocation (GTK_WIDGET (range), &allocation);
-
-      if (gtk_orientable_get_orientation (GTK_ORIENTABLE (range)) == GTK_ORIENTATION_HORIZONTAL)
-        size = allocation.width;
-      else
-        size = allocation.height;
-
       if (dx != 0 &&
           gtk_orientable_get_orientation (GTK_ORIENTABLE (range)) == GTK_ORIENTATION_HORIZONTAL)
-        {
-          if (GTK_IS_SCROLLBAR (range) && page_size > 0)
-            delta = dx * page_size / size;
-          else
-            delta = dx * (gtk_adjustment_get_upper (adjustment) -
-                          gtk_adjustment_get_lower (adjustment)) / size;
-        }
+        delta = dx * scroll_unit;
       else
-        {
-          if (GTK_IS_SCROLLBAR (range) && page_size > 0)
-            delta = dy * page_size / size;
-          else
-            delta = dy * (gtk_adjustment_get_upper (adjustment) -
-                          gtk_adjustment_get_lower (adjustment)) / size;
-        }
+        delta = dy * scroll_unit;
     }
   else
     {
-      if (GTK_IS_SCROLLBAR (range))
-        delta = pow (page_size, 2.0 / 3.0);
-      else
-        delta = gtk_adjustment_get_page_increment (adjustment) * 2;
-
       if (event->direction == GDK_SCROLL_UP ||
           event->direction == GDK_SCROLL_LEFT)
-        delta = - delta;
+        delta = - scroll_unit;
+      else
+        delta = scroll_unit;
     }
 
   if (priv->inverted)
@@ -3000,20 +3015,6 @@ gtk_range_adjustment_changed (GtkAdjustment *adjustment,
    */
 }
 
-static gboolean
-force_repaint (gpointer data)
-{
-  GtkRange *range = GTK_RANGE (data);
-  GtkRangePrivate *priv = range->priv;
-  GtkWidget *widget = GTK_WIDGET (range);
-
-  priv->repaint_id = 0;
-  if (gtk_widget_is_drawable (widget))
-    gdk_window_process_updates (gtk_widget_get_window (widget), FALSE);
-
-  return FALSE;
-}
-
 static void
 gtk_range_adjustment_value_changed (GtkAdjustment *adjustment,
                                    gpointer       data)
@@ -3030,11 +3031,6 @@ gtk_range_adjustment_value_changed (GtkAdjustment *adjustment,
       (GTK_IS_SCALE (range) && gtk_scale_get_draw_value (GTK_SCALE (range))))
     {
       gtk_widget_queue_draw (GTK_WIDGET (range));
-      /* setup a timer to ensure the range isn't lagging too much behind the scroll position */
-      if (!priv->repaint_id)
-        priv->repaint_id = gdk_threads_add_timeout_full (GDK_PRIORITY_EVENTS,
-                                                         181, force_repaint,
-                                                         range, NULL);
     }
 
   /* Note that we don't round off to priv->round_digits here.
@@ -3603,13 +3599,15 @@ gtk_range_calc_layout (GtkRange *range,
   GtkRangePrivate *priv = range->priv;
   gint slider_width, stepper_size, focus_width, trough_border, stepper_spacing;
   gint slider_length;
-  GtkBorder border;
+  GtkBorder border, trough_margin;
   gint n_steppers;
   gboolean has_steppers_ab;
   gboolean has_steppers_cd;
   gboolean trough_under_steppers;
   GdkRectangle range_rect;
   GtkWidget *widget;
+  GtkStyleContext *context;
+  GtkStateFlags state;
 
   if (!priv->need_recalc)
     return;
@@ -3625,6 +3623,13 @@ gtk_range_calc_layout (GtkRange *range,
    */
 
   widget = GTK_WIDGET (range);
+  context = gtk_widget_get_style_context (widget);
+
+  state = gtk_widget_get_state_flags (widget);
+  gtk_style_context_save (context);
+  gtk_style_context_add_class (context, GTK_STYLE_CLASS_TROUGH);
+  gtk_style_context_get_margin (context, state, &trough_margin);
+  gtk_style_context_restore (context);
 
   gtk_range_get_props (range,
                        &slider_width, &stepper_size,
@@ -3893,7 +3898,6 @@ gtk_range_calc_layout (GtkRange *range,
        */
       priv->trough.x = priv->stepper_b.x + priv->stepper_b.width + stepper_spacing * has_steppers_ab;
       priv->trough.y = range_rect.y;
-
       priv->trough.width = priv->stepper_c.x - priv->trough.x - stepper_spacing * has_steppers_cd;
       priv->trough.height = range_rect.height;