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