]> Pileus Git - ~andy/gtk/blob - gtk/gtkspinbutton.c
call the base class init fucntions from all parent types upon class
[~andy/gtk] / gtk / gtkspinbutton.c
1 /* GTK - The GIMP Toolkit
2  * Copyright (C) 1995-1997 Peter Mattis, Spencer Kimball and Josh MacDonald
3  *
4  * GtkSpinButton widget for GTK+
5  * Copyright (C) 1998 Lars Hamann and Stefan Jeske
6  *
7  * This library is free software; you can redistribute it and/or
8  * modify it under the terms of the GNU Library General Public
9  * License as published by the Free Software Foundation; either
10  * version 2 of the License, or (at your option) any later version.
11  *
12  * This library is distributed in the hope that it will be useful,
13  * but WITHOUT ANY WARRANTY; without even the implied warranty of
14  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
15  * Library General Public License for more details.
16  *
17  * You should have received a copy of the GNU Library General Public
18  * License along with this library; if not, write to the
19  * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
20  * Boston, MA 02111-1307, USA.
21  */
22
23 #include <stdio.h>
24 #include <stdlib.h>
25 #include <math.h>
26 #include <string.h>
27 #include <locale.h>
28 #include "gdk/gdkkeysyms.h"
29 #include "gtkspinbutton.h"
30 #include "gtkmain.h"
31 #include "gtksignal.h"
32
33
34 #define MIN_SPIN_BUTTON_WIDTH              30
35 #define ARROW_SIZE                         11
36 #define SPIN_BUTTON_INITIAL_TIMER_DELAY    200
37 #define SPIN_BUTTON_TIMER_DELAY            20
38 #define MAX_TEXT_LENGTH                    256
39 #define MAX_TIMER_CALLS                    5
40 #define EPSILON                            1e-5
41
42
43 static void gtk_spin_button_class_init     (GtkSpinButtonClass *klass);
44 static void gtk_spin_button_init           (GtkSpinButton      *spin_button);
45 static void gtk_spin_button_finalize       (GtkObject          *object);
46 static void gtk_spin_button_map            (GtkWidget          *widget);
47 static void gtk_spin_button_unmap          (GtkWidget          *widget);
48 static void gtk_spin_button_realize        (GtkWidget          *widget);
49 static void gtk_spin_button_unrealize      (GtkWidget          *widget);
50 static void gtk_spin_button_size_request   (GtkWidget          *widget,
51                                             GtkRequisition     *requisition);
52 static void gtk_spin_button_size_allocate  (GtkWidget          *widget,
53                                             GtkAllocation      *allocation);
54 static void gtk_spin_button_paint          (GtkWidget          *widget,
55                                             GdkRectangle       *area);
56 static void gtk_spin_button_draw           (GtkWidget          *widget,
57                                             GdkRectangle       *area);
58 static gint gtk_spin_button_expose         (GtkWidget          *widget,
59                                             GdkEventExpose     *event);
60 static gint gtk_spin_button_button_press   (GtkWidget          *widget,
61                                             GdkEventButton     *event);
62 static gint gtk_spin_button_button_release (GtkWidget          *widget,
63                                             GdkEventButton     *event);
64 static gint gtk_spin_button_motion_notify  (GtkWidget          *widget,
65                                             GdkEventMotion     *event);
66 static gint gtk_spin_button_enter_notify   (GtkWidget          *widget,
67                                             GdkEventCrossing   *event);
68 static gint gtk_spin_button_leave_notify   (GtkWidget          *widget,
69                                             GdkEventCrossing   *event);
70 static gint gtk_spin_button_focus_out      (GtkWidget          *widget,
71                                             GdkEventFocus      *event);
72 static void gtk_spin_button_draw_arrow     (GtkSpinButton      *spin_button, 
73                                             guint               arrow);
74 static gint gtk_spin_button_timer          (GtkSpinButton      *spin_button);
75 static void gtk_spin_button_value_changed  (GtkAdjustment      *adjustment,
76                                             GtkSpinButton      *spin_button); 
77 static gint gtk_spin_button_key_press      (GtkWidget          *widget,
78                                             GdkEventKey        *event);
79 static gint gtk_spin_button_key_release    (GtkWidget          *widget,
80                                             GdkEventKey        *event);
81 static void gtk_spin_button_update         (GtkSpinButton      *spin_button);
82 static void gtk_spin_button_activate       (GtkEditable        *editable);
83 static void gtk_spin_button_snap           (GtkSpinButton      *spin_button,
84                                             gfloat              val);
85 static void gtk_spin_button_insert_text    (GtkEditable        *editable,
86                                             const gchar        *new_text,
87                                             gint                new_text_length,
88                                             gint               *position);
89 static void gtk_spin_button_real_spin      (GtkSpinButton      *spin_button,
90                                             gfloat              step);
91
92
93 static GtkEntryClass *parent_class = NULL;
94
95
96 guint
97 gtk_spin_button_get_type (void)
98 {
99   static guint spin_button_type = 0;
100
101   if (!spin_button_type)
102     {
103       GtkTypeInfo spin_button_info =
104       {
105         "GtkSpinButton",
106         sizeof (GtkSpinButton),
107         sizeof (GtkSpinButtonClass),
108         (GtkClassInitFunc) gtk_spin_button_class_init,
109         (GtkObjectInitFunc) gtk_spin_button_init,
110         /* reversed_1 */ NULL,
111         /* reversed_2 */ NULL,
112         (GtkClassInitFunc) NULL,
113       };
114
115       spin_button_type = gtk_type_unique (gtk_entry_get_type (), 
116                                           &spin_button_info);
117     }
118   return spin_button_type;
119 }
120
121 static void
122 gtk_spin_button_class_init (GtkSpinButtonClass *class)
123 {
124   GtkObjectClass   *object_class;
125   GtkWidgetClass   *widget_class;
126   GtkEditableClass *editable_class;
127
128   object_class   = (GtkObjectClass*)   class;
129   widget_class   = (GtkWidgetClass*)   class;
130   editable_class = (GtkEditableClass*) class; 
131
132   parent_class = gtk_type_class (gtk_entry_get_type ());
133
134   object_class->finalize = gtk_spin_button_finalize;
135
136   widget_class->map = gtk_spin_button_map;
137   widget_class->unmap = gtk_spin_button_unmap;
138   widget_class->realize = gtk_spin_button_realize;
139   widget_class->unrealize = gtk_spin_button_unrealize;
140   widget_class->size_request = gtk_spin_button_size_request;
141   widget_class->size_allocate = gtk_spin_button_size_allocate;
142   widget_class->draw = gtk_spin_button_draw;
143   widget_class->expose_event = gtk_spin_button_expose;
144   widget_class->button_press_event = gtk_spin_button_button_press;
145   widget_class->button_release_event = gtk_spin_button_button_release;
146   widget_class->motion_notify_event = gtk_spin_button_motion_notify;
147   widget_class->key_press_event = gtk_spin_button_key_press;
148   widget_class->key_release_event = gtk_spin_button_key_release;
149   widget_class->enter_notify_event = gtk_spin_button_enter_notify;
150   widget_class->leave_notify_event = gtk_spin_button_leave_notify;
151   widget_class->focus_out_event = gtk_spin_button_focus_out;
152
153   editable_class->insert_text = gtk_spin_button_insert_text;
154   editable_class->activate = gtk_spin_button_activate;
155 }
156
157 static void
158 gtk_spin_button_init (GtkSpinButton *spin_button)
159 {
160   spin_button->adjustment = NULL;
161   spin_button->panel = NULL;
162   spin_button->shadow_type = GTK_SHADOW_NONE;
163   spin_button->timer = 0;
164   spin_button->ev_time = 0;
165   spin_button->climb_rate = 0.0;
166   spin_button->timer_step = 0.0;
167   spin_button->update_policy = GTK_UPDATE_ALWAYS;
168   spin_button->in_child = 2;
169   spin_button->click_child = 2;
170   spin_button->button = 0;
171   spin_button->need_timer = FALSE;
172   spin_button->timer_calls = 0;
173   spin_button->digits = 0;
174   spin_button->numeric = FALSE;
175   spin_button->wrap = FALSE;
176   spin_button->snap_to_ticks = FALSE;
177 }
178
179 static void
180 gtk_spin_button_finalize (GtkObject *object)
181 {
182   g_return_if_fail (object != NULL);
183   g_return_if_fail (GTK_IS_SPIN_BUTTON (object));
184
185   gtk_object_unref (GTK_OBJECT (GTK_SPIN_BUTTON (object)->adjustment));
186   
187   GTK_OBJECT_CLASS (parent_class)->finalize (object);
188 }
189
190 static void
191 gtk_spin_button_map (GtkWidget *widget)
192 {
193   g_return_if_fail (widget != NULL);
194   g_return_if_fail (GTK_IS_SPIN_BUTTON (widget));
195
196   if (GTK_WIDGET_REALIZED (widget) && !GTK_WIDGET_MAPPED (widget))
197     {
198       GTK_WIDGET_CLASS (parent_class)->map (widget);
199       gdk_window_show (GTK_SPIN_BUTTON (widget)->panel);
200     }
201 }
202
203 static void
204 gtk_spin_button_unmap (GtkWidget *widget)
205 {
206   g_return_if_fail (widget != NULL);
207   g_return_if_fail (GTK_IS_SPIN_BUTTON (widget));
208
209   if (GTK_WIDGET_MAPPED (widget))
210     {
211       gdk_window_hide (GTK_SPIN_BUTTON (widget)->panel);
212       GTK_WIDGET_CLASS (parent_class)->unmap (widget);
213     }
214 }
215
216 static void
217 gtk_spin_button_realize (GtkWidget *widget)
218 {
219   GtkSpinButton *spin;
220   GdkWindowAttr attributes;
221   gint attributes_mask;
222   guint real_width;
223
224   g_return_if_fail (widget != NULL);
225   g_return_if_fail (GTK_IS_SPIN_BUTTON (widget));
226   
227   spin = GTK_SPIN_BUTTON (widget);
228
229   real_width = widget->allocation.width;
230   widget->allocation.width -= ARROW_SIZE + 2 * widget->style->klass->xthickness;
231   gtk_widget_set_events (widget, gtk_widget_get_events (widget) |
232                          GDK_KEY_RELEASE_MASK);
233   GTK_WIDGET_CLASS (parent_class)->realize (widget);
234
235   widget->allocation.width = real_width;
236   
237   attributes.window_type = GDK_WINDOW_CHILD;
238   attributes.wclass = GDK_INPUT_OUTPUT;
239   attributes.visual = gtk_widget_get_visual (widget);
240   attributes.colormap = gtk_widget_get_colormap (widget);
241   attributes.event_mask = gtk_widget_get_events (widget);
242   attributes.event_mask |= GDK_EXPOSURE_MASK | GDK_BUTTON_PRESS_MASK 
243     | GDK_BUTTON_RELEASE_MASK | GDK_LEAVE_NOTIFY_MASK | GDK_ENTER_NOTIFY_MASK 
244     | GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK;
245
246   attributes_mask = GDK_WA_X | GDK_WA_Y | GDK_WA_VISUAL | GDK_WA_COLORMAP;
247
248   attributes.x = (widget->allocation.x + widget->allocation.width - ARROW_SIZE -
249                   2 * widget->style->klass->xthickness);
250   attributes.y = widget->allocation.y + (widget->allocation.height -
251                                          widget->requisition.height) / 2;
252   attributes.width = ARROW_SIZE + 2 * widget->style->klass->xthickness;
253   attributes.height = widget->requisition.height;
254   
255   spin->panel = gdk_window_new (gtk_widget_get_parent_window (widget), 
256                                 &attributes, attributes_mask);
257   gdk_window_set_user_data (spin->panel, widget);
258
259   gtk_style_set_background (widget->style, spin->panel, GTK_STATE_NORMAL);
260 }
261
262 static void
263 gtk_spin_button_unrealize (GtkWidget *widget)
264 {
265   GtkSpinButton *spin;
266
267   g_return_if_fail (widget != NULL);
268   g_return_if_fail (GTK_IS_SPIN_BUTTON (widget));
269
270   spin = GTK_SPIN_BUTTON (widget);
271
272   GTK_WIDGET_CLASS (parent_class)->unrealize (widget);
273
274   if (spin->panel)
275     {
276       gdk_window_set_user_data (spin->panel, NULL);
277       gdk_window_destroy (spin->panel);
278       spin->panel = NULL;
279     }
280 }
281
282 static void
283 gtk_spin_button_size_request (GtkWidget      *widget,
284                               GtkRequisition *requisition)
285 {
286   g_return_if_fail (widget != NULL);
287   g_return_if_fail (requisition != NULL);
288   g_return_if_fail (GTK_IS_SPIN_BUTTON (widget));
289
290   GTK_WIDGET_CLASS (parent_class)->size_request (widget, requisition);
291   
292   requisition->width = MIN_SPIN_BUTTON_WIDTH + ARROW_SIZE 
293     + 2 * widget->style->klass->xthickness;
294 }
295
296 static void
297 gtk_spin_button_size_allocate (GtkWidget     *widget,
298                                GtkAllocation *allocation)
299 {
300   GtkAllocation child_allocation;
301
302   g_return_if_fail (widget != NULL);
303   g_return_if_fail (GTK_IS_SPIN_BUTTON (widget));
304   g_return_if_fail (allocation != NULL);
305
306   child_allocation = *allocation;
307   child_allocation.width -= ARROW_SIZE + 2 * widget->style->klass->xthickness;
308
309   GTK_WIDGET_CLASS (parent_class)->size_allocate (widget, &child_allocation);
310
311   widget->allocation = *allocation;
312
313   if (GTK_WIDGET_REALIZED (widget))
314     {
315       child_allocation.width = ARROW_SIZE + 2 * widget->style->klass->xthickness;
316       child_allocation.height = widget->requisition.height;  
317       child_allocation.x = (allocation->x + allocation->width - ARROW_SIZE - 
318                             2 * widget->style->klass->xthickness);
319       child_allocation.y = allocation->y + (allocation->height - widget->requisition.height) / 2;
320
321       gdk_window_move_resize (GTK_SPIN_BUTTON (widget)->panel, 
322                               child_allocation.x,
323                               child_allocation.y,
324                               child_allocation.width,
325                               child_allocation.height); 
326     }
327 }
328
329 static void
330 gtk_spin_button_paint (GtkWidget    *widget,
331                        GdkRectangle *area)
332 {
333   GtkSpinButton *spin;
334
335   g_return_if_fail (widget != NULL);
336   g_return_if_fail (GTK_IS_SPIN_BUTTON (widget));
337
338   spin = GTK_SPIN_BUTTON (widget);
339
340   if (GTK_WIDGET_DRAWABLE (widget))
341     {
342       if (spin->shadow_type != GTK_SHADOW_NONE)
343         gtk_draw_shadow (widget->style, spin->panel,
344                          GTK_STATE_NORMAL, spin->shadow_type,
345                          0, 0, 
346                          ARROW_SIZE + 2 * widget->style->klass->xthickness,
347                          widget->requisition.height); 
348       gtk_spin_button_draw_arrow (spin, GTK_ARROW_UP);
349       gtk_spin_button_draw_arrow (spin, GTK_ARROW_DOWN);
350
351       GTK_WIDGET_CLASS (parent_class)->draw (widget, area);
352     }
353 }
354
355 static void
356 gtk_spin_button_draw (GtkWidget    *widget,
357                       GdkRectangle *area)
358 {
359   g_return_if_fail (widget != NULL);
360   g_return_if_fail (GTK_IS_SPIN_BUTTON (widget));
361   g_return_if_fail (area != NULL);
362
363   if (GTK_WIDGET_DRAWABLE (widget))
364     gtk_spin_button_paint (widget, area);
365 }
366
367 static gint
368 gtk_spin_button_expose (GtkWidget      *widget,
369                         GdkEventExpose *event)
370 {
371   g_return_val_if_fail (widget != NULL, FALSE);
372   g_return_val_if_fail (GTK_IS_SPIN_BUTTON (widget), FALSE);
373   g_return_val_if_fail (event != NULL, FALSE);
374
375   if (GTK_WIDGET_DRAWABLE (widget))
376     gtk_spin_button_paint (widget, &event->area);
377
378   return FALSE;
379 }
380
381 static void
382 gtk_spin_button_draw_arrow (GtkSpinButton *spin_button, 
383                             guint          arrow)
384 {
385   GtkStateType state_type;
386   GtkShadowType shadow_type;
387   GtkWidget *widget;
388   gint x;
389   gint y;
390
391   g_return_if_fail (spin_button != NULL);
392   g_return_if_fail (GTK_IS_SPIN_BUTTON (spin_button));
393   
394   widget = GTK_WIDGET (spin_button);
395
396   if (GTK_WIDGET_DRAWABLE (spin_button))
397     {
398       if (spin_button->in_child == arrow)
399         {
400           if (spin_button->click_child == arrow)
401             state_type = GTK_STATE_ACTIVE;
402           else
403             state_type = GTK_STATE_PRELIGHT;
404         }
405       else
406         state_type = GTK_STATE_NORMAL;
407
408       if (spin_button->click_child == arrow)
409         shadow_type = GTK_SHADOW_IN;
410       else
411         shadow_type = GTK_SHADOW_OUT;
412
413       if (arrow == GTK_ARROW_UP)
414         {
415           if (spin_button->shadow_type != GTK_SHADOW_NONE)
416             {
417               x = widget->style->klass->xthickness;
418               y = widget->style->klass->ythickness;
419             }
420           else
421             {
422               x = widget->style->klass->xthickness - 1;
423               y = widget->style->klass->ythickness - 1;
424             }
425           gtk_draw_arrow (widget->style, spin_button->panel,
426                           state_type, shadow_type, arrow, TRUE, 
427                           x, y, ARROW_SIZE, widget->requisition.height / 2 
428                           - widget->style->klass->ythickness);
429         }
430       else
431         {
432           if (spin_button->shadow_type != GTK_SHADOW_NONE)
433             {
434               x = widget->style->klass->xthickness;
435               y = widget->requisition.height / 2;
436             }
437           else
438             {
439               x = widget->style->klass->xthickness - 1;
440               y = widget->requisition.height / 2 + 1;
441             }
442           gtk_draw_arrow (widget->style, spin_button->panel,
443                           state_type, shadow_type, arrow, TRUE, 
444                           x, y, ARROW_SIZE, widget->requisition.height / 2 
445                           - widget->style->klass->ythickness);
446         }
447     }
448 }
449
450 static gint
451 gtk_spin_button_enter_notify (GtkWidget        *widget,
452                               GdkEventCrossing *event)
453 {
454   GtkSpinButton *spin;
455
456   g_return_val_if_fail (widget != NULL, FALSE);
457   g_return_val_if_fail (GTK_IS_SPIN_BUTTON (widget), FALSE);
458   g_return_val_if_fail (event != NULL, FALSE);
459
460   spin = GTK_SPIN_BUTTON (widget);
461
462   if (event->window == spin->panel)
463     {
464       gint x;
465       gint y;
466
467       gdk_window_get_pointer (spin->panel, &x, &y, NULL);
468
469       if (y <= widget->requisition.height / 2)
470         {
471           spin->in_child = GTK_ARROW_UP;
472           if (spin->click_child == 2) 
473             gtk_spin_button_draw_arrow (spin, GTK_ARROW_UP);
474         }
475       else
476         {
477           spin->in_child = GTK_ARROW_DOWN;
478           if (spin->click_child == 2) 
479             gtk_spin_button_draw_arrow (spin, GTK_ARROW_DOWN);
480         }
481     }
482   return FALSE;
483 }
484
485 static gint
486 gtk_spin_button_leave_notify (GtkWidget        *widget,
487                               GdkEventCrossing *event)
488 {
489   GtkSpinButton *spin;
490
491   g_return_val_if_fail (widget != NULL, FALSE);
492   g_return_val_if_fail (GTK_IS_SPIN_BUTTON (widget), FALSE);
493   g_return_val_if_fail (event != NULL, FALSE);
494
495   spin = GTK_SPIN_BUTTON (widget);
496
497   if (event->window == spin->panel && spin->click_child == 2)
498     {
499       if (spin->in_child == GTK_ARROW_UP) 
500         {
501           spin->in_child = 2;
502           gtk_spin_button_draw_arrow (spin, GTK_ARROW_UP);
503         }
504       else
505         {
506           spin->in_child = 2;
507           gtk_spin_button_draw_arrow (spin, GTK_ARROW_DOWN);
508         }
509     }
510   return FALSE;
511 }
512
513 static gint
514 gtk_spin_button_focus_out (GtkWidget     *widget,
515                            GdkEventFocus *event)
516 {
517   g_return_val_if_fail (widget != NULL, FALSE);
518   g_return_val_if_fail (GTK_IS_SPIN_BUTTON (widget), FALSE);
519   g_return_val_if_fail (event != NULL, FALSE);
520
521   gtk_spin_button_update (GTK_SPIN_BUTTON (widget));
522
523   return GTK_WIDGET_CLASS (parent_class)->focus_out_event (widget, event);
524 }
525
526 static gint
527 gtk_spin_button_button_press (GtkWidget      *widget,
528                               GdkEventButton *event)
529 {
530   GtkSpinButton *spin;
531
532   g_return_val_if_fail (widget != NULL, FALSE);
533   g_return_val_if_fail (GTK_IS_SPIN_BUTTON (widget), FALSE);
534   g_return_val_if_fail (event != NULL, FALSE);
535
536   spin = GTK_SPIN_BUTTON (widget);
537
538   if (!spin->button)
539     {
540       if (event->window == spin->panel)
541         {
542           if (!GTK_WIDGET_HAS_FOCUS (widget))
543             gtk_widget_grab_focus (widget);
544           gtk_grab_add (widget);
545           spin->button = event->button;
546           
547           gtk_spin_button_update (spin);
548           
549           if (event->y <= widget->requisition.height / 2)
550             {
551               spin->click_child = GTK_ARROW_UP;
552               if (event->button == 1)
553                 {
554                  gtk_spin_button_real_spin (spin, 
555                                             spin->adjustment->step_increment);
556                   if (!spin->timer)
557                     {
558                       spin->timer_step = spin->adjustment->step_increment;
559                       spin->need_timer = TRUE;
560                       spin->timer = gtk_timeout_add 
561                         (SPIN_BUTTON_INITIAL_TIMER_DELAY, 
562                          (GtkFunction) gtk_spin_button_timer, (gpointer) spin);
563                     }
564                 }
565               else if (event->button == 2)
566                 {
567                  gtk_spin_button_real_spin (spin, 
568                                             spin->adjustment->page_increment);
569                   if (!spin->timer) 
570                     {
571                       spin->timer_step = spin->adjustment->page_increment;
572                       spin->need_timer = TRUE;
573                       spin->timer = gtk_timeout_add 
574                         (SPIN_BUTTON_INITIAL_TIMER_DELAY, 
575                          (GtkFunction) gtk_spin_button_timer, (gpointer) spin);
576                     }
577                 }
578               gtk_spin_button_draw_arrow (spin, GTK_ARROW_UP);
579             }
580           else 
581             {
582               spin->click_child = GTK_ARROW_DOWN;
583               if (event->button == 1)
584                 {
585                   gtk_spin_button_real_spin (spin,
586                                              -spin->adjustment->step_increment);
587                   if (!spin->timer)
588                     {
589                       spin->timer_step = spin->adjustment->step_increment;
590                       spin->need_timer = TRUE;
591                       spin->timer = gtk_timeout_add 
592                         (SPIN_BUTTON_INITIAL_TIMER_DELAY, 
593                          (GtkFunction) gtk_spin_button_timer, (gpointer) spin);
594                     }
595                 }      
596               else if (event->button == 2)
597                 {
598                   gtk_spin_button_real_spin (spin,
599                                              -spin->adjustment->page_increment);
600                   if (!spin->timer) 
601                     {
602                       spin->timer_step = spin->adjustment->page_increment;
603                       spin->need_timer = TRUE;
604                       spin->timer = gtk_timeout_add 
605                         (SPIN_BUTTON_INITIAL_TIMER_DELAY, 
606                          (GtkFunction) gtk_spin_button_timer, (gpointer) spin);
607                     }
608                 }
609               gtk_spin_button_draw_arrow (spin, GTK_ARROW_DOWN);
610             }
611         }
612       else
613         GTK_WIDGET_CLASS (parent_class)->button_press_event (widget, event);
614     }
615   return FALSE;
616 }
617
618 static gint
619 gtk_spin_button_button_release (GtkWidget      *widget,
620                                 GdkEventButton *event)
621 {
622   GtkSpinButton *spin;
623
624   g_return_val_if_fail (widget != NULL, FALSE);
625   g_return_val_if_fail (GTK_IS_SPIN_BUTTON (widget), FALSE);
626   g_return_val_if_fail (event != NULL, FALSE);
627
628   spin = GTK_SPIN_BUTTON (widget);
629
630   if (event->button == spin->button)
631     {
632       guint click_child;
633
634       if (spin->timer)
635         {
636           gtk_timeout_remove (spin->timer);
637           spin->timer = 0;
638           spin->timer_calls = 0;
639           spin->need_timer = FALSE;
640         }
641
642       if (event->button == 3)
643         {
644           if (event->y >= 0 && event->x >= 0 && 
645               event->y <= widget->requisition.height &&
646               event->x <= ARROW_SIZE + 2 * widget->style->klass->xthickness)
647             {
648               if (spin->click_child == GTK_ARROW_UP &&
649                   event->y <= widget->requisition.height / 2)
650                 {
651                   gfloat diff;
652
653                   diff = spin->adjustment->upper - spin->adjustment->value;
654                   if (diff > EPSILON)
655                     gtk_spin_button_real_spin (spin, diff);
656                 }
657               else if (spin->click_child == GTK_ARROW_DOWN &&
658                        event->y > widget->requisition.height / 2)
659                 {
660                   gfloat diff;
661
662                   diff = spin->adjustment->value - spin->adjustment->lower;
663                   if (diff > EPSILON)
664                     gtk_spin_button_real_spin (spin, -diff);
665                 }
666             }
667         }                 
668       gtk_grab_remove (widget);
669       click_child = spin->click_child;
670       spin->click_child = 2;
671       spin->button = 0;
672       gtk_spin_button_draw_arrow (spin, click_child);
673     }
674   else
675     GTK_WIDGET_CLASS (parent_class)->button_release_event (widget, event);
676
677   return FALSE;
678 }
679
680 static gint
681 gtk_spin_button_motion_notify (GtkWidget      *widget,
682                                GdkEventMotion *event)
683 {
684   GtkSpinButton *spin;
685
686   g_return_val_if_fail (widget != NULL, FALSE);
687   g_return_val_if_fail (GTK_IS_SPIN_BUTTON (widget), FALSE);
688   g_return_val_if_fail (event != NULL, FALSE);
689
690   spin = GTK_SPIN_BUTTON (widget);
691   
692   if (spin->button)
693     return FALSE;
694
695   if (event->window == spin->panel)
696     {
697       gint y;
698
699       y = event->y;
700       if (event->is_hint)
701         gdk_window_get_pointer (spin->panel, NULL, &y, NULL);
702
703       if (y <= widget->requisition.height / 2 && 
704           spin->in_child == GTK_ARROW_DOWN)
705         {
706           spin->in_child = GTK_ARROW_UP;
707           gtk_spin_button_draw_arrow (spin, GTK_ARROW_UP);
708           gtk_spin_button_draw_arrow (spin, GTK_ARROW_DOWN);
709         }
710       else if (y > widget->requisition.height / 2 && 
711           spin->in_child == GTK_ARROW_UP)
712         {
713           spin->in_child = GTK_ARROW_DOWN;
714           gtk_spin_button_draw_arrow (spin, GTK_ARROW_UP);
715           gtk_spin_button_draw_arrow (spin, GTK_ARROW_DOWN);
716         }
717       return FALSE;
718     }
719           
720   return GTK_WIDGET_CLASS (parent_class)->motion_notify_event (widget, event);
721 }
722
723 static gint
724 gtk_spin_button_timer (GtkSpinButton *spin_button)
725 {
726   g_return_val_if_fail (spin_button != NULL, FALSE);
727   g_return_val_if_fail (GTK_IS_SPIN_BUTTON (spin_button), FALSE);
728
729   if (spin_button->timer)
730     {
731       if (spin_button->click_child == GTK_ARROW_UP)
732         gtk_spin_button_real_spin (spin_button, spin_button->timer_step);
733       else
734         gtk_spin_button_real_spin (spin_button, -spin_button->timer_step);
735
736       if (spin_button->need_timer)
737         {
738           spin_button->need_timer = FALSE;
739           spin_button->timer = gtk_timeout_add 
740             (SPIN_BUTTON_TIMER_DELAY, (GtkFunction) gtk_spin_button_timer, 
741              (gpointer) spin_button);
742           return FALSE;
743         }
744       else if (spin_button->climb_rate > 0.0 && spin_button->timer_step 
745                < spin_button->adjustment->page_increment)
746         {
747           if (spin_button->timer_calls < MAX_TIMER_CALLS)
748             spin_button->timer_calls++;
749           else 
750             {
751               spin_button->timer_calls = 0;
752               spin_button->timer_step += spin_button->climb_rate;
753             }
754         }
755       return TRUE;
756     }
757   return FALSE;
758 }
759
760 static void
761 gtk_spin_button_value_changed (GtkAdjustment *adjustment,
762                                GtkSpinButton *spin_button)
763 {
764   char buf[MAX_TEXT_LENGTH];
765
766   g_return_if_fail (adjustment != NULL);
767   g_return_if_fail (GTK_IS_ADJUSTMENT (adjustment));
768
769   sprintf (buf, "%0.*f", spin_button->digits, adjustment->value);
770   gtk_entry_set_text (GTK_ENTRY (spin_button), buf);
771 }
772
773 static gint
774 gtk_spin_button_key_press (GtkWidget     *widget,
775                            GdkEventKey   *event)
776 {
777   GtkSpinButton *spin;
778   gint key;
779   gboolean key_repeat = FALSE;
780
781   g_return_val_if_fail (widget != NULL, FALSE);
782   g_return_val_if_fail (GTK_IS_SPIN_BUTTON (widget), FALSE);
783   g_return_val_if_fail (event != NULL, FALSE);
784   
785   spin = GTK_SPIN_BUTTON (widget);
786   key = event->keyval;
787
788   key_repeat = (event->time == spin->ev_time);
789
790   if (key == GDK_Up || key == GDK_Down || 
791       key == GDK_Page_Up || key == GDK_Page_Down)
792     gtk_spin_button_update (spin);
793
794   switch (key)
795     {
796     case GDK_Up:
797
798       if (GTK_WIDGET_HAS_FOCUS (widget))
799         {
800           gtk_signal_emit_stop_by_name (GTK_OBJECT (widget), 
801                                         "key_press_event");
802           if (!key_repeat)
803             spin->timer_step = spin->adjustment->step_increment;
804
805          gtk_spin_button_real_spin (spin, spin->timer_step);
806
807           if (key_repeat)
808             {
809               if (spin->climb_rate > 0.0 && spin->timer_step
810                   < spin->adjustment->page_increment)
811                 {
812                   if (spin->timer_calls < MAX_TIMER_CALLS)
813                     spin->timer_calls++;
814                   else 
815                     {
816                       spin->timer_calls = 0;
817                       spin->timer_step += spin->climb_rate;
818                     }
819                 }
820             }
821           return TRUE;
822         }
823       return FALSE;
824
825     case GDK_Down:
826
827       if (GTK_WIDGET_HAS_FOCUS (widget))
828         {
829           gtk_signal_emit_stop_by_name (GTK_OBJECT (widget), 
830                                         "key_press_event");
831           if (!key_repeat)
832             spin->timer_step = spin->adjustment->step_increment;
833
834          gtk_spin_button_real_spin (spin, -spin->timer_step);
835
836           if (key_repeat)
837             {
838               if (spin->climb_rate > 0.0 && spin->timer_step
839                   < spin->adjustment->page_increment)
840                 {
841                   if (spin->timer_calls < MAX_TIMER_CALLS)
842                     spin->timer_calls++;
843                   else 
844                     {
845                       spin->timer_calls = 0;
846                       spin->timer_step += spin->climb_rate;
847                     }
848                 }
849             }
850           return TRUE;
851         }
852       return FALSE;
853
854     case GDK_Page_Up:
855
856       if (event->state & GDK_CONTROL_MASK)
857         {
858           gfloat diff = spin->adjustment->upper - spin->adjustment->value;
859           if (diff > EPSILON)
860             gtk_spin_button_real_spin (spin, diff);
861         }
862       else
863         gtk_spin_button_real_spin (spin, spin->adjustment->page_increment);
864       return TRUE;
865
866     case GDK_Page_Down:
867
868       if (event->state & GDK_CONTROL_MASK)
869         {
870           gfloat diff = spin->adjustment->value - spin->adjustment->lower;
871           if (diff > EPSILON)
872             gtk_spin_button_real_spin (spin, -diff);
873         }
874       else
875         gtk_spin_button_real_spin (spin, -spin->adjustment->page_increment);
876       return TRUE;
877
878     default:
879       break;
880     }
881
882   return GTK_WIDGET_CLASS (parent_class)->key_press_event (widget, event);
883 }
884
885 static gint
886 gtk_spin_button_key_release (GtkWidget   *widget,
887                              GdkEventKey *event)
888 {
889   GtkSpinButton *spin;
890
891   g_return_val_if_fail (widget != NULL, FALSE);
892   g_return_val_if_fail (GTK_IS_SPIN_BUTTON (widget), FALSE);
893   
894   spin = GTK_SPIN_BUTTON (widget);
895   
896   spin->ev_time = event->time;
897   return TRUE;
898 }
899
900 static void
901 gtk_spin_button_snap (GtkSpinButton *spin_button,
902                       gfloat         val)
903 {
904   gfloat inc;
905   gfloat tmp;
906   
907   inc = spin_button->adjustment->step_increment;
908   tmp = (val - spin_button->adjustment->lower) / inc;
909   if (tmp - floor (tmp) < ceil (tmp) - tmp)
910     val = spin_button->adjustment->lower + floor (tmp) * inc;
911   else
912     val = spin_button->adjustment->lower + ceil (tmp) * inc;
913
914   if (fabs (val - spin_button->adjustment->value) > EPSILON)
915     gtk_adjustment_set_value (spin_button->adjustment, val);
916   else
917     {
918       char buf[MAX_TEXT_LENGTH];
919
920       sprintf (buf, "%0.*f", spin_button->digits, 
921                spin_button->adjustment->value);
922       if (strcmp (buf, gtk_entry_get_text (GTK_ENTRY (spin_button))))
923         gtk_entry_set_text (GTK_ENTRY (spin_button), buf);
924     }
925 }
926
927 static void 
928 gtk_spin_button_update (GtkSpinButton *spin_button)
929 {
930   gfloat val;
931   gchar *error = NULL;
932
933   g_return_if_fail (spin_button != NULL);
934   g_return_if_fail (GTK_IS_SPIN_BUTTON (spin_button));
935
936   val = strtod (gtk_entry_get_text (GTK_ENTRY (spin_button)), &error);
937
938   if (spin_button->update_policy == GTK_UPDATE_ALWAYS)
939     {
940       if (val < spin_button->adjustment->lower)
941         val = spin_button->adjustment->lower;
942       else if (val > spin_button->adjustment->upper)
943         val = spin_button->adjustment->upper;
944     }
945   else if ((spin_button->update_policy == GTK_UPDATE_IF_VALID) && 
946            (*error ||
947            val < spin_button->adjustment->lower ||
948            val > spin_button->adjustment->upper))
949     {
950       gtk_spin_button_value_changed (spin_button->adjustment, spin_button);
951       return;
952     }
953
954   if (spin_button->snap_to_ticks)
955     gtk_spin_button_snap (spin_button, val);
956   else
957     {
958       if (fabs (val - spin_button->adjustment->value) > EPSILON)
959         gtk_adjustment_set_value (spin_button->adjustment, val);
960       else
961         {
962           char buf[MAX_TEXT_LENGTH];
963           
964           sprintf (buf, "%0.*f", spin_button->digits, 
965                    spin_button->adjustment->value);
966           if (strcmp (buf, gtk_entry_get_text (GTK_ENTRY (spin_button))))
967             gtk_entry_set_text (GTK_ENTRY (spin_button), buf);
968         }
969     }
970 }
971
972 static void
973 gtk_spin_button_activate (GtkEditable *editable)
974 {
975   g_return_if_fail (editable != NULL);
976   g_return_if_fail (GTK_IS_SPIN_BUTTON (editable));
977
978   if (editable->editable)
979     gtk_spin_button_update (GTK_SPIN_BUTTON (editable));
980 }
981
982 static void
983 gtk_spin_button_insert_text (GtkEditable *editable,
984                              const gchar *new_text,
985                              gint         new_text_length,
986                              gint        *position)
987 {
988   GtkEntry *entry;
989   GtkSpinButton *spin;
990  
991   g_return_if_fail (editable != NULL);
992   g_return_if_fail (GTK_IS_SPIN_BUTTON (editable));
993
994   entry = GTK_ENTRY (editable);
995   spin  = GTK_SPIN_BUTTON (editable);
996
997   if (spin->numeric)
998     {
999       struct lconv *lc;
1000       gboolean sign;
1001       gint dotpos = -1;
1002       gint i;
1003       gchar pos_sign;
1004       gchar neg_sign;
1005
1006       lc = localeconv ();
1007
1008       if (*(lc->negative_sign))
1009         neg_sign = *(lc->negative_sign);
1010       else 
1011         neg_sign = '-';
1012
1013       if (*(lc->positive_sign))
1014         pos_sign = *(lc->positive_sign);
1015       else 
1016         pos_sign = '+';
1017
1018       sign = ((strchr (entry->text, neg_sign) != 0) ||
1019               (strchr (entry->text, pos_sign) != 0));
1020
1021       if (sign && !(*position))
1022         return;
1023
1024       dotpos = strchr (entry->text, *(lc->decimal_point)) - entry->text;
1025       
1026       if (dotpos > -1 && *position > dotpos &&
1027           spin->digits - entry->text_length + dotpos - new_text_length + 1 < 0)
1028         return;
1029
1030       for (i = 0; i < new_text_length; i++)
1031         {
1032           if (new_text[i] == neg_sign || new_text[i] == pos_sign)
1033             {
1034               if (sign || (*position) || i)
1035                 return;
1036               sign = TRUE;
1037             }
1038           else if (new_text[i] == *(lc->decimal_point))
1039             {
1040               if (!spin->digits || dotpos > -1 || 
1041                   (new_text_length - 1 - i + entry->text_length - *position > 
1042                    spin->digits)) 
1043                 return;
1044               dotpos = *position + i;
1045             }
1046           else if (new_text[i] < 0x30 || new_text[i] > 0x39)
1047             return;
1048         }
1049     }
1050
1051   GTK_EDITABLE_CLASS (parent_class)->insert_text (editable, new_text,
1052                                                   new_text_length, position);
1053 }
1054
1055 static void
1056 gtk_spin_button_real_spin (GtkSpinButton *spin_button,
1057                            gfloat         increment)
1058 {
1059   GtkAdjustment *adj;
1060   gfloat new_value = 0.0;
1061
1062   g_return_if_fail (spin_button != NULL);
1063   g_return_if_fail (GTK_IS_SPIN_BUTTON (spin_button));
1064   
1065   adj = spin_button->adjustment;
1066
1067   new_value = adj->value + increment;
1068
1069   if (increment > 0)
1070     {
1071       if (spin_button->wrap)
1072         {
1073           if (fabs (adj->value - adj->upper) < EPSILON)
1074             new_value = adj->lower;
1075           else if (new_value > adj->upper)
1076             new_value = adj->upper;
1077         }
1078       else
1079         new_value = MIN (new_value, adj->upper);
1080     }
1081   else if (increment < 0) 
1082     {
1083       if (spin_button->wrap)
1084         {
1085           if (fabs (adj->value - adj->lower) < EPSILON)
1086             new_value = adj->upper;
1087           else if (new_value < adj->lower)
1088             new_value = adj->lower;
1089         }
1090       else
1091         new_value = MAX (new_value, adj->lower);
1092     }
1093
1094   if (fabs (new_value - adj->value) > EPSILON)
1095     gtk_adjustment_set_value (adj, new_value);
1096 }
1097
1098
1099 /***********************************************************
1100  ***********************************************************
1101  ***                  Public interface                   ***
1102  ***********************************************************
1103  ***********************************************************/
1104
1105
1106 void
1107 gtk_spin_button_construct (GtkSpinButton  *spin_button,
1108                            GtkAdjustment  *adjustment,
1109                            gfloat          climb_rate,
1110                            gint            digits)
1111 {
1112   char buf[MAX_TEXT_LENGTH];
1113
1114   g_return_if_fail (spin_button != NULL);
1115   g_return_if_fail (GTK_IS_SPIN_BUTTON (spin_button));
1116   g_return_if_fail (digits >= 0 && digits < 6);
1117
1118   if (!adjustment)
1119     adjustment = (GtkAdjustment*) gtk_adjustment_new (0, 0, 0, 0, 0, 0);
1120
1121   gtk_spin_button_set_adjustment (spin_button, adjustment);
1122   spin_button->digits = digits;
1123   sprintf (buf, "%0.*f", digits, adjustment->value);
1124   gtk_entry_set_text (GTK_ENTRY (spin_button), buf);
1125   spin_button->climb_rate = climb_rate;
1126 }
1127
1128 GtkWidget *
1129 gtk_spin_button_new (GtkAdjustment *adjustment,
1130                      gfloat         climb_rate,
1131                      gint           digits)
1132 {
1133   GtkSpinButton *spin;
1134
1135   g_return_val_if_fail (digits >= 0 && digits < 6, NULL);
1136
1137   spin = gtk_type_new (gtk_spin_button_get_type ());
1138
1139   gtk_spin_button_construct (spin, adjustment, climb_rate, digits);
1140
1141   return GTK_WIDGET (spin);
1142 }
1143
1144 void
1145 gtk_spin_button_set_adjustment (GtkSpinButton *spin_button,
1146                                 GtkAdjustment *adjustment)
1147 {
1148   g_return_if_fail (spin_button != NULL);
1149   g_return_if_fail (GTK_IS_SPIN_BUTTON (spin_button));
1150
1151   if (spin_button->adjustment != adjustment)
1152     {
1153       if (spin_button->adjustment)
1154         {
1155           gtk_signal_disconnect_by_data (GTK_OBJECT (spin_button->adjustment),
1156                                          (gpointer) spin_button);
1157           gtk_object_unref (GTK_OBJECT (spin_button->adjustment));
1158         }
1159       spin_button->adjustment = adjustment;
1160       if (adjustment)
1161         {
1162           gtk_object_ref (GTK_OBJECT (adjustment));
1163           gtk_object_sink (GTK_OBJECT (adjustment));
1164           gtk_signal_connect (GTK_OBJECT (adjustment), "value_changed",
1165                               (GtkSignalFunc) gtk_spin_button_value_changed,
1166                               (gpointer) spin_button);
1167         }
1168     }
1169 }
1170
1171 GtkAdjustment *
1172 gtk_spin_button_get_adjustment (GtkSpinButton *spin_button)
1173 {
1174   g_return_val_if_fail (spin_button != NULL, NULL);
1175   g_return_val_if_fail (GTK_IS_SPIN_BUTTON (spin_button), NULL);
1176
1177   return spin_button->adjustment;
1178 }
1179
1180 void
1181 gtk_spin_button_set_digits (GtkSpinButton *spin_button,
1182                             gint           digits)
1183 {
1184   g_return_if_fail (spin_button != NULL);
1185   g_return_if_fail (GTK_IS_SPIN_BUTTON (spin_button));
1186   g_return_if_fail (digits >= 0 || digits < 6);
1187
1188   if (spin_button->digits != digits)
1189     {
1190       spin_button->digits = digits;
1191       gtk_spin_button_value_changed (spin_button->adjustment, spin_button);
1192     }
1193 }
1194
1195 gfloat
1196 gtk_spin_button_get_value_as_float (GtkSpinButton *spin_button)
1197 {
1198   g_return_val_if_fail (spin_button != NULL, 0.0);
1199   g_return_val_if_fail (GTK_IS_SPIN_BUTTON (spin_button), 0.0);
1200
1201   return spin_button->adjustment->value;
1202 }
1203
1204 gint
1205 gtk_spin_button_get_value_as_int (GtkSpinButton *spin_button)
1206 {
1207   gfloat val;
1208
1209   g_return_val_if_fail (spin_button != NULL, 0);
1210   g_return_val_if_fail (GTK_IS_SPIN_BUTTON (spin_button), 0);
1211
1212   val = spin_button->adjustment->value;
1213   if (val - floor (val) < ceil (val) - val)
1214     return floor (val);
1215   else
1216     return ceil (val);
1217 }
1218
1219 void 
1220 gtk_spin_button_set_value (GtkSpinButton *spin_button, 
1221                            gfloat         value)
1222 {
1223   g_return_if_fail (spin_button != NULL);
1224   g_return_if_fail (GTK_IS_SPIN_BUTTON (spin_button));
1225
1226   if (fabs (value - spin_button->adjustment->value) > EPSILON)
1227     gtk_adjustment_set_value (spin_button->adjustment, value);
1228   else
1229     {
1230       char buf[MAX_TEXT_LENGTH];
1231
1232       sprintf (buf, "%0.*f", spin_button->digits, 
1233                spin_button->adjustment->value);
1234       if (strcmp (buf, gtk_entry_get_text (GTK_ENTRY (spin_button))))
1235         gtk_entry_set_text (GTK_ENTRY (spin_button), buf);
1236     }
1237 }
1238
1239 void
1240 gtk_spin_button_set_update_policy (GtkSpinButton             *spin_button,
1241                                    GtkSpinButtonUpdatePolicy  policy)
1242 {
1243   g_return_if_fail (spin_button != NULL);
1244   g_return_if_fail (GTK_IS_SPIN_BUTTON (spin_button));
1245
1246   spin_button->update_policy = policy;
1247 }
1248
1249 void
1250 gtk_spin_button_set_numeric (GtkSpinButton  *spin_button,
1251                              gint            numeric)
1252 {
1253   g_return_if_fail (spin_button != NULL);
1254   g_return_if_fail (GTK_IS_SPIN_BUTTON (spin_button));
1255
1256   spin_button->numeric = (numeric != 0);
1257 }
1258
1259 void
1260 gtk_spin_button_set_wrap (GtkSpinButton  *spin_button,
1261                           gint            wrap)
1262 {
1263   g_return_if_fail (spin_button != NULL);
1264   g_return_if_fail (GTK_IS_SPIN_BUTTON (spin_button));
1265
1266   spin_button->wrap = (wrap != 0);
1267 }
1268
1269 void
1270 gtk_spin_button_set_shadow_type (GtkSpinButton *spin_button,
1271                                  GtkShadowType  shadow_type)
1272 {
1273   g_return_if_fail (spin_button != NULL);
1274   g_return_if_fail (GTK_IS_SPIN_BUTTON (spin_button));
1275
1276   if (shadow_type != spin_button->shadow_type)
1277     {
1278       spin_button->shadow_type = shadow_type;
1279       if (GTK_WIDGET_DRAWABLE (spin_button))
1280         gdk_window_clear (spin_button->panel);
1281     }
1282 }
1283
1284 void
1285 gtk_spin_button_set_snap_to_ticks (GtkSpinButton *spin_button,
1286                                    gint           snap_to_ticks)
1287 {
1288   guint new_val;
1289
1290   g_return_if_fail (spin_button != NULL);
1291   g_return_if_fail (GTK_IS_SPIN_BUTTON (spin_button));
1292
1293   new_val = (snap_to_ticks != 0);
1294
1295   if (new_val != spin_button->snap_to_ticks)
1296     {
1297       spin_button->snap_to_ticks = new_val;
1298       if (new_val)
1299         {
1300           gchar *error = NULL;
1301           gfloat val;
1302
1303           val = strtod (gtk_entry_get_text (GTK_ENTRY (spin_button)), &error);
1304           gtk_spin_button_snap (spin_button, val);
1305         }
1306     }
1307 }
1308
1309 void
1310 gtk_spin_button_spin (GtkSpinButton *spin_button,
1311                       GtkSpinType    direction,
1312                       gfloat         increment)
1313 {
1314   GtkAdjustment *adj;
1315   gfloat diff;
1316
1317   g_return_if_fail (spin_button != NULL);
1318   g_return_if_fail (GTK_IS_SPIN_BUTTON (spin_button));
1319   
1320   adj = spin_button->adjustment;
1321
1322   /* for compatibility with the 1.0.x version of this function */
1323   if (increment != 0 && increment != adj->step_increment &&
1324       (direction == GTK_SPIN_STEP_FORWARD ||
1325        direction == GTK_SPIN_STEP_BACKWARD))
1326     {
1327       if (direction == GTK_SPIN_STEP_BACKWARD && increment > 0)
1328         increment = -increment;
1329       direction = GTK_SPIN_USER_DEFINED;
1330     }
1331
1332   switch (direction)
1333     {
1334     case GTK_SPIN_STEP_FORWARD:
1335
1336       gtk_spin_button_real_spin (spin_button, adj->step_increment);
1337       break;
1338
1339     case GTK_SPIN_STEP_BACKWARD:
1340
1341       gtk_spin_button_real_spin (spin_button, -adj->step_increment);
1342       break;
1343
1344     case GTK_SPIN_PAGE_FORWARD:
1345
1346       gtk_spin_button_real_spin (spin_button, adj->page_increment);
1347       break;
1348
1349     case GTK_SPIN_PAGE_BACKWARD:
1350
1351       gtk_spin_button_real_spin (spin_button, -adj->page_increment);
1352       break;
1353
1354     case GTK_SPIN_HOME:
1355
1356       diff = adj->value - adj->lower;
1357       if (diff > EPSILON)
1358         gtk_spin_button_real_spin (spin_button, -diff);
1359       break;
1360
1361     case GTK_SPIN_END:
1362
1363       diff = adj->upper - adj->value;
1364       if (diff > EPSILON)
1365         gtk_spin_button_real_spin (spin_button, diff);
1366       break;
1367
1368     case GTK_SPIN_USER_DEFINED:
1369
1370       if (increment != 0)
1371         gtk_spin_button_real_spin (spin_button, increment);
1372       break;
1373
1374     default:
1375       break;
1376     }
1377 }