]> Pileus Git - ~andy/gtk/blob - gtk/gtkrange.c
Patch from ChiDeok Hwang to move call to sync_selection() up a few lines
[~andy/gtk] / gtk / gtkrange.c
1 /* GTK - The GIMP Toolkit
2  * Copyright (C) 1995-1997 Peter Mattis, Spencer Kimball and Josh MacDonald
3  *
4  * This library is free software; you can redistribute it and/or
5  * modify it under the terms of the GNU Lesser General Public
6  * License as published by the Free Software Foundation; either
7  * version 2 of the License, or (at your option) any later version.
8  *
9  * This library is distributed in the hope that it will be useful,
10  * but WITHOUT ANY WARRANTY; without even the implied warranty of
11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
12  * Lesser General Public License for more details.
13  *
14  * You should have received a copy of the GNU Lesser General Public
15  * License along with this library; if not, write to the
16  * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
17  * Boston, MA 02111-1307, USA.
18  */
19
20 /*
21  * Modified by the GTK+ Team and others 1997-2000.  See the AUTHORS
22  * file for a list of people on the GTK+ Team.  See the ChangeLog
23  * files for a list of changes.  These files are distributed with
24  * GTK+ at ftp://ftp.gtk.org/pub/gtk/. 
25  */
26
27 #include <stdio.h>
28 #include "gtkmain.h"
29 #include "gtkrange.h"
30 #include "gtksignal.h"
31
32 #define SCROLL_TIMER_LENGTH  20
33 #define SCROLL_INITIAL_DELAY 250  /* must hold button this long before ... */
34 #define SCROLL_LATER_DELAY   100  /* ... it starts repeating at this rate  */
35 #define SCROLL_DELAY_LENGTH  300
36
37 #define RANGE_CLASS(w)  GTK_RANGE_GET_CLASS (w)
38
39 enum {
40   ARG_0,
41   ARG_UPDATE_POLICY
42 };
43
44 static void gtk_range_class_init               (GtkRangeClass    *klass);
45 static void gtk_range_init                     (GtkRange         *range);
46 static void gtk_range_set_arg                  (GtkObject        *object,
47                                                 GtkArg           *arg,
48                                                 guint             arg_id);
49 static void gtk_range_get_arg                  (GtkObject        *object,
50                                                 GtkArg           *arg,
51                                                 guint             arg_id);
52 static void gtk_range_destroy                  (GtkObject        *object);
53 static void gtk_range_unrealize                (GtkWidget        *widget);
54 static gint gtk_range_expose                   (GtkWidget        *widget,
55                                                 GdkEventExpose   *event);
56 static gint gtk_range_button_press             (GtkWidget        *widget,
57                                                 GdkEventButton   *event);
58 static gint gtk_range_button_release           (GtkWidget        *widget,
59                                                 GdkEventButton   *event);
60 static gint gtk_range_motion_notify            (GtkWidget        *widget,
61                                                 GdkEventMotion   *event);
62 static gint gtk_range_key_press                (GtkWidget         *widget,
63                                                 GdkEventKey       *event);
64 static gint gtk_range_enter_notify             (GtkWidget        *widget,
65                                                 GdkEventCrossing *event);
66 static gint gtk_range_leave_notify             (GtkWidget        *widget,
67                                                 GdkEventCrossing *event);
68 static gint gtk_range_scroll_event             (GtkWidget        *widget,
69                                                 GdkEventScroll   *event);
70 static void gtk_range_style_set                 (GtkWidget       *widget,
71                                                  GtkStyle        *previous_style);
72
73 static void gtk_real_range_draw_trough         (GtkRange         *range);
74 static void gtk_real_range_draw_slider         (GtkRange         *range);
75 static gint gtk_real_range_timer               (GtkRange         *range);
76 static gint gtk_range_scroll                   (GtkRange         *range,
77                                                 gfloat            jump_perc);
78
79 static void gtk_range_add_timer                (GtkRange         *range);
80 static void gtk_range_remove_timer             (GtkRange         *range);
81
82 static void gtk_range_adjustment_changed       (GtkAdjustment    *adjustment,
83                                                 gpointer          data);
84 static void gtk_range_adjustment_value_changed (GtkAdjustment    *adjustment,
85                                                 gpointer          data);
86
87 static void gtk_range_trough_hdims             (GtkRange         *range,
88                                                 gint             *left,
89                                                 gint             *right);
90 static void gtk_range_trough_vdims             (GtkRange         *range,
91                                                 gint             *top,
92                                                 gint             *bottom);
93
94 static GtkWidgetClass *parent_class = NULL;
95
96
97 GtkType
98 gtk_range_get_type (void)
99 {
100   static GtkType range_type = 0;
101
102   if (!range_type)
103     {
104       static const GtkTypeInfo range_info =
105       {
106         "GtkRange",
107         sizeof (GtkRange),
108         sizeof (GtkRangeClass),
109         (GtkClassInitFunc) gtk_range_class_init,
110         (GtkObjectInitFunc) gtk_range_init,
111         /* reserved_1 */ NULL,
112         /* reserved_2 */ NULL,
113         (GtkClassInitFunc) NULL,
114       };
115
116       range_type = gtk_type_unique (GTK_TYPE_WIDGET, &range_info);
117     }
118
119   return range_type;
120 }
121
122 static void
123 gtk_range_class_init (GtkRangeClass *class)
124 {
125   GtkObjectClass *object_class;
126   GtkWidgetClass *widget_class;
127
128   object_class = (GtkObjectClass*) class;
129   widget_class = (GtkWidgetClass*) class;
130
131   parent_class = gtk_type_class (GTK_TYPE_WIDGET);
132
133   object_class->set_arg = gtk_range_set_arg;
134   object_class->get_arg = gtk_range_get_arg;
135   object_class->destroy = gtk_range_destroy;
136
137   widget_class->unrealize = gtk_range_unrealize;
138   widget_class->expose_event = gtk_range_expose;
139   widget_class->button_press_event = gtk_range_button_press;
140   widget_class->button_release_event = gtk_range_button_release;
141   widget_class->motion_notify_event = gtk_range_motion_notify;
142   widget_class->scroll_event = gtk_range_scroll_event;
143   widget_class->key_press_event = gtk_range_key_press;
144   widget_class->enter_notify_event = gtk_range_enter_notify;
145   widget_class->leave_notify_event = gtk_range_leave_notify;
146   widget_class->style_set = gtk_range_style_set;
147
148   class->slider_width = 11;
149   class->stepper_size = 11;
150   class->stepper_slider_spacing = 1;
151   class->min_slider_size = 7;
152   class->trough = 1;
153   class->slider = 2;
154   class->step_forw = 3;
155   class->step_back = 4;
156   class->draw_background = NULL;
157   class->clear_background = NULL;
158   class->draw_trough = gtk_real_range_draw_trough;
159   class->draw_slider = gtk_real_range_draw_slider;
160   class->draw_step_forw = NULL;
161   class->draw_step_back = NULL;
162   class->trough_click = NULL;
163   class->trough_keys = NULL;
164   class->motion = NULL;
165   class->timer = gtk_real_range_timer;
166
167   gtk_object_add_arg_type ("GtkRange::update_policy",
168                            GTK_TYPE_UPDATE_TYPE,
169                            GTK_ARG_READWRITE,
170                            ARG_UPDATE_POLICY);
171 }
172
173 static void
174 gtk_range_set_arg (GtkObject      *object,
175                    GtkArg         *arg,
176                    guint           arg_id)
177 {
178   GtkRange *range;
179
180   range = GTK_RANGE (object);
181
182   switch (arg_id)
183     {
184     case ARG_UPDATE_POLICY:
185       gtk_range_set_update_policy (range, GTK_VALUE_ENUM (*arg));
186       break;
187     default:
188       break;
189     }
190 }
191
192 static void
193 gtk_range_get_arg (GtkObject      *object,
194                    GtkArg         *arg,
195                    guint           arg_id)
196 {
197   GtkRange *range;
198
199   range = GTK_RANGE (object);
200
201   switch (arg_id)
202     {
203     case ARG_UPDATE_POLICY:
204       GTK_VALUE_ENUM (*arg) = range->policy;
205       break;
206     default:
207       arg->type = GTK_TYPE_INVALID;
208       break;
209     }
210 }
211
212 static void
213 gtk_range_init (GtkRange *range)
214 {
215   range->trough = NULL;
216   range->slider = NULL;
217   range->step_forw = NULL;
218   range->step_back = NULL;
219
220   range->x_click_point = 0;
221   range->y_click_point = 0;
222   range->button = 0;
223   range->digits = -1;
224   range->policy = GTK_UPDATE_CONTINUOUS;
225   range->scroll_type = GTK_SCROLL_NONE;
226   range->in_child = 0;
227   range->click_child = 0;
228   range->need_timer = FALSE;
229   range->timer = 0;
230   range->flippable = 0;
231   range->old_value = 0.0;
232   range->old_lower = 0.0;
233   range->old_upper = 0.0;
234   range->old_page_size = 0.0;
235   range->adjustment = NULL;
236 }
237
238 GtkAdjustment*
239 gtk_range_get_adjustment (GtkRange *range)
240 {
241   g_return_val_if_fail (range != NULL, NULL);
242   g_return_val_if_fail (GTK_IS_RANGE (range), NULL);
243
244   if (!range->adjustment)
245     gtk_range_set_adjustment (range, NULL);
246
247   return range->adjustment;
248 }
249
250 void
251 gtk_range_set_update_policy (GtkRange      *range,
252                              GtkUpdateType  policy)
253 {
254   g_return_if_fail (range != NULL);
255   g_return_if_fail (GTK_IS_RANGE (range));
256
257   range->policy = policy;
258 }
259
260 void
261 gtk_range_set_adjustment (GtkRange      *range,
262                           GtkAdjustment *adjustment)
263 {
264   g_return_if_fail (range != NULL);
265   g_return_if_fail (GTK_IS_RANGE (range));
266   
267   if (!adjustment)
268     adjustment = (GtkAdjustment*) gtk_adjustment_new (0.0, 0.0, 0.0, 0.0, 0.0, 0.0);
269   else
270     g_return_if_fail (GTK_IS_ADJUSTMENT (adjustment));
271
272   if (range->adjustment != adjustment)
273     {
274       if (range->adjustment)
275         {
276           gtk_signal_disconnect_by_data (GTK_OBJECT (range->adjustment),
277                                          (gpointer) range);
278           gtk_object_unref (GTK_OBJECT (range->adjustment));
279         }
280
281       range->adjustment = adjustment;
282       gtk_object_ref (GTK_OBJECT (adjustment));
283       gtk_object_sink (GTK_OBJECT (adjustment));
284       
285       gtk_signal_connect (GTK_OBJECT (adjustment), "changed",
286                           (GtkSignalFunc) gtk_range_adjustment_changed,
287                           (gpointer) range);
288       gtk_signal_connect (GTK_OBJECT (adjustment), "value_changed",
289                           (GtkSignalFunc) gtk_range_adjustment_value_changed,
290                           (gpointer) range);
291       
292       range->old_value = adjustment->value;
293       range->old_lower = adjustment->lower;
294       range->old_upper = adjustment->upper;
295       range->old_page_size = adjustment->page_size;
296       
297       gtk_range_adjustment_changed (adjustment, (gpointer) range);
298     }
299 }
300
301 void
302 gtk_range_set_inverted (GtkRange *range,
303                         gboolean  setting)
304 {
305   g_return_if_fail (GTK_IS_RANGE (range));
306   
307   setting = setting != FALSE;
308
309   if (setting != range->inverted)
310     {
311       range->inverted = setting;
312       gtk_widget_queue_resize (GTK_WIDGET (range));
313     }
314 }
315
316 gboolean
317 gtk_range_get_inverted (GtkRange *range)
318 {
319   g_return_val_if_fail (GTK_IS_RANGE (range), FALSE);
320
321   return range->inverted;
322 }
323
324 void
325 _gtk_range_draw_background (GtkRange *range)
326 {
327   g_return_if_fail (range != NULL);
328   g_return_if_fail (GTK_IS_RANGE (range));
329
330   if (range->trough && RANGE_CLASS (range)->draw_background)
331     (* RANGE_CLASS (range)->draw_background) (range);
332 }
333
334 void
335 _gtk_range_clear_background (GtkRange *range)
336 {
337   g_return_if_fail (range != NULL);
338   g_return_if_fail (GTK_IS_RANGE (range));
339
340   if (range->trough && RANGE_CLASS (range)->clear_background)
341     (* RANGE_CLASS (range)->clear_background) (range);
342 }
343
344 void
345 _gtk_range_draw_trough (GtkRange *range)
346 {
347   g_return_if_fail (range != NULL);
348   g_return_if_fail (GTK_IS_RANGE (range));
349
350   if (range->trough && RANGE_CLASS (range)->draw_trough)
351     (* RANGE_CLASS (range)->draw_trough) (range);
352 }
353
354 void
355 _gtk_range_draw_slider (GtkRange *range)
356 {
357   g_return_if_fail (range != NULL);
358   g_return_if_fail (GTK_IS_RANGE (range));
359
360   if (range->slider && RANGE_CLASS (range)->draw_slider)
361     (* RANGE_CLASS (range)->draw_slider) (range);
362 }
363
364 void
365 _gtk_range_draw_step_forw (GtkRange *range)
366 {
367   g_return_if_fail (range != NULL);
368   g_return_if_fail (GTK_IS_RANGE (range));
369
370   if (range->step_forw && RANGE_CLASS (range)->draw_step_forw)
371     (* RANGE_CLASS (range)->draw_step_forw) (range);
372 }
373
374 void
375 _gtk_range_draw_step_back (GtkRange *range)
376 {
377   g_return_if_fail (range != NULL);
378   g_return_if_fail (GTK_IS_RANGE (range));
379
380   if (range->step_back && RANGE_CLASS (range)->draw_step_back)
381     (* RANGE_CLASS (range)->draw_step_back) (range);
382 }
383
384 void
385 _gtk_range_slider_update (GtkRange *range)
386 {
387   g_return_if_fail (range != NULL);
388   g_return_if_fail (GTK_IS_RANGE (range));
389
390   if (RANGE_CLASS (range)->slider_update)
391     (* RANGE_CLASS (range)->slider_update) (range);
392 }
393
394 gint
395 _gtk_range_trough_click (GtkRange *range,
396                          gint      x,
397                          gint      y,
398                          gfloat   *jump_perc)
399 {
400   g_return_val_if_fail (range != NULL, GTK_TROUGH_NONE);
401   g_return_val_if_fail (GTK_IS_RANGE (range), GTK_TROUGH_NONE);
402
403   if (RANGE_CLASS (range)->trough_click)
404     return (* RANGE_CLASS (range)->trough_click) (range, x, y, jump_perc);
405
406   return GTK_TROUGH_NONE;
407 }
408
409 static GdkRegion *
410 get_window_region (GdkWindow *window)
411 {
412   GdkRectangle rect;
413
414   gdk_window_get_position (window, &rect.x, &rect.y);
415   gdk_window_get_size (window, &rect.width, &rect.height);
416
417   return gdk_region_rectangle (&rect);
418 }
419
420 static void
421 move_and_update_window (GdkWindow *window, gint x, gint y)
422 {
423   GdkRegion *old_region;
424   GdkRegion *new_region;
425   GdkWindow *parent = gdk_window_get_parent (window);
426
427   old_region = get_window_region (window);
428   gdk_window_move (window, x, y);
429   new_region = get_window_region (window);
430                    
431   gdk_region_subtract (old_region, new_region);
432   gdk_window_invalidate_region (parent, old_region, TRUE);
433   gdk_region_destroy (old_region);
434   gdk_region_destroy (new_region);
435   
436   gdk_window_process_updates (parent, TRUE);
437 }
438
439 static gboolean
440 should_invert (GtkRange *range,
441                gboolean  horizontal)
442 {  
443   if (horizontal)
444     return
445       (range->inverted && !range->flippable) ||
446       (range->inverted && range->flippable && gtk_widget_get_direction (GTK_WIDGET (range)) == GTK_TEXT_DIR_LTR) ||
447       (!range->inverted && range->flippable && gtk_widget_get_direction (GTK_WIDGET (range)) == GTK_TEXT_DIR_RTL);
448   else
449     return range->inverted;
450 }
451
452 void
453 _gtk_range_default_hslider_update (GtkRange *range)
454 {
455   gint left;
456   gint right;
457   gint x;
458
459   g_return_if_fail (range != NULL);
460   g_return_if_fail (GTK_IS_RANGE (range));
461
462   if (GTK_WIDGET_REALIZED (range))
463     {
464       gtk_range_trough_hdims (range, &left, &right);
465       x = left;
466
467       if (range->adjustment->value < range->adjustment->lower)
468         {
469           range->adjustment->value = range->adjustment->lower;
470           gtk_signal_emit_by_name (GTK_OBJECT (range->adjustment), "value_changed");
471         }
472       else if (range->adjustment->value > range->adjustment->upper)
473         {
474           range->adjustment->value = range->adjustment->upper;
475           gtk_signal_emit_by_name (GTK_OBJECT (range->adjustment), "value_changed");
476         }
477
478       if (range->adjustment->lower != (range->adjustment->upper - range->adjustment->page_size))
479         x += ((right - left) * (range->adjustment->value - range->adjustment->lower) /
480               (range->adjustment->upper - range->adjustment->lower - range->adjustment->page_size));
481
482       if (x < left)
483         x = left;
484       else if (x > right)
485         x = right;
486
487       if (should_invert (range, TRUE))
488         x = right - (x - left);
489       
490       move_and_update_window (range->slider, x, GTK_WIDGET (range)->style->ythickness);
491     }
492 }
493
494 void
495 _gtk_range_default_vslider_update (GtkRange *range)
496 {
497   gint top;
498   gint bottom;
499   gint y;
500
501   g_return_if_fail (range != NULL);
502   g_return_if_fail (GTK_IS_RANGE (range));
503
504   if (GTK_WIDGET_REALIZED (range))
505     {
506       gtk_range_trough_vdims (range, &top, &bottom);
507       y = top;
508
509       if (range->adjustment->value < range->adjustment->lower)
510         {
511           range->adjustment->value = range->adjustment->lower;
512           gtk_signal_emit_by_name (GTK_OBJECT (range->adjustment), "value_changed");
513         }
514       else if (range->adjustment->value > range->adjustment->upper)
515         {
516           range->adjustment->value = range->adjustment->upper;
517           gtk_signal_emit_by_name (GTK_OBJECT (range->adjustment), "value_changed");
518         }
519
520       if (range->adjustment->lower != (range->adjustment->upper - range->adjustment->page_size))
521         y += ((bottom - top) * (range->adjustment->value - range->adjustment->lower) /
522               (range->adjustment->upper - range->adjustment->lower - range->adjustment->page_size));
523
524       if (y < top)
525         y = top;
526       else if (y > bottom)
527         y = bottom;
528
529       if (should_invert (range, FALSE))
530         y = bottom - (y - top);
531       
532       move_and_update_window (range->slider, GTK_WIDGET (range)->style->xthickness, y);
533     }
534 }
535
536 gint
537 _gtk_range_default_htrough_click (GtkRange *range,
538                                   gint      x,
539                                   gint      y,
540                                   gfloat   *jump_perc)
541 {
542   gint ythickness;
543   gint trough_width;
544   gint trough_height;
545   gint slider_x;
546   gint slider_length;
547   gint left, right;
548
549   g_return_val_if_fail (range != NULL, GTK_TROUGH_NONE);
550   g_return_val_if_fail (GTK_IS_RANGE (range), GTK_TROUGH_NONE);
551
552   ythickness = GTK_WIDGET (range)->style->ythickness;
553
554   gtk_range_trough_hdims (range, &left, &right);
555   gdk_window_get_size (range->slider, &slider_length, NULL);
556   right += slider_length;
557
558   if (should_invert (range, TRUE))
559     x = (right - x) + left;
560
561   if ((x > left) && (y > ythickness))
562     {
563       gdk_window_get_size (range->trough, &trough_width, &trough_height);
564
565       if ((x < right) && (y < (trough_height - ythickness)))
566         {
567           if (jump_perc)
568             {
569               *jump_perc = ((gdouble) (x - left)) / ((gdouble) (right - left));
570               return GTK_TROUGH_JUMP;
571             }
572           
573           gdk_window_get_position (range->slider, &slider_x, NULL);
574           
575           if (x < slider_x)
576             return GTK_TROUGH_START;
577           else
578             return GTK_TROUGH_END;
579         }
580     }
581
582   return GTK_TROUGH_NONE;
583 }
584
585 gint
586 _gtk_range_default_vtrough_click (GtkRange *range,
587                                   gint      x,
588                                   gint      y,
589                                   gfloat   *jump_perc)
590 {
591   gint xthickness;
592   gint trough_width;
593   gint trough_height;
594   gint slider_y;
595   gint top, bottom;
596   gint slider_length;
597
598   g_return_val_if_fail (range != NULL, GTK_TROUGH_NONE);
599   g_return_val_if_fail (GTK_IS_RANGE (range), GTK_TROUGH_NONE);
600
601   xthickness = GTK_WIDGET (range)->style->xthickness;
602
603   gtk_range_trough_vdims (range, &top, &bottom);
604   gdk_window_get_size (range->slider, NULL, &slider_length);
605   bottom += slider_length;
606
607   if (should_invert (range, FALSE))
608     y = (bottom - y) + top;
609   
610   if ((x > xthickness) && (y > top))
611     {
612       gdk_window_get_size (range->trough, &trough_width, &trough_height);
613
614       if ((x < (trough_width - xthickness) && (y < bottom)))
615         {
616           if (jump_perc)
617             {
618               *jump_perc = ((gdouble) (y - top)) / ((gdouble) (bottom - top));
619
620               return GTK_TROUGH_JUMP;
621             }
622           
623           gdk_window_get_position (range->slider, NULL, &slider_y);
624           
625           if (y < slider_y)
626             return GTK_TROUGH_START;
627           else
628             return GTK_TROUGH_END;
629         }
630     }
631
632   return GTK_TROUGH_NONE;
633 }
634
635 void
636 _gtk_range_default_hmotion (GtkRange *range,
637                             gint      xdelta,
638                             gint      ydelta)
639 {
640   gdouble old_value;
641   gint left, right;
642   gint slider_x, slider_y;
643   gint new_pos;
644
645   g_return_if_fail (GTK_IS_RANGE (range));
646   g_return_if_fail (GTK_WIDGET_REALIZED (range));
647
648   gdk_window_get_position (range->slider, &slider_x, &slider_y);
649   gtk_range_trough_hdims (range, &left, &right);
650
651   if (left == right)
652     return;
653
654   new_pos = slider_x + xdelta;
655
656   if (should_invert (range, TRUE))
657     new_pos = (right - new_pos) + left;
658
659   if (new_pos < left)
660     new_pos = left;
661   else if (new_pos > right)
662     new_pos = right;
663
664   old_value = range->adjustment->value;
665   range->adjustment->value = ((range->adjustment->upper -
666                                range->adjustment->lower -
667                                range->adjustment->page_size) *
668                               (new_pos - left) / (right - left) +
669                               range->adjustment->lower);
670
671   if (range->digits >= 0)
672     {
673       char buffer[64];
674
675       sprintf (buffer, "%0.*f", range->digits, range->adjustment->value);
676       sscanf (buffer, "%f", &range->adjustment->value);
677     }
678
679   if (old_value != range->adjustment->value)
680     {
681       if (range->policy == GTK_UPDATE_CONTINUOUS)
682         {
683           gtk_signal_emit_by_name (GTK_OBJECT (range->adjustment), "value_changed");
684         }
685       else
686         {
687           _gtk_range_slider_update (range);
688           _gtk_range_clear_background (range);
689
690           if (range->policy == GTK_UPDATE_DELAYED)
691             {
692               gtk_range_remove_timer (range);
693               range->timer = gtk_timeout_add (SCROLL_DELAY_LENGTH,
694                                               (GtkFunction) RANGE_CLASS (range)->timer,
695                                               (gpointer) range);
696             }
697         }
698     }
699 }
700
701 void
702 _gtk_range_default_vmotion (GtkRange *range,
703                             gint      xdelta,
704                             gint      ydelta)
705 {
706   gdouble old_value;
707   gint top, bottom;
708   gint slider_x, slider_y;
709   gint new_pos;
710
711   g_return_if_fail (GTK_IS_RANGE (range));
712   g_return_if_fail (GTK_WIDGET_REALIZED (range));
713
714   range = GTK_RANGE (range);
715
716   gdk_window_get_position (range->slider, &slider_x, &slider_y);
717   gtk_range_trough_vdims (range, &top, &bottom);
718
719   if (bottom == top)
720     return;
721
722   new_pos = slider_y + ydelta;
723
724   if (should_invert (range, FALSE))
725     new_pos = (bottom - new_pos) + top;
726   
727   if (new_pos < top)
728     new_pos = top;
729   else if (new_pos > bottom)
730     new_pos = bottom;
731
732   old_value = range->adjustment->value;
733   range->adjustment->value = ((range->adjustment->upper -
734                                range->adjustment->lower -
735                                range->adjustment->page_size) *
736                               (new_pos - top) / (bottom - top) +
737                               range->adjustment->lower);
738
739   if (range->digits >= 0)
740     {
741       char buffer[64];
742
743       sprintf (buffer, "%0.*f", range->digits, range->adjustment->value);
744       sscanf (buffer, "%f", &range->adjustment->value);
745     }
746
747   if (old_value != range->adjustment->value)
748     {
749       if (range->policy == GTK_UPDATE_CONTINUOUS)
750         {
751           gtk_signal_emit_by_name (GTK_OBJECT (range->adjustment), "value_changed");
752         }
753       else
754         {
755           _gtk_range_slider_update (range);
756           _gtk_range_clear_background (range);
757
758           if (range->policy == GTK_UPDATE_DELAYED)
759             {
760               gtk_range_remove_timer (range);
761               range->timer = gtk_timeout_add (SCROLL_DELAY_LENGTH,
762                                               (GtkFunction) RANGE_CLASS (range)->timer,
763                                               (gpointer) range);
764             }
765         }
766     }
767 }
768
769
770 static void
771 gtk_range_destroy (GtkObject *object)
772 {
773   GtkRange *range;
774
775   g_return_if_fail (object != NULL);
776   g_return_if_fail (GTK_IS_RANGE (object));
777
778   range = GTK_RANGE (object);
779
780   gtk_range_remove_timer (range);
781   if (range->adjustment)
782     {
783       if (range->adjustment)
784         gtk_signal_disconnect_by_data (GTK_OBJECT (range->adjustment),
785                                        (gpointer) range);
786       gtk_object_unref (GTK_OBJECT (range->adjustment));
787       range->adjustment = NULL;
788     }
789
790   (* GTK_OBJECT_CLASS (parent_class)->destroy) (object);
791 }
792
793 static void
794 gtk_range_unrealize (GtkWidget *widget)
795 {
796   GtkRange *range;
797
798   g_return_if_fail (widget != NULL);
799   g_return_if_fail (GTK_IS_RANGE (widget));
800
801   range = GTK_RANGE (widget);
802
803   if (range->slider)
804     {
805       gdk_window_set_user_data (range->slider, NULL);
806       gdk_window_destroy (range->slider);
807       range->slider = NULL;
808     }
809   if (range->trough)
810     {
811       gdk_window_set_user_data (range->trough, NULL);
812       gdk_window_destroy (range->trough);
813       range->trough = NULL;
814     }
815   if (range->step_forw)
816     {
817       gdk_window_set_user_data (range->step_forw, NULL);
818       gdk_window_destroy (range->step_forw);
819       range->step_forw = NULL;
820     }
821   if (range->step_back)
822     {
823       gdk_window_set_user_data (range->step_back, NULL);
824       gdk_window_destroy (range->step_back);
825       range->step_back = NULL;
826     }
827
828   if (GTK_WIDGET_CLASS (parent_class)->unrealize)
829     (* GTK_WIDGET_CLASS (parent_class)->unrealize) (widget);
830 }
831
832 static gint
833 gtk_range_expose (GtkWidget      *widget,
834                   GdkEventExpose *event)
835 {
836   GtkRange *range;
837
838   g_return_val_if_fail (widget != NULL, FALSE);
839   g_return_val_if_fail (GTK_IS_RANGE (widget), FALSE);
840   g_return_val_if_fail (event != NULL, FALSE);
841
842   range = GTK_RANGE (widget);
843
844   /* We should really pass another argument - 
845    *the redrawn area - to all the drawing functions)
846    */
847   if (event->window == range->trough)
848     {
849       _gtk_range_draw_trough (range);
850     }
851   else if (event->window == widget->window)
852     {
853       _gtk_range_draw_background (range); 
854     }
855   else if (event->window == range->slider)
856     {
857       _gtk_range_draw_slider (range);
858     }
859   else if (event->window == range->step_forw)
860     {
861       _gtk_range_draw_step_forw (range);
862     }
863   else if (event->window == range->step_back)
864     {
865       _gtk_range_draw_step_back (range);
866     }
867   return FALSE;
868 }
869
870 static gint
871 gtk_range_button_press (GtkWidget      *widget,
872                         GdkEventButton *event)
873 {
874   GtkRange *range;
875   gint trough_part;
876   gfloat jump_perc;
877
878   g_return_val_if_fail (GTK_IS_RANGE (widget), FALSE);
879   g_return_val_if_fail (event != NULL, FALSE);
880
881   if (!GTK_WIDGET_HAS_FOCUS (widget))
882     gtk_widget_grab_focus (widget);
883
884   jump_perc = -1;
885   range = GTK_RANGE (widget);
886   if (range->button == 0)
887     {
888       gtk_grab_add (widget);
889
890       range->button = event->button;
891       range->x_click_point = event->x;
892       range->y_click_point = event->y;
893
894       if (event->window == range->trough)
895         {
896           range->click_child = RANGE_CLASS (range)->trough;
897           
898           if (range->button == 2)
899             trough_part = _gtk_range_trough_click (range, event->x, event->y, &jump_perc);
900           else
901             trough_part = _gtk_range_trough_click (range, event->x, event->y, NULL);
902           
903           range->scroll_type = GTK_SCROLL_NONE;
904           if (trough_part == GTK_TROUGH_START)
905             range->scroll_type = GTK_SCROLL_PAGE_BACKWARD;
906           else if (trough_part == GTK_TROUGH_END)
907             range->scroll_type = GTK_SCROLL_PAGE_FORWARD;
908           else if (trough_part == GTK_TROUGH_JUMP &&
909                    jump_perc >= 0 && jump_perc <= 1)
910             range->scroll_type = GTK_SCROLL_JUMP;
911           
912           if (range->scroll_type != GTK_SCROLL_NONE)
913             {
914               gtk_range_scroll (range, jump_perc);
915               gtk_range_add_timer (range);
916             }
917         }
918       else if (event->window == range->slider)
919         {
920           range->click_child = RANGE_CLASS (range)->slider;
921           range->scroll_type = GTK_SCROLL_NONE;
922         }
923       else if (event->window == range->step_forw ||
924                event->window == range->step_back)
925         {
926           gboolean back = (event->window == range->step_back);
927           
928           if (range->button == 3)
929             {
930               range->scroll_type = GTK_SCROLL_JUMP;
931               gtk_range_scroll (range, back ? 0.0 : 1.0);
932             }
933           else
934             {
935               range->click_child =
936                 back ? RANGE_CLASS (range)->step_back
937                      : RANGE_CLASS (range)->step_forw;
938
939               if (range->button == 2)
940                 range->scroll_type =
941                   back ? GTK_SCROLL_PAGE_BACKWARD : GTK_SCROLL_PAGE_FORWARD;
942               else
943                 range->scroll_type =
944                   back ? GTK_SCROLL_STEP_BACKWARD : GTK_SCROLL_STEP_FORWARD;
945
946               gtk_range_scroll (range, -1);
947               gtk_range_add_timer (range);
948               
949               if (back)
950                 _gtk_range_draw_step_back (range);
951               else
952                 _gtk_range_draw_step_forw (range);
953             }
954         }
955     }
956
957   return TRUE;
958 }
959
960 static gint
961 gtk_range_button_release (GtkWidget      *widget,
962                           GdkEventButton *event)
963 {
964   GtkRange *range;
965
966   g_return_val_if_fail (GTK_IS_RANGE (widget), FALSE);
967   g_return_val_if_fail (event != NULL, FALSE);
968
969   range = GTK_RANGE (widget);
970
971   if (range->button == event->button)
972     {
973       gtk_grab_remove (widget);
974
975       range->button = 0;
976       range->x_click_point = -1;
977       range->y_click_point = -1;
978
979       if (range->click_child == RANGE_CLASS (range)->slider)
980         {
981           if (range->policy == GTK_UPDATE_DELAYED)
982             gtk_range_remove_timer (range);
983
984           if ((range->policy != GTK_UPDATE_CONTINUOUS) &&
985               (range->old_value != range->adjustment->value))
986             gtk_signal_emit_by_name (GTK_OBJECT (range->adjustment), "value_changed");
987         }
988       else if ((range->click_child == RANGE_CLASS (range)->trough) ||
989                (range->click_child == RANGE_CLASS (range)->step_forw) ||
990                (range->click_child == RANGE_CLASS (range)->step_back))
991         {
992           gtk_range_remove_timer (range);
993
994           if ((range->policy != GTK_UPDATE_CONTINUOUS) &&
995               (range->old_value != range->adjustment->value))
996             gtk_signal_emit_by_name (GTK_OBJECT (range->adjustment), "value_changed");
997
998           if (range->click_child == RANGE_CLASS (range)->step_forw)
999             {
1000               range->click_child = 0;
1001               _gtk_range_draw_step_forw (range);
1002             }
1003           else if (range->click_child == RANGE_CLASS (range)->step_back)
1004             {
1005               range->click_child = 0;
1006               _gtk_range_draw_step_back (range);
1007             }
1008         }
1009
1010       range->click_child = 0;
1011     }
1012
1013   return TRUE;
1014 }
1015
1016 static gint
1017 gtk_range_scroll_event (GtkWidget      *widget,
1018                         GdkEventScroll *event)
1019 {
1020   GtkRange *range;
1021
1022   g_return_val_if_fail (GTK_IS_RANGE (widget), FALSE);
1023   g_return_val_if_fail (event != NULL, FALSE);
1024
1025   range = GTK_RANGE (widget);
1026
1027   if (GTK_WIDGET_REALIZED (range))
1028     {
1029       GtkAdjustment *adj = GTK_RANGE (range)->adjustment;
1030       gfloat new_value = adj->value + ((event->direction == GDK_SCROLL_UP) ? 
1031                                        -adj->page_increment / 2: 
1032                                        adj->page_increment / 2);
1033       new_value = CLAMP (new_value, adj->lower, adj->upper - adj->page_size);
1034       gtk_adjustment_set_value (adj, new_value);
1035     }
1036
1037   return TRUE;
1038 }
1039
1040 static gint
1041 gtk_range_motion_notify (GtkWidget      *widget,
1042                          GdkEventMotion *event)
1043 {
1044   GtkRange *range;
1045
1046   g_return_val_if_fail (GTK_IS_RANGE (widget), FALSE);
1047   g_return_val_if_fail (event != NULL, FALSE);
1048
1049   range = GTK_RANGE (widget);
1050
1051   if (range->click_child == RANGE_CLASS (range)->slider)
1052     {
1053       GdkModifierType mods;
1054       gint x, y, mask, x2, y2;
1055
1056       gdk_window_get_pointer (range->trough, &x, &y, &mods);
1057       gdk_window_get_position (range->slider, &x2, &y2);
1058
1059       x -= x2;
1060       y -= y2;
1061
1062       switch (range->button)
1063         {
1064         case 1:
1065           mask = GDK_BUTTON1_MASK;
1066           break;
1067         case 2:
1068           mask = GDK_BUTTON2_MASK;
1069           break;
1070         case 3:
1071           mask = GDK_BUTTON3_MASK;
1072           break;
1073         default:
1074           mask = 0;
1075           break;
1076         }
1077
1078       if (mods & mask)
1079         {
1080           if (RANGE_CLASS (range)->motion)
1081             (* RANGE_CLASS (range)->motion) (range, x - range->x_click_point, y - range->y_click_point);
1082         }
1083     }
1084
1085   return TRUE;
1086 }
1087
1088 static gint
1089 gtk_range_key_press (GtkWidget   *widget,
1090                      GdkEventKey *event)
1091 {
1092   GtkRange *range;
1093   gint return_val;
1094   GtkScrollType scroll = GTK_SCROLL_NONE;
1095   GtkTroughType pos = GTK_TROUGH_NONE;
1096
1097   g_return_val_if_fail (GTK_IS_RANGE (widget), FALSE);
1098   g_return_val_if_fail (event != NULL, FALSE);
1099
1100   range = GTK_RANGE (widget);
1101   return_val = FALSE;
1102   
1103   if (RANGE_CLASS (range)->trough_keys)
1104     return_val = (* RANGE_CLASS (range)->trough_keys) (range, event, &scroll, &pos);
1105
1106   if (return_val)
1107     {
1108       if (scroll != GTK_SCROLL_NONE)
1109         {
1110           range->scroll_type = scroll;
1111
1112           gtk_range_scroll (range, -1);
1113           if (range->old_value != range->adjustment->value)
1114             {
1115               gtk_signal_emit_by_name (GTK_OBJECT (range->adjustment), "value_changed");
1116               switch (range->scroll_type)
1117                 {
1118                 case GTK_SCROLL_STEP_LEFT:
1119                   if (should_invert (range, TRUE))
1120                     _gtk_range_draw_step_forw (range);
1121                   else
1122                     _gtk_range_draw_step_back (range);
1123                   break;
1124                     
1125                 case GTK_SCROLL_STEP_UP:
1126                   if (should_invert (range, FALSE))
1127                     _gtk_range_draw_step_forw (range);
1128                   else
1129                     _gtk_range_draw_step_back (range);
1130                   break;
1131
1132                 case GTK_SCROLL_STEP_RIGHT:
1133                   if (should_invert (range, TRUE))
1134                     _gtk_range_draw_step_back (range);
1135                   else
1136                     _gtk_range_draw_step_forw (range);
1137                   break;
1138                     
1139                 case GTK_SCROLL_STEP_DOWN:
1140                   if (should_invert (range, FALSE))
1141                     _gtk_range_draw_step_back (range);
1142                   else
1143                     _gtk_range_draw_step_forw (range);
1144                   break;
1145                   
1146                 case GTK_SCROLL_STEP_BACKWARD:
1147                   _gtk_range_draw_step_back (range);
1148                   break;
1149                   
1150                 case GTK_SCROLL_STEP_FORWARD:
1151                   _gtk_range_draw_step_forw (range);
1152                   break;
1153                 }
1154             }
1155         }
1156       if (pos != GTK_TROUGH_NONE)
1157         {
1158           if (pos == GTK_TROUGH_START)
1159             range->adjustment->value = range->adjustment->lower;
1160           else if (pos == GTK_TROUGH_END)
1161             range->adjustment->value =
1162               range->adjustment->upper - range->adjustment->page_size;
1163
1164           if (range->old_value != range->adjustment->value)
1165             {
1166               gtk_signal_emit_by_name (GTK_OBJECT (range->adjustment),
1167                                        "value_changed");
1168
1169               _gtk_range_slider_update (range);
1170               _gtk_range_clear_background (range);
1171             }
1172         }
1173     }
1174   return return_val;
1175 }
1176
1177 static gint
1178 gtk_range_enter_notify (GtkWidget        *widget,
1179                         GdkEventCrossing *event)
1180 {
1181   GtkRange *range;
1182
1183   g_return_val_if_fail (GTK_IS_RANGE (widget), FALSE);
1184   g_return_val_if_fail (event != NULL, FALSE);
1185
1186   range = GTK_RANGE (widget);
1187
1188   if (event->window == range->trough)
1189     {
1190       range->in_child = RANGE_CLASS (range)->trough;
1191     }
1192   else if (event->window == range->slider)
1193     {
1194       range->in_child = RANGE_CLASS (range)->slider;
1195
1196       if ((range->click_child == 0) ||
1197           (range->click_child == RANGE_CLASS (range)->trough))
1198         _gtk_range_draw_slider (range);
1199     }
1200   else if (event->window == range->step_forw)
1201     {
1202       range->in_child = RANGE_CLASS (range)->step_forw;
1203
1204       if ((range->click_child == 0) ||
1205           (range->click_child == RANGE_CLASS (range)->trough))
1206         _gtk_range_draw_step_forw (range);
1207     }
1208   else if (event->window == range->step_back)
1209     {
1210       range->in_child = RANGE_CLASS (range)->step_back;
1211
1212       if ((range->click_child == 0) ||
1213           (range->click_child == RANGE_CLASS (range)->trough))
1214         _gtk_range_draw_step_back (range);
1215     }
1216
1217   return TRUE;
1218 }
1219
1220 static gint
1221 gtk_range_leave_notify (GtkWidget        *widget,
1222                         GdkEventCrossing *event)
1223 {
1224   GtkRange *range;
1225
1226   g_return_val_if_fail (GTK_IS_RANGE (widget), FALSE);
1227   g_return_val_if_fail (event != NULL, FALSE);
1228
1229   range = GTK_RANGE (widget);
1230
1231   range->in_child = 0;
1232
1233   if (event->window == range->trough)
1234     {
1235     }
1236   else if (event->window == range->slider)
1237     {
1238       if ((range->click_child == 0) ||
1239           (range->click_child == RANGE_CLASS (range)->trough))
1240         _gtk_range_draw_slider (range);
1241     }
1242   else if (event->window == range->step_forw)
1243     {
1244       if ((range->click_child == 0) ||
1245           (range->click_child == RANGE_CLASS (range)->trough))
1246         _gtk_range_draw_step_forw (range);
1247     }
1248   else if (event->window == range->step_back)
1249     {
1250       if ((range->click_child == 0) ||
1251           (range->click_child == RANGE_CLASS (range)->trough))
1252         _gtk_range_draw_step_back (range);
1253     }
1254
1255   return TRUE;
1256 }
1257
1258 static void
1259 gtk_real_range_draw_trough (GtkRange *range)
1260 {
1261   g_return_if_fail (GTK_IS_RANGE (range));
1262
1263   if (range->trough)
1264      {
1265         gtk_paint_box (GTK_WIDGET (range)->style, range->trough,
1266                        GTK_STATE_ACTIVE, GTK_SHADOW_IN,
1267                        NULL, GTK_WIDGET(range), "trough",
1268                        0, 0, -1, -1);
1269         if (GTK_WIDGET_HAS_FOCUS (range))
1270           gtk_paint_focus (GTK_WIDGET (range)->style,
1271                           range->trough,
1272                            NULL, GTK_WIDGET(range), "trough",
1273                           0, 0, -1, -1);
1274     }
1275 }
1276
1277 static void
1278 gtk_real_range_draw_slider (GtkRange *range)
1279 {
1280   GtkStateType state_type;
1281    
1282   g_return_if_fail (GTK_IS_RANGE (range));
1283    
1284   if (range->slider)
1285     {
1286       if ((range->in_child == RANGE_CLASS (range)->slider) ||
1287           (range->click_child == RANGE_CLASS (range)->slider))
1288         state_type = GTK_STATE_PRELIGHT;
1289       else
1290         state_type = GTK_STATE_NORMAL;
1291       gtk_paint_box (GTK_WIDGET (range)->style, range->slider,
1292                      state_type, GTK_SHADOW_OUT,
1293                      NULL, GTK_WIDGET (range), "slider",
1294                      0, 0, -1, -1);
1295     }
1296 }
1297
1298 static gint
1299 gtk_real_range_timer (GtkRange *range)
1300 {
1301   gint return_val;
1302
1303   GDK_THREADS_ENTER ();
1304
1305   return_val = TRUE;
1306   if (range->click_child == RANGE_CLASS (range)->slider)
1307     {
1308       if (range->policy == GTK_UPDATE_DELAYED)
1309         gtk_signal_emit_by_name (GTK_OBJECT (range->adjustment), "value_changed");
1310       return_val = FALSE;
1311     }
1312   else
1313     {
1314       GdkModifierType mods, mask;
1315
1316       if (!range->timer)
1317         {
1318           return_val = FALSE;
1319           if (range->need_timer)
1320             range->timer = gtk_timeout_add (SCROLL_TIMER_LENGTH,
1321                                             (GtkFunction) RANGE_CLASS (range)->timer,
1322                                             (gpointer) range);
1323           else
1324             {
1325               GDK_THREADS_LEAVE ();
1326               return FALSE;
1327             }
1328           range->need_timer = FALSE;
1329         }
1330
1331       switch (range->button)
1332         {
1333         case 1:
1334           mask = GDK_BUTTON1_MASK;
1335           break;
1336         case 2:
1337           mask = GDK_BUTTON2_MASK;
1338           break;
1339         case 3:
1340           mask = GDK_BUTTON3_MASK;
1341           break;
1342         default:
1343           mask = 0;
1344           break;
1345         }
1346
1347       gdk_window_get_pointer (range->slider, NULL, NULL, &mods);
1348
1349       if (mods & mask)
1350         return_val = gtk_range_scroll (range, -1);
1351     }
1352
1353   GDK_THREADS_LEAVE ();
1354
1355   return return_val;
1356 }
1357
1358 static gint
1359 gtk_range_scroll (GtkRange *range,
1360                   gfloat    jump_perc)
1361 {
1362   gfloat new_value;
1363   gint return_val;
1364   GtkScrollType scroll_type;
1365   
1366   g_return_val_if_fail (GTK_IS_RANGE (range), FALSE);
1367
1368   new_value = range->adjustment->value;
1369   return_val = TRUE;
1370
1371   /* Translate visual to logical */
1372
1373   scroll_type = range->scroll_type;
1374   switch (scroll_type)
1375     {
1376     case GTK_SCROLL_STEP_UP:
1377       if (should_invert (range, FALSE))
1378         scroll_type = GTK_SCROLL_STEP_FORWARD;
1379       else
1380         scroll_type = GTK_SCROLL_STEP_BACKWARD;
1381       break;
1382
1383     case GTK_SCROLL_STEP_DOWN:
1384       if (should_invert (range, FALSE))
1385         scroll_type = GTK_SCROLL_STEP_BACKWARD;
1386       else
1387         scroll_type = GTK_SCROLL_STEP_FORWARD;
1388       break;
1389
1390     case GTK_SCROLL_PAGE_UP:
1391       if (should_invert (range, FALSE))
1392         scroll_type = GTK_SCROLL_PAGE_FORWARD;
1393       else
1394         scroll_type = GTK_SCROLL_PAGE_BACKWARD;
1395       break;
1396
1397     case GTK_SCROLL_PAGE_DOWN:
1398       if (should_invert (range, FALSE))
1399         scroll_type = GTK_SCROLL_PAGE_BACKWARD;
1400       else
1401         scroll_type = GTK_SCROLL_PAGE_FORWARD;
1402       break;
1403
1404     case GTK_SCROLL_STEP_LEFT:
1405       if (should_invert (range, TRUE))
1406         scroll_type = GTK_SCROLL_STEP_FORWARD;
1407       else
1408         scroll_type = GTK_SCROLL_STEP_BACKWARD;
1409       break;
1410
1411     case GTK_SCROLL_STEP_RIGHT:
1412       if (should_invert (range, TRUE))
1413         scroll_type = GTK_SCROLL_STEP_BACKWARD;
1414       else
1415         scroll_type = GTK_SCROLL_STEP_FORWARD;
1416       break;
1417
1418     case GTK_SCROLL_PAGE_LEFT:
1419       if (should_invert (range, TRUE))
1420         scroll_type = GTK_SCROLL_PAGE_FORWARD;
1421       else
1422         scroll_type = GTK_SCROLL_PAGE_BACKWARD;
1423       break;
1424
1425     case GTK_SCROLL_PAGE_RIGHT:
1426       if (should_invert (range, TRUE))
1427         scroll_type = GTK_SCROLL_PAGE_BACKWARD;
1428       else
1429         scroll_type = GTK_SCROLL_PAGE_FORWARD;
1430       break;
1431
1432     default:
1433       break;
1434     }
1435   
1436   switch (scroll_type)
1437     {
1438     case GTK_SCROLL_NONE:
1439       break;
1440       
1441     case GTK_SCROLL_JUMP:
1442       if (jump_perc >= 0 && jump_perc <= 1)
1443         {
1444           new_value = (range->adjustment->lower +
1445                        (range->adjustment->upper - range->adjustment->page_size -
1446                         range->adjustment->lower) * jump_perc);
1447         }
1448       break;
1449       
1450     case GTK_SCROLL_STEP_BACKWARD:
1451       new_value -= range->adjustment->step_increment;
1452       if (new_value <= range->adjustment->lower)
1453         {
1454           new_value = range->adjustment->lower;
1455           return_val = FALSE;
1456           range->timer = 0;
1457         }
1458       break;
1459
1460     case GTK_SCROLL_STEP_FORWARD:
1461       new_value += range->adjustment->step_increment;
1462       if (new_value >= (range->adjustment->upper - range->adjustment->page_size))
1463         {
1464           new_value = range->adjustment->upper - range->adjustment->page_size;
1465           return_val = FALSE;
1466           range->timer = 0;
1467         }
1468       break;
1469
1470     case GTK_SCROLL_PAGE_BACKWARD:
1471       new_value -= range->adjustment->page_increment;
1472       if (new_value <= range->adjustment->lower)
1473         {
1474           new_value = range->adjustment->lower;
1475           return_val = FALSE;
1476           range->timer = 0;
1477         }
1478       break;
1479
1480     case GTK_SCROLL_PAGE_FORWARD:
1481       new_value += range->adjustment->page_increment;
1482       if (new_value >= (range->adjustment->upper - range->adjustment->page_size))
1483         {
1484           new_value = range->adjustment->upper - range->adjustment->page_size;
1485           return_val = FALSE;
1486           range->timer = 0;
1487         }
1488       break;
1489
1490     case GTK_SCROLL_STEP_UP:
1491     case GTK_SCROLL_STEP_DOWN:
1492     case GTK_SCROLL_PAGE_UP:
1493     case GTK_SCROLL_PAGE_DOWN:
1494     case GTK_SCROLL_STEP_LEFT:
1495     case GTK_SCROLL_STEP_RIGHT:
1496     case GTK_SCROLL_PAGE_LEFT:
1497     case GTK_SCROLL_PAGE_RIGHT:
1498       g_assert_not_reached ();
1499       break;
1500
1501     }
1502   
1503   if (new_value != range->adjustment->value)
1504     {
1505       range->adjustment->value = new_value;
1506
1507       if ((range->policy == GTK_UPDATE_CONTINUOUS) ||
1508           (!return_val && (range->policy == GTK_UPDATE_DELAYED)))
1509         {
1510           gtk_signal_emit_by_name (GTK_OBJECT (range->adjustment), "value_changed");
1511         }
1512       else
1513         {
1514           _gtk_range_slider_update (range);
1515           _gtk_range_clear_background (range);
1516         }
1517     }
1518
1519   return return_val;
1520 }
1521
1522
1523 static gboolean
1524 gtk_range_timer_1st_time (GtkRange *range)
1525 {
1526   /*
1527    * If the real timeout function succeeds and the timeout is still set,
1528    * replace it with a quicker one so successive scrolling goes faster.
1529    */
1530   gtk_object_ref (GTK_OBJECT (range));
1531
1532   if (RANGE_CLASS (range)->timer (range))
1533     {
1534       if (range->timer)
1535         {
1536           /* We explicitely remove ourselves here in the paranoia
1537            * that due to things happening above in the callback
1538            * above, we might have been removed, and another added.
1539            */
1540           g_source_remove (range->timer);
1541           range->timer = gtk_timeout_add (SCROLL_LATER_DELAY,
1542                                           (GtkFunction) RANGE_CLASS (range)->timer,
1543                                           range);
1544         }
1545     }
1546   
1547   gtk_object_unref (GTK_OBJECT (range));
1548   
1549   return FALSE;  /* don't keep calling this function */
1550 }
1551
1552 static void
1553 gtk_range_add_timer (GtkRange *range)
1554 {
1555   g_return_if_fail (GTK_IS_RANGE (range));
1556
1557   if (!range->timer)
1558     {
1559       range->need_timer = TRUE;
1560       range->timer = gtk_timeout_add (SCROLL_INITIAL_DELAY,
1561                                       (GtkFunction) gtk_range_timer_1st_time,
1562                                       range);
1563     }
1564 }
1565
1566 static void
1567 gtk_range_remove_timer (GtkRange *range)
1568 {
1569   g_return_if_fail (GTK_IS_RANGE (range));
1570
1571   if (range->timer)
1572     {
1573       gtk_timeout_remove (range->timer);
1574       range->timer = 0;
1575     }
1576   range->need_timer = FALSE;
1577 }
1578
1579 static void
1580 gtk_range_adjustment_changed (GtkAdjustment *adjustment,
1581                               gpointer       data)
1582 {
1583   GtkRange *range;
1584
1585   g_return_if_fail (adjustment != NULL);
1586   g_return_if_fail (data != NULL);
1587
1588   range = GTK_RANGE (data);
1589
1590   if (((range->old_lower != adjustment->lower) ||
1591        (range->old_upper != adjustment->upper) ||
1592        (range->old_page_size != adjustment->page_size)) &&
1593       (range->old_value == adjustment->value))
1594     {
1595       if ((adjustment->lower == adjustment->upper) ||
1596           (range->old_lower == (range->old_upper - range->old_page_size)))
1597         {
1598           adjustment->value = adjustment->lower;
1599           gtk_signal_emit_by_name (GTK_OBJECT (adjustment), "value_changed");
1600         }
1601     }
1602
1603   if ((range->old_value != adjustment->value) ||
1604       (range->old_lower != adjustment->lower) ||
1605       (range->old_upper != adjustment->upper) ||
1606       (range->old_page_size != adjustment->page_size))
1607     {
1608       _gtk_range_slider_update (range);
1609       _gtk_range_clear_background (range);
1610
1611       range->old_value = adjustment->value;
1612       range->old_lower = adjustment->lower;
1613       range->old_upper = adjustment->upper;
1614       range->old_page_size = adjustment->page_size;
1615     }
1616 }
1617
1618 static void
1619 gtk_range_adjustment_value_changed (GtkAdjustment *adjustment,
1620                                     gpointer       data)
1621 {
1622   GtkRange *range;
1623
1624   g_return_if_fail (adjustment != NULL);
1625   g_return_if_fail (data != NULL);
1626
1627   range = GTK_RANGE (data);
1628
1629   if (range->old_value != adjustment->value)
1630     {
1631       _gtk_range_slider_update (range);
1632       _gtk_range_clear_background (range);
1633
1634       range->old_value = adjustment->value;
1635     }
1636 }
1637
1638
1639 static void
1640 gtk_range_trough_hdims (GtkRange *range,
1641                         gint     *left,
1642                         gint     *right)
1643 {
1644   gint trough_width;
1645   gint slider_length;
1646   gint tmp_width;
1647   gint tleft;
1648   gint tright;
1649
1650   g_return_if_fail (range != NULL);
1651
1652   gdk_window_get_size (range->trough, &trough_width, NULL);
1653   gdk_window_get_size (range->slider, &slider_length, NULL);
1654
1655   tleft = GTK_WIDGET (range)->style->xthickness;
1656   tright = trough_width - slider_length - GTK_WIDGET (range)->style->xthickness;
1657
1658   if (range->step_back)
1659     {
1660       gdk_window_get_size (range->step_back, &tmp_width, NULL);
1661       tleft += (tmp_width + RANGE_CLASS (range)->stepper_slider_spacing);
1662     }
1663
1664   if (range->step_forw)
1665     {
1666       gdk_window_get_size (range->step_forw, &tmp_width, NULL);
1667       tright -= (tmp_width + RANGE_CLASS (range)->stepper_slider_spacing);
1668     }
1669
1670   if (left)
1671     *left = tleft;
1672   if (right)
1673     *right = tright;
1674 }
1675
1676 static void
1677 gtk_range_trough_vdims (GtkRange *range,
1678                         gint     *top,
1679                         gint     *bottom)
1680 {
1681   gint trough_height;
1682   gint slider_length;
1683   gint tmp_height;
1684   gint ttop;
1685   gint tbottom;
1686
1687   g_return_if_fail (range != NULL);
1688
1689   gdk_window_get_size (range->trough, NULL, &trough_height);
1690   gdk_window_get_size (range->slider, NULL, &slider_length);
1691
1692   ttop = GTK_WIDGET (range)->style->ythickness;
1693   tbottom = trough_height - slider_length - GTK_WIDGET (range)->style->ythickness;
1694
1695   if (range->step_back)
1696     {
1697       gdk_window_get_size (range->step_back, NULL, &tmp_height);
1698       ttop += (tmp_height + RANGE_CLASS (range)->stepper_slider_spacing);
1699     }
1700
1701   if (range->step_forw)
1702     {
1703       gdk_window_get_size (range->step_forw, NULL, &tmp_height);
1704       tbottom -= (tmp_height + RANGE_CLASS (range)->stepper_slider_spacing);
1705     }
1706
1707   if (top)
1708     *top = ttop;
1709   if (bottom)
1710     *bottom = tbottom;
1711 }
1712
1713 static void
1714 gtk_range_style_set (GtkWidget *widget,
1715                       GtkStyle  *previous_style)
1716 {
1717   GtkRange *range;
1718
1719   g_return_if_fail (widget != NULL);
1720   g_return_if_fail (GTK_IS_RANGE (widget));
1721
1722   range = GTK_RANGE (widget);
1723
1724   if (GTK_WIDGET_REALIZED (widget))
1725     {
1726       if (range->trough)
1727         gtk_style_set_background (widget->style, range->trough, GTK_STATE_ACTIVE);
1728
1729       if (range->slider)
1730         gtk_style_set_background (widget->style, range->slider, GTK_STATE_NORMAL);
1731       
1732       /* The backgrounds of the step_forw and step_back never actually
1733        * get drawn in draw calls, so we call gdk_window_clear() here
1734        * so they get the correct colors. This is a hack. OWT.
1735        */
1736
1737       if (range->step_forw)
1738         {
1739           gtk_style_set_background (widget->style, range->step_forw, GTK_STATE_ACTIVE);
1740           gdk_window_clear (range->step_forw);
1741         }
1742
1743       if (range->step_back)
1744         {
1745           gtk_style_set_background (widget->style, range->step_back, GTK_STATE_ACTIVE);
1746           gdk_window_clear (range->step_back);
1747         }
1748     }
1749 }