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