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