source: trunk/third/gtk/gtk/gtkrange.c @ 15781

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