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