]> Pileus Git - ~andy/gtk/blob - gtk/gtkrange.c
use FALSE for size_only most of the time when calling
[~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 static GdkRegion *
396 get_window_region (GdkWindow *window)
397 {
398   GdkRectangle rect;
399
400   gdk_window_get_position (window, &rect.x, &rect.y);
401   gdk_window_get_size (window, &rect.width, &rect.height);
402
403   return gdk_region_rectangle (&rect);
404 }
405
406 static void
407 move_and_update_window (GdkWindow *window, gint x, gint y)
408 {
409   GdkRegion *old_region;
410   GdkRegion *new_region;
411   GdkWindow *parent = gdk_window_get_parent (window);
412
413   old_region = get_window_region (window);
414   gdk_window_move (window, x, y);
415   new_region = get_window_region (window);
416                    
417   gdk_region_subtract (old_region, new_region);
418   gdk_window_invalidate_region (parent, old_region, TRUE);
419   gdk_region_destroy (old_region);
420   gdk_region_destroy (new_region);
421   
422   gdk_window_process_updates (parent, TRUE);
423 }
424
425 void
426 gtk_range_default_hslider_update (GtkRange *range)
427 {
428   gint left;
429   gint right;
430   gint x;
431
432   g_return_if_fail (range != NULL);
433   g_return_if_fail (GTK_IS_RANGE (range));
434
435   if (GTK_WIDGET_REALIZED (range))
436     {
437       gtk_range_trough_hdims (range, &left, &right);
438       x = left;
439
440       if (range->adjustment->value < range->adjustment->lower)
441         {
442           range->adjustment->value = range->adjustment->lower;
443           gtk_signal_emit_by_name (GTK_OBJECT (range->adjustment), "value_changed");
444         }
445       else if (range->adjustment->value > range->adjustment->upper)
446         {
447           range->adjustment->value = range->adjustment->upper;
448           gtk_signal_emit_by_name (GTK_OBJECT (range->adjustment), "value_changed");
449         }
450
451       if (range->adjustment->lower != (range->adjustment->upper - range->adjustment->page_size))
452         x += ((right - left) * (range->adjustment->value - range->adjustment->lower) /
453               (range->adjustment->upper - range->adjustment->lower - range->adjustment->page_size));
454
455       if (x < left)
456         x = left;
457       else if (x > right)
458         x = right;
459
460       move_and_update_window (range->slider, x, GTK_WIDGET (range)->style->ythickness);
461     }
462 }
463
464 void
465 gtk_range_default_vslider_update (GtkRange *range)
466 {
467   gint top;
468   gint bottom;
469   gint y;
470
471   g_return_if_fail (range != NULL);
472   g_return_if_fail (GTK_IS_RANGE (range));
473
474   if (GTK_WIDGET_REALIZED (range))
475     {
476       gtk_range_trough_vdims (range, &top, &bottom);
477       y = top;
478
479       if (range->adjustment->value < range->adjustment->lower)
480         {
481           range->adjustment->value = range->adjustment->lower;
482           gtk_signal_emit_by_name (GTK_OBJECT (range->adjustment), "value_changed");
483         }
484       else if (range->adjustment->value > range->adjustment->upper)
485         {
486           range->adjustment->value = range->adjustment->upper;
487           gtk_signal_emit_by_name (GTK_OBJECT (range->adjustment), "value_changed");
488         }
489
490       if (range->adjustment->lower != (range->adjustment->upper - range->adjustment->page_size))
491         y += ((bottom - top) * (range->adjustment->value - range->adjustment->lower) /
492               (range->adjustment->upper - range->adjustment->lower - range->adjustment->page_size));
493
494       if (y < top)
495         y = top;
496       else if (y > bottom)
497         y = bottom;
498
499       move_and_update_window (range->slider, GTK_WIDGET (range)->style->xthickness, y);
500     }
501 }
502
503 gint
504 gtk_range_default_htrough_click (GtkRange *range,
505                                  gint      x,
506                                  gint      y,
507                                  gfloat   *jump_perc)
508 {
509   gint ythickness;
510   gint trough_width;
511   gint trough_height;
512   gint slider_x;
513   gint slider_length;
514   gint left, right;
515
516   g_return_val_if_fail (range != NULL, GTK_TROUGH_NONE);
517   g_return_val_if_fail (GTK_IS_RANGE (range), GTK_TROUGH_NONE);
518
519   ythickness = GTK_WIDGET (range)->style->ythickness;
520
521   gtk_range_trough_hdims (range, &left, &right);
522   gdk_window_get_size (range->slider, &slider_length, NULL);
523   right += slider_length;
524               
525   if ((x > left) && (y > ythickness))
526     {
527       gdk_window_get_size (range->trough, &trough_width, &trough_height);
528
529       if ((x < right) && (y < (trough_height - ythickness)))
530         {
531           if (jump_perc)
532             {
533               *jump_perc = ((gdouble) (x - left)) / ((gdouble) (right - left));
534               return GTK_TROUGH_JUMP;
535             }
536           
537           gdk_window_get_position (range->slider, &slider_x, NULL);
538           
539           if (x < slider_x)
540             return GTK_TROUGH_START;
541           else
542             return GTK_TROUGH_END;
543         }
544     }
545
546   return GTK_TROUGH_NONE;
547 }
548
549 gint
550 gtk_range_default_vtrough_click (GtkRange *range,
551                                  gint      x,
552                                  gint      y,
553                                  gfloat   *jump_perc)
554 {
555   gint xthickness;
556   gint trough_width;
557   gint trough_height;
558   gint slider_y;
559   gint top, bottom;
560   gint slider_length;
561
562   g_return_val_if_fail (range != NULL, GTK_TROUGH_NONE);
563   g_return_val_if_fail (GTK_IS_RANGE (range), GTK_TROUGH_NONE);
564
565   xthickness = GTK_WIDGET (range)->style->xthickness;
566
567   gtk_range_trough_vdims (range, &top, &bottom);
568   gdk_window_get_size (range->slider, NULL, &slider_length);
569   bottom += slider_length;
570               
571   if ((x > xthickness) && (y > top))
572     {
573       gdk_window_get_size (range->trough, &trough_width, &trough_height);
574
575       if ((x < (trough_width - xthickness) && (y < bottom)))
576         {
577           if (jump_perc)
578             {
579               *jump_perc = ((gdouble) (y - top)) / ((gdouble) (bottom - top));
580
581               return GTK_TROUGH_JUMP;
582             }
583           
584           gdk_window_get_position (range->slider, NULL, &slider_y);
585           
586           if (y < slider_y)
587             return GTK_TROUGH_START;
588           else
589             return GTK_TROUGH_END;
590         }
591     }
592
593   return GTK_TROUGH_NONE;
594 }
595
596 void
597 gtk_range_default_hmotion (GtkRange *range,
598                            gint      xdelta,
599                            gint      ydelta)
600 {
601   gdouble old_value;
602   gint left, right;
603   gint slider_x, slider_y;
604   gint new_pos;
605
606   g_return_if_fail (GTK_IS_RANGE (range));
607   g_return_if_fail (GTK_WIDGET_REALIZED (range));
608
609   range = GTK_RANGE (range);
610
611   gdk_window_get_position (range->slider, &slider_x, &slider_y);
612   gtk_range_trough_hdims (range, &left, &right);
613
614   if (left == right)
615     return;
616
617   new_pos = slider_x + xdelta;
618
619   if (new_pos < left)
620     new_pos = left;
621   else if (new_pos > right)
622     new_pos = right;
623
624   old_value = range->adjustment->value;
625   range->adjustment->value = ((range->adjustment->upper -
626                                range->adjustment->lower -
627                                range->adjustment->page_size) *
628                               (new_pos - left) / (right - left) +
629                               range->adjustment->lower);
630
631   if (range->digits >= 0)
632     {
633       char buffer[64];
634
635       sprintf (buffer, "%0.*f", range->digits, range->adjustment->value);
636       sscanf (buffer, "%f", &range->adjustment->value);
637     }
638
639   if (old_value != range->adjustment->value)
640     {
641       if (range->policy == GTK_UPDATE_CONTINUOUS)
642         {
643           gtk_signal_emit_by_name (GTK_OBJECT (range->adjustment), "value_changed");
644         }
645       else
646         {
647           gtk_range_slider_update (range);
648           gtk_range_clear_background (range);
649
650           if (range->policy == GTK_UPDATE_DELAYED)
651             {
652               gtk_range_remove_timer (range);
653               range->timer = gtk_timeout_add (SCROLL_DELAY_LENGTH,
654                                               (GtkFunction) RANGE_CLASS (range)->timer,
655                                               (gpointer) range);
656             }
657         }
658     }
659 }
660
661 void
662 gtk_range_default_vmotion (GtkRange *range,
663                            gint      xdelta,
664                            gint      ydelta)
665 {
666   gdouble old_value;
667   gint top, bottom;
668   gint slider_x, slider_y;
669   gint new_pos;
670
671   g_return_if_fail (GTK_IS_RANGE (range));
672   g_return_if_fail (GTK_WIDGET_REALIZED (range));
673
674   range = GTK_RANGE (range);
675
676   gdk_window_get_position (range->slider, &slider_x, &slider_y);
677   gtk_range_trough_vdims (range, &top, &bottom);
678
679   if (bottom == top)
680     return;
681
682   new_pos = slider_y + ydelta;
683
684   if (new_pos < top)
685     new_pos = top;
686   else if (new_pos > bottom)
687     new_pos = bottom;
688
689   old_value = range->adjustment->value;
690   range->adjustment->value = ((range->adjustment->upper -
691                                range->adjustment->lower -
692                                range->adjustment->page_size) *
693                               (new_pos - top) / (bottom - top) +
694                               range->adjustment->lower);
695
696   if (range->digits >= 0)
697     {
698       char buffer[64];
699
700       sprintf (buffer, "%0.*f", range->digits, range->adjustment->value);
701       sscanf (buffer, "%f", &range->adjustment->value);
702     }
703
704   if (old_value != range->adjustment->value)
705     {
706       if (range->policy == GTK_UPDATE_CONTINUOUS)
707         {
708           gtk_signal_emit_by_name (GTK_OBJECT (range->adjustment), "value_changed");
709         }
710       else
711         {
712           gtk_range_slider_update (range);
713           gtk_range_clear_background (range);
714
715           if (range->policy == GTK_UPDATE_DELAYED)
716             {
717               gtk_range_remove_timer (range);
718               range->timer = gtk_timeout_add (SCROLL_DELAY_LENGTH,
719                                               (GtkFunction) RANGE_CLASS (range)->timer,
720                                               (gpointer) range);
721             }
722         }
723     }
724 }
725
726
727 static void
728 gtk_range_destroy (GtkObject *object)
729 {
730   GtkRange *range;
731
732   g_return_if_fail (object != NULL);
733   g_return_if_fail (GTK_IS_RANGE (object));
734
735   range = GTK_RANGE (object);
736
737   gtk_range_remove_timer (range);
738   if (range->adjustment)
739     {
740       if (range->adjustment)
741         gtk_signal_disconnect_by_data (GTK_OBJECT (range->adjustment),
742                                        (gpointer) range);
743       gtk_object_unref (GTK_OBJECT (range->adjustment));
744       range->adjustment = NULL;
745     }
746
747   (* GTK_OBJECT_CLASS (parent_class)->destroy) (object);
748 }
749
750 static void
751 gtk_range_draw (GtkWidget    *widget,
752                 GdkRectangle *area)
753 {
754   GtkRange *range;
755
756   g_return_if_fail (widget != NULL);
757   g_return_if_fail (GTK_IS_RANGE (widget));
758   g_return_if_fail (area != NULL);
759
760   if (GTK_WIDGET_DRAWABLE (widget))
761     {
762       range = GTK_RANGE (widget);
763
764       gtk_range_draw_background (range);
765       gtk_range_draw_trough (range);
766       gtk_range_draw_slider (range);
767       gtk_range_draw_step_forw (range);
768       gtk_range_draw_step_back (range);
769     }
770 }
771
772 static void
773 gtk_range_draw_focus (GtkWidget *widget)
774 {
775   g_return_if_fail (widget != NULL);
776   g_return_if_fail (GTK_IS_RANGE (widget));
777
778   if (GTK_WIDGET_DRAWABLE (widget))
779     gtk_range_draw_trough (GTK_RANGE (widget));
780 }
781
782 static void
783 gtk_range_unrealize (GtkWidget *widget)
784 {
785   GtkRange *range;
786
787   g_return_if_fail (widget != NULL);
788   g_return_if_fail (GTK_IS_RANGE (widget));
789
790   range = GTK_RANGE (widget);
791
792   if (range->slider)
793     {
794       gdk_window_set_user_data (range->slider, NULL);
795       gdk_window_destroy (range->slider);
796       range->slider = NULL;
797     }
798   if (range->trough)
799     {
800       gdk_window_set_user_data (range->trough, NULL);
801       gdk_window_destroy (range->trough);
802       range->trough = NULL;
803     }
804   if (range->step_forw)
805     {
806       gdk_window_set_user_data (range->step_forw, NULL);
807       gdk_window_destroy (range->step_forw);
808       range->step_forw = NULL;
809     }
810   if (range->step_back)
811     {
812       gdk_window_set_user_data (range->step_back, NULL);
813       gdk_window_destroy (range->step_back);
814       range->step_back = NULL;
815     }
816
817   if (GTK_WIDGET_CLASS (parent_class)->unrealize)
818     (* GTK_WIDGET_CLASS (parent_class)->unrealize) (widget);
819 }
820
821 static gint
822 gtk_range_expose (GtkWidget      *widget,
823                   GdkEventExpose *event)
824 {
825   GtkRange *range;
826
827   g_return_val_if_fail (widget != NULL, FALSE);
828   g_return_val_if_fail (GTK_IS_RANGE (widget), FALSE);
829   g_return_val_if_fail (event != NULL, FALSE);
830
831   range = GTK_RANGE (widget);
832
833   /* We should really pass another argument - 
834    *the redrawn area - to all the drawing functions)
835    */
836   if (event->window == range->trough)
837     {
838       gtk_range_draw_trough (range);
839     }
840   else if (event->window == widget->window)
841     {
842       gtk_range_draw_background (range); 
843     }
844   else if (event->window == range->slider)
845     {
846       gtk_range_draw_slider (range);
847     }
848   else if (event->window == range->step_forw)
849     {
850       gtk_range_draw_step_forw (range);
851     }
852   else if (event->window == range->step_back)
853     {
854       gtk_range_draw_step_back (range);
855     }
856   return FALSE;
857 }
858
859 static gint
860 gtk_range_button_press (GtkWidget      *widget,
861                         GdkEventButton *event)
862 {
863   GtkRange *range;
864   gint trough_part;
865   gfloat jump_perc;
866
867   g_return_val_if_fail (GTK_IS_RANGE (widget), FALSE);
868   g_return_val_if_fail (event != NULL, FALSE);
869
870   if (!GTK_WIDGET_HAS_FOCUS (widget))
871     gtk_widget_grab_focus (widget);
872
873   jump_perc = -1;
874   range = GTK_RANGE (widget);
875   if (range->button == 0)
876     {
877       gtk_grab_add (widget);
878
879       range->button = event->button;
880       range->x_click_point = event->x;
881       range->y_click_point = event->y;
882
883       if (event->window == range->trough)
884         {
885           range->click_child = RANGE_CLASS (range)->trough;
886           
887           if (range->button == 2)
888             trough_part = gtk_range_trough_click (range, event->x, event->y, &jump_perc);
889           else
890             trough_part = gtk_range_trough_click (range, event->x, event->y, NULL);
891           
892           range->scroll_type = GTK_SCROLL_NONE;
893           if (trough_part == GTK_TROUGH_START)
894             range->scroll_type = GTK_SCROLL_PAGE_BACKWARD;
895           else if (trough_part == GTK_TROUGH_END)
896             range->scroll_type = GTK_SCROLL_PAGE_FORWARD;
897           else if (trough_part == GTK_TROUGH_JUMP &&
898                    jump_perc >= 0 && jump_perc <= 1)
899             range->scroll_type = GTK_SCROLL_JUMP;
900           
901           if (range->scroll_type != GTK_SCROLL_NONE)
902             {
903               gtk_range_scroll (range, jump_perc);
904               gtk_range_add_timer (range);
905             }
906         }
907       else if (event->window == range->slider)
908         {
909           range->click_child = RANGE_CLASS (range)->slider;
910           range->scroll_type = GTK_SCROLL_NONE;
911         }
912       else if (event->window == range->step_forw)
913         {
914           range->click_child = RANGE_CLASS (range)->step_forw;
915           range->scroll_type = GTK_SCROLL_STEP_FORWARD;
916
917           gtk_range_scroll (range, -1);
918           gtk_range_add_timer (range);
919           gtk_range_draw_step_forw (range);
920         }
921       else if (event->window == range->step_back)
922         {
923           range->click_child = RANGE_CLASS (range)->step_back;
924           range->scroll_type = GTK_SCROLL_STEP_BACKWARD;
925
926           gtk_range_scroll (range, -1);
927           gtk_range_add_timer (range);
928           gtk_range_draw_step_back (range);
929         }
930     }
931
932   return FALSE;
933 }
934
935 static gint
936 gtk_range_button_release (GtkWidget      *widget,
937                           GdkEventButton *event)
938 {
939   GtkRange *range;
940
941   g_return_val_if_fail (GTK_IS_RANGE (widget), FALSE);
942   g_return_val_if_fail (event != NULL, FALSE);
943
944   range = GTK_RANGE (widget);
945
946   if (range->button == event->button)
947     {
948       gtk_grab_remove (widget);
949
950       range->button = 0;
951       range->x_click_point = -1;
952       range->y_click_point = -1;
953
954       if (range->click_child == RANGE_CLASS (range)->slider)
955         {
956           if (range->policy == GTK_UPDATE_DELAYED)
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       else if ((range->click_child == RANGE_CLASS (range)->trough) ||
964                (range->click_child == RANGE_CLASS (range)->step_forw) ||
965                (range->click_child == RANGE_CLASS (range)->step_back))
966         {
967           gtk_range_remove_timer (range);
968
969           if ((range->policy != GTK_UPDATE_CONTINUOUS) &&
970               (range->old_value != range->adjustment->value))
971             gtk_signal_emit_by_name (GTK_OBJECT (range->adjustment), "value_changed");
972
973           if (range->click_child == RANGE_CLASS (range)->step_forw)
974             {
975               range->click_child = 0;
976               gtk_range_draw_step_forw (range);
977             }
978           else if (range->click_child == RANGE_CLASS (range)->step_back)
979             {
980               range->click_child = 0;
981               gtk_range_draw_step_back (range);
982             }
983         }
984
985       range->click_child = 0;
986     }
987
988   return FALSE;
989 }
990
991 static gint
992 gtk_range_scroll_event (GtkWidget      *widget,
993                         GdkEventScroll *event)
994 {
995   GtkRange *range;
996
997   g_return_val_if_fail (GTK_IS_RANGE (widget), FALSE);
998   g_return_val_if_fail (event != NULL, FALSE);
999
1000   range = GTK_RANGE (widget);
1001
1002   if (GTK_WIDGET_REALIZED (range))
1003     {
1004       GtkAdjustment *adj = GTK_RANGE (range)->adjustment;
1005       gfloat new_value = adj->value + ((event->direction == GDK_SCROLL_UP) ? 
1006                                        -adj->page_increment / 2: 
1007                                        adj->page_increment / 2);
1008       new_value = CLAMP (new_value, adj->lower, adj->upper - adj->page_size);
1009       gtk_adjustment_set_value (adj, new_value);
1010     }
1011
1012   return TRUE;
1013 }
1014
1015 static gint
1016 gtk_range_motion_notify (GtkWidget      *widget,
1017                          GdkEventMotion *event)
1018 {
1019   GtkRange *range;
1020
1021   g_return_val_if_fail (GTK_IS_RANGE (widget), FALSE);
1022   g_return_val_if_fail (event != NULL, FALSE);
1023
1024   range = GTK_RANGE (widget);
1025
1026   if (range->click_child == RANGE_CLASS (range)->slider)
1027     {
1028       GdkModifierType mods;
1029       gint x, y, mask, x2, y2;
1030
1031       gdk_window_get_pointer (range->trough, &x, &y, &mods);
1032       gdk_window_get_position (range->slider, &x2, &y2);
1033
1034       x -= x2;
1035       y -= y2;
1036
1037       switch (range->button)
1038         {
1039         case 1:
1040           mask = GDK_BUTTON1_MASK;
1041           break;
1042         case 2:
1043           mask = GDK_BUTTON2_MASK;
1044           break;
1045         case 3:
1046           mask = GDK_BUTTON3_MASK;
1047           break;
1048         default:
1049           mask = 0;
1050           break;
1051         }
1052
1053       if (mods & mask)
1054         {
1055           if (RANGE_CLASS (range)->motion)
1056             (* RANGE_CLASS (range)->motion) (range, x - range->x_click_point, y - range->y_click_point);
1057         }
1058     }
1059
1060   return FALSE;
1061 }
1062
1063 static gint
1064 gtk_range_key_press (GtkWidget   *widget,
1065                      GdkEventKey *event)
1066 {
1067   GtkRange *range;
1068   gint return_val;
1069   GtkScrollType scroll = GTK_SCROLL_NONE;
1070   GtkTroughType pos = GTK_TROUGH_NONE;
1071
1072   g_return_val_if_fail (GTK_IS_RANGE (widget), FALSE);
1073   g_return_val_if_fail (event != NULL, FALSE);
1074
1075   range = GTK_RANGE (widget);
1076   return_val = FALSE;
1077
1078   if (RANGE_CLASS (range)->trough_keys)
1079     return_val = (* RANGE_CLASS (range)->trough_keys) (range, event, &scroll, &pos);
1080
1081   if (return_val)
1082     {
1083       if (scroll != GTK_SCROLL_NONE)
1084         {
1085           range->scroll_type = scroll;
1086           gtk_range_scroll (range, -1);
1087           if (range->old_value != range->adjustment->value)
1088             {
1089               gtk_signal_emit_by_name (GTK_OBJECT (range->adjustment), "value_changed");
1090               switch (range->scroll_type)
1091                 {
1092                 case GTK_SCROLL_STEP_BACKWARD:
1093                   gtk_range_draw_step_back (range);
1094                   break;
1095                 case GTK_SCROLL_STEP_FORWARD:
1096                   gtk_range_draw_step_forw (range);
1097                   break;
1098                 }
1099             }
1100         }
1101       if (pos != GTK_TROUGH_NONE)
1102         {
1103           if (pos == GTK_TROUGH_START)
1104             range->adjustment->value = range->adjustment->lower;
1105           else if (pos == GTK_TROUGH_END)
1106             range->adjustment->value =
1107               range->adjustment->upper - range->adjustment->page_size;
1108
1109           if (range->old_value != range->adjustment->value)
1110             {
1111               gtk_signal_emit_by_name (GTK_OBJECT (range->adjustment),
1112                                        "value_changed");
1113
1114               gtk_range_slider_update (range);
1115               gtk_range_clear_background (range);
1116             }
1117         }
1118     }
1119   return return_val;
1120 }
1121
1122 static gint
1123 gtk_range_enter_notify (GtkWidget        *widget,
1124                         GdkEventCrossing *event)
1125 {
1126   GtkRange *range;
1127
1128   g_return_val_if_fail (GTK_IS_RANGE (widget), FALSE);
1129   g_return_val_if_fail (event != NULL, FALSE);
1130
1131   range = GTK_RANGE (widget);
1132
1133   if (event->window == range->trough)
1134     {
1135       range->in_child = RANGE_CLASS (range)->trough;
1136     }
1137   else if (event->window == range->slider)
1138     {
1139       range->in_child = RANGE_CLASS (range)->slider;
1140
1141       if ((range->click_child == 0) ||
1142           (range->click_child == RANGE_CLASS (range)->trough))
1143         gtk_range_draw_slider (range);
1144     }
1145   else if (event->window == range->step_forw)
1146     {
1147       range->in_child = RANGE_CLASS (range)->step_forw;
1148
1149       if ((range->click_child == 0) ||
1150           (range->click_child == RANGE_CLASS (range)->trough))
1151         gtk_range_draw_step_forw (range);
1152     }
1153   else if (event->window == range->step_back)
1154     {
1155       range->in_child = RANGE_CLASS (range)->step_back;
1156
1157       if ((range->click_child == 0) ||
1158           (range->click_child == RANGE_CLASS (range)->trough))
1159         gtk_range_draw_step_back (range);
1160     }
1161
1162   return FALSE;
1163 }
1164
1165 static gint
1166 gtk_range_leave_notify (GtkWidget        *widget,
1167                         GdkEventCrossing *event)
1168 {
1169   GtkRange *range;
1170
1171   g_return_val_if_fail (GTK_IS_RANGE (widget), FALSE);
1172   g_return_val_if_fail (event != NULL, FALSE);
1173
1174   range = GTK_RANGE (widget);
1175
1176   range->in_child = 0;
1177
1178   if (event->window == range->trough)
1179     {
1180     }
1181   else if (event->window == range->slider)
1182     {
1183       if ((range->click_child == 0) ||
1184           (range->click_child == RANGE_CLASS (range)->trough))
1185         gtk_range_draw_slider (range);
1186     }
1187   else if (event->window == range->step_forw)
1188     {
1189       if ((range->click_child == 0) ||
1190           (range->click_child == RANGE_CLASS (range)->trough))
1191         gtk_range_draw_step_forw (range);
1192     }
1193   else if (event->window == range->step_back)
1194     {
1195       if ((range->click_child == 0) ||
1196           (range->click_child == RANGE_CLASS (range)->trough))
1197         gtk_range_draw_step_back (range);
1198     }
1199
1200   return FALSE;
1201 }
1202
1203 static gint
1204 gtk_range_focus_in (GtkWidget     *widget,
1205                     GdkEventFocus *event)
1206 {
1207   g_return_val_if_fail (GTK_IS_RANGE (widget), FALSE);
1208   g_return_val_if_fail (event != NULL, FALSE);
1209
1210   GTK_WIDGET_SET_FLAGS (widget, GTK_HAS_FOCUS);
1211   gtk_widget_draw_focus (widget);
1212
1213   return FALSE;
1214 }
1215
1216 static gint
1217 gtk_range_focus_out (GtkWidget     *widget,
1218                      GdkEventFocus *event)
1219 {
1220   g_return_val_if_fail (GTK_IS_RANGE (widget), FALSE);
1221   g_return_val_if_fail (event != NULL, FALSE);
1222
1223   GTK_WIDGET_UNSET_FLAGS (widget, GTK_HAS_FOCUS);
1224   gtk_widget_draw_focus (widget);
1225
1226   return FALSE;
1227 }
1228
1229 static void
1230 gtk_real_range_draw_trough (GtkRange *range)
1231 {
1232   g_return_if_fail (GTK_IS_RANGE (range));
1233
1234   if (range->trough)
1235      {
1236         gtk_paint_box (GTK_WIDGET (range)->style, range->trough,
1237                        GTK_STATE_ACTIVE, GTK_SHADOW_IN,
1238                        NULL, GTK_WIDGET(range), "trough",
1239                        0, 0, -1, -1);
1240         if (GTK_WIDGET_HAS_FOCUS (range))
1241           gtk_paint_focus (GTK_WIDGET (range)->style,
1242                           range->trough,
1243                            NULL, GTK_WIDGET(range), "trough",
1244                           0, 0, -1, -1);
1245     }
1246 }
1247
1248 static void
1249 gtk_real_range_draw_slider (GtkRange *range)
1250 {
1251   GtkStateType state_type;
1252    
1253   g_return_if_fail (GTK_IS_RANGE (range));
1254    
1255   if (range->slider)
1256     {
1257       if ((range->in_child == RANGE_CLASS (range)->slider) ||
1258           (range->click_child == RANGE_CLASS (range)->slider))
1259         state_type = GTK_STATE_PRELIGHT;
1260       else
1261         state_type = GTK_STATE_NORMAL;
1262       gtk_paint_box (GTK_WIDGET (range)->style, range->slider,
1263                      state_type, GTK_SHADOW_OUT,
1264                      NULL, GTK_WIDGET (range), "slider",
1265                      0, 0, -1, -1);
1266     }
1267 }
1268
1269 static gint
1270 gtk_real_range_timer (GtkRange *range)
1271 {
1272   gint return_val;
1273
1274   GDK_THREADS_ENTER ();
1275
1276   return_val = TRUE;
1277   if (range->click_child == RANGE_CLASS (range)->slider)
1278     {
1279       if (range->policy == GTK_UPDATE_DELAYED)
1280         gtk_signal_emit_by_name (GTK_OBJECT (range->adjustment), "value_changed");
1281       return_val = FALSE;
1282     }
1283   else
1284     {
1285       GdkModifierType mods, mask;
1286
1287       if (!range->timer)
1288         {
1289           return_val = FALSE;
1290           if (range->need_timer)
1291             range->timer = gtk_timeout_add (SCROLL_TIMER_LENGTH,
1292                                             (GtkFunction) RANGE_CLASS (range)->timer,
1293                                             (gpointer) range);
1294           else
1295             {
1296               GDK_THREADS_LEAVE ();
1297               return FALSE;
1298             }
1299           range->need_timer = FALSE;
1300         }
1301
1302       switch (range->button)
1303         {
1304         case 1:
1305           mask = GDK_BUTTON1_MASK;
1306           break;
1307         case 2:
1308           mask = GDK_BUTTON2_MASK;
1309           break;
1310         case 3:
1311           mask = GDK_BUTTON3_MASK;
1312           break;
1313         default:
1314           mask = 0;
1315           break;
1316         }
1317
1318       gdk_window_get_pointer (range->slider, NULL, NULL, &mods);
1319
1320       if (mods & mask)
1321         return_val = gtk_range_scroll (range, -1);
1322     }
1323
1324   GDK_THREADS_LEAVE ();
1325
1326   return return_val;
1327 }
1328
1329 static gint
1330 gtk_range_scroll (GtkRange *range,
1331                   gfloat    jump_perc)
1332 {
1333   gfloat new_value;
1334   gint return_val;
1335
1336   g_return_val_if_fail (GTK_IS_RANGE (range), FALSE);
1337
1338   new_value = range->adjustment->value;
1339   return_val = TRUE;
1340
1341   switch (range->scroll_type)
1342     {
1343     case GTK_SCROLL_NONE:
1344       break;
1345       
1346     case GTK_SCROLL_JUMP:
1347       if (jump_perc >= 0 && jump_perc <= 1)
1348         {
1349           new_value = (range->adjustment->lower +
1350                        (range->adjustment->upper - range->adjustment->page_size -
1351                         range->adjustment->lower) * jump_perc);
1352         }
1353       break;
1354       
1355     case GTK_SCROLL_STEP_BACKWARD:
1356       new_value -= range->adjustment->step_increment;
1357       if (new_value <= range->adjustment->lower)
1358         {
1359           new_value = range->adjustment->lower;
1360           return_val = FALSE;
1361           range->timer = 0;
1362         }
1363       break;
1364
1365     case GTK_SCROLL_STEP_FORWARD:
1366       new_value += range->adjustment->step_increment;
1367       if (new_value >= (range->adjustment->upper - range->adjustment->page_size))
1368         {
1369           new_value = range->adjustment->upper - range->adjustment->page_size;
1370           return_val = FALSE;
1371           range->timer = 0;
1372         }
1373       break;
1374
1375     case GTK_SCROLL_PAGE_BACKWARD:
1376       new_value -= range->adjustment->page_increment;
1377       if (new_value <= range->adjustment->lower)
1378         {
1379           new_value = range->adjustment->lower;
1380           return_val = FALSE;
1381           range->timer = 0;
1382         }
1383       break;
1384
1385     case GTK_SCROLL_PAGE_FORWARD:
1386       new_value += range->adjustment->page_increment;
1387       if (new_value >= (range->adjustment->upper - range->adjustment->page_size))
1388         {
1389           new_value = range->adjustment->upper - range->adjustment->page_size;
1390           return_val = FALSE;
1391           range->timer = 0;
1392         }
1393       break;
1394     }
1395
1396   if (new_value != range->adjustment->value)
1397     {
1398       range->adjustment->value = new_value;
1399
1400       if ((range->policy == GTK_UPDATE_CONTINUOUS) ||
1401           (!return_val && (range->policy == GTK_UPDATE_DELAYED)))
1402         {
1403           gtk_signal_emit_by_name (GTK_OBJECT (range->adjustment), "value_changed");
1404         }
1405       else
1406         {
1407           gtk_range_slider_update (range);
1408           gtk_range_clear_background (range);
1409         }
1410     }
1411
1412   return return_val;
1413 }
1414
1415
1416 static void
1417 gtk_range_add_timer (GtkRange *range)
1418 {
1419   g_return_if_fail (GTK_IS_RANGE (range));
1420
1421   if (!range->timer)
1422     {
1423       range->need_timer = TRUE;
1424       range->timer = gtk_timeout_add (SCROLL_INITIAL_DELAY,
1425                                       (GtkFunction) RANGE_CLASS (range)->timer,
1426                                       (gpointer) range);
1427     }
1428 }
1429
1430 static void
1431 gtk_range_remove_timer (GtkRange *range)
1432 {
1433   g_return_if_fail (GTK_IS_RANGE (range));
1434
1435   if (range->timer)
1436     {
1437       gtk_timeout_remove (range->timer);
1438       range->timer = 0;
1439     }
1440   range->need_timer = FALSE;
1441 }
1442
1443 static void
1444 gtk_range_adjustment_changed (GtkAdjustment *adjustment,
1445                               gpointer       data)
1446 {
1447   GtkRange *range;
1448
1449   g_return_if_fail (adjustment != NULL);
1450   g_return_if_fail (data != NULL);
1451
1452   range = GTK_RANGE (data);
1453
1454   if (((range->old_lower != adjustment->lower) ||
1455        (range->old_upper != adjustment->upper) ||
1456        (range->old_page_size != adjustment->page_size)) &&
1457       (range->old_value == adjustment->value))
1458     {
1459       if ((adjustment->lower == adjustment->upper) ||
1460           (range->old_lower == (range->old_upper - range->old_page_size)))
1461         {
1462           adjustment->value = adjustment->lower;
1463           gtk_signal_emit_by_name (GTK_OBJECT (adjustment), "value_changed");
1464         }
1465     }
1466
1467   if ((range->old_value != adjustment->value) ||
1468       (range->old_lower != adjustment->lower) ||
1469       (range->old_upper != adjustment->upper) ||
1470       (range->old_page_size != adjustment->page_size))
1471     {
1472       gtk_range_slider_update (range);
1473       gtk_range_clear_background (range);
1474
1475       range->old_value = adjustment->value;
1476       range->old_lower = adjustment->lower;
1477       range->old_upper = adjustment->upper;
1478       range->old_page_size = adjustment->page_size;
1479     }
1480 }
1481
1482 static void
1483 gtk_range_adjustment_value_changed (GtkAdjustment *adjustment,
1484                                     gpointer       data)
1485 {
1486   GtkRange *range;
1487
1488   g_return_if_fail (adjustment != NULL);
1489   g_return_if_fail (data != NULL);
1490
1491   range = GTK_RANGE (data);
1492
1493   if (range->old_value != adjustment->value)
1494     {
1495       gtk_range_slider_update (range);
1496       gtk_range_clear_background (range);
1497
1498       range->old_value = adjustment->value;
1499     }
1500 }
1501
1502
1503 static void
1504 gtk_range_trough_hdims (GtkRange *range,
1505                         gint     *left,
1506                         gint     *right)
1507 {
1508   gint trough_width;
1509   gint slider_length;
1510   gint tmp_width;
1511   gint tleft;
1512   gint tright;
1513
1514   g_return_if_fail (range != NULL);
1515
1516   gdk_window_get_size (range->trough, &trough_width, NULL);
1517   gdk_window_get_size (range->slider, &slider_length, NULL);
1518
1519   tleft = GTK_WIDGET (range)->style->xthickness;
1520   tright = trough_width - slider_length - GTK_WIDGET (range)->style->xthickness;
1521
1522   if (range->step_back)
1523     {
1524       gdk_window_get_size (range->step_back, &tmp_width, NULL);
1525       tleft += (tmp_width + RANGE_CLASS (range)->stepper_slider_spacing);
1526     }
1527
1528   if (range->step_forw)
1529     {
1530       gdk_window_get_size (range->step_forw, &tmp_width, NULL);
1531       tright -= (tmp_width + RANGE_CLASS (range)->stepper_slider_spacing);
1532     }
1533
1534   if (left)
1535     *left = tleft;
1536   if (right)
1537     *right = tright;
1538 }
1539
1540 static void
1541 gtk_range_trough_vdims (GtkRange *range,
1542                         gint     *top,
1543                         gint     *bottom)
1544 {
1545   gint trough_height;
1546   gint slider_length;
1547   gint tmp_height;
1548   gint ttop;
1549   gint tbottom;
1550
1551   g_return_if_fail (range != NULL);
1552
1553   gdk_window_get_size (range->trough, NULL, &trough_height);
1554   gdk_window_get_size (range->slider, NULL, &slider_length);
1555
1556   ttop = GTK_WIDGET (range)->style->ythickness;
1557   tbottom = trough_height - slider_length - GTK_WIDGET (range)->style->ythickness;
1558
1559   if (range->step_back)
1560     {
1561       gdk_window_get_size (range->step_back, NULL, &tmp_height);
1562       ttop += (tmp_height + RANGE_CLASS (range)->stepper_slider_spacing);
1563     }
1564
1565   if (range->step_forw)
1566     {
1567       gdk_window_get_size (range->step_forw, NULL, &tmp_height);
1568       tbottom -= (tmp_height + RANGE_CLASS (range)->stepper_slider_spacing);
1569     }
1570
1571   if (top)
1572     *top = ttop;
1573   if (bottom)
1574     *bottom = tbottom;
1575 }
1576
1577 static void
1578 gtk_range_style_set (GtkWidget *widget,
1579                       GtkStyle  *previous_style)
1580 {
1581   GtkRange *range;
1582
1583   g_return_if_fail (widget != NULL);
1584   g_return_if_fail (GTK_IS_RANGE (widget));
1585
1586   range = GTK_RANGE (widget);
1587
1588   if (GTK_WIDGET_REALIZED (widget))
1589     {
1590       if (range->trough)
1591         gtk_style_set_background (widget->style, range->trough, GTK_STATE_ACTIVE);
1592
1593       if (range->slider)
1594         gtk_style_set_background (widget->style, range->slider, GTK_STATE_NORMAL);
1595       
1596       /* The backgrounds of the step_forw and step_back never actually
1597        * get drawn in draw calls, so we call gdk_window_clear() here
1598        * so they get the correct colors. This is a hack. OWT.
1599        */
1600
1601       if (range->step_forw)
1602         {
1603           gtk_style_set_background (widget->style, range->step_forw, GTK_STATE_ACTIVE);
1604           gdk_window_clear (range->step_forw);
1605         }
1606
1607       if (range->step_back)
1608         {
1609           gtk_style_set_background (widget->style, range->step_back, GTK_STATE_ACTIVE);
1610           gdk_window_clear (range->step_back);
1611         }
1612     }
1613 }