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