]> Pileus Git - ~andy/gtk/blob - gtk/gtklist.c
documented necessary changes for 1.4 transition.
[~andy/gtk] / gtk / gtklist.c
1 /* GTK - The GIMP Toolkit
2  * Copyright (C) 1995-1997 Peter Mattis, Spencer Kimball and Josh MacDonald
3  *
4  * This library is free software; you can redistribute it and/or
5  * modify it under the terms of the GNU Library General Public
6  * License as published by the Free Software Foundation; either
7  * version 2 of the License, or (at your option) any later version.
8  *
9  * This library is distributed in the hope that it will be useful,
10  * but WITHOUT ANY WARRANTY; without even the implied warranty of
11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
12  * Library General Public License for more details.
13  *
14  * You should have received a copy of the GNU Library General Public
15  * License along with this library; if not, write to the
16  * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
17  * Boston, MA 02111-1307, USA.
18  */
19
20 /*
21  * Modified by the GTK+ Team and others 1997-1999.  See the AUTHORS
22  * file for a list of people on the GTK+ Team.  See the ChangeLog
23  * files for a list of changes.  These files are distributed with
24  * GTK+ at ftp://ftp.gtk.org/pub/gtk/. 
25  */
26
27 #include "gtklist.h"
28 #include "gtklistitem.h"
29 #include "gtkmain.h"
30 #include "gtksignal.h"
31 #include "gtklabel.h"
32
33 enum {
34   SELECTION_CHANGED,
35   SELECT_CHILD,
36   UNSELECT_CHILD,
37   LAST_SIGNAL
38 };
39
40 enum {
41   ARG_0,
42   ARG_SELECTION_MODE
43 };
44
45 #define SCROLL_TIME  100
46
47 /** GtkList Methods **/
48 static void gtk_list_class_init      (GtkListClass   *klass);
49 static void gtk_list_init            (GtkList        *list);
50 static void gtk_list_set_arg         (GtkObject      *object,
51                                       GtkArg         *arg,
52                                       guint           arg_id);
53 static void gtk_list_get_arg         (GtkObject      *object,
54                                       GtkArg         *arg,
55                                       guint           arg_id);
56 /** GtkObject Methods **/
57 static void gtk_list_shutdown        (GObject        *object);
58
59 /** GtkWidget Methods **/
60 static void gtk_list_size_request    (GtkWidget      *widget,
61                                       GtkRequisition *requisition);
62 static void gtk_list_size_allocate   (GtkWidget      *widget,
63                                       GtkAllocation  *allocation);
64 static void gtk_list_realize         (GtkWidget      *widget);
65 static void gtk_list_map             (GtkWidget      *widget);
66 static void gtk_list_unmap           (GtkWidget      *widget);
67 static void gtk_list_style_set       (GtkWidget      *widget,
68                                       GtkStyle       *previous_style);
69 static void gtk_list_draw            (GtkWidget      *widget,
70                                       GdkRectangle   *area);
71 static gint gtk_list_expose          (GtkWidget      *widget,
72                                       GdkEventExpose *event);
73 static gint gtk_list_motion_notify   (GtkWidget      *widget,
74                                       GdkEventMotion *event);
75 static gint gtk_list_button_press    (GtkWidget      *widget,
76                                       GdkEventButton *event);
77 static gint gtk_list_button_release  (GtkWidget      *widget,
78                                       GdkEventButton *event);
79
80 /** GtkContainer Methods **/
81 static void gtk_list_add             (GtkContainer     *container,
82                                       GtkWidget        *widget);
83 static void gtk_list_remove          (GtkContainer     *container,
84                                       GtkWidget        *widget);
85 static void gtk_list_forall          (GtkContainer     *container,
86                                       gboolean          include_internals,
87                                       GtkCallback       callback,
88                                       gpointer          callback_data);
89 static GtkType gtk_list_child_type   (GtkContainer     *container);
90 static void gtk_list_set_focus_child (GtkContainer     *container,
91                                       GtkWidget        *widget);
92 static gint gtk_list_focus           (GtkContainer     *container,
93                                       GtkDirectionType  direction);
94
95 /** GtkList Private Functions **/
96 static void gtk_list_move_focus_child      (GtkList       *list,
97                                             GtkScrollType  scroll_type,
98                                             gfloat         position);
99 static gint gtk_list_horizontal_timeout    (GtkWidget     *list);
100 static gint gtk_list_vertical_timeout      (GtkWidget     *list);
101 static void gtk_list_remove_items_internal (GtkList       *list,
102                                             GList         *items,
103                                             gboolean       no_unref);
104
105 /** GtkList Selection Methods **/
106 static void gtk_real_list_select_child          (GtkList   *list,
107                                                  GtkWidget *child);
108 static void gtk_real_list_unselect_child        (GtkList   *list,
109                                                  GtkWidget *child);
110
111 /** GtkList Selection Functions **/
112 static void gtk_list_set_anchor                 (GtkList   *list,
113                                                  gboolean   add_mode,
114                                                  gint       anchor,
115                                                  GtkWidget *undo_focus_child);
116 static void gtk_list_fake_unselect_all          (GtkList   *list,
117                                                  GtkWidget *item);
118 static void gtk_list_fake_toggle_row            (GtkList   *list,
119                                                  GtkWidget *item);
120 static void gtk_list_update_extended_selection  (GtkList   *list,
121                                                  gint       row);
122 static void gtk_list_reset_extended_selection   (GtkList   *list);
123
124 /** GtkListItem Signal Functions **/
125 static void gtk_list_signal_drag_begin         (GtkWidget      *widget,
126                                                 GdkDragContext *context,
127                                                 GtkList        *list);
128 static void gtk_list_signal_toggle_focus_row   (GtkListItem   *list_item,
129                                                 GtkList       *list);
130 static void gtk_list_signal_select_all         (GtkListItem   *list_item,
131                                                 GtkList       *list);
132 static void gtk_list_signal_unselect_all       (GtkListItem   *list_item,
133                                                 GtkList       *list);
134 static void gtk_list_signal_undo_selection     (GtkListItem   *list_item,
135                                                 GtkList       *list);
136 static void gtk_list_signal_start_selection    (GtkListItem   *list_item,
137                                                 GtkList       *list);
138 static void gtk_list_signal_end_selection      (GtkListItem   *list_item,
139                                                 GtkList       *list);
140 static void gtk_list_signal_extend_selection   (GtkListItem   *list_item,
141                                                 GtkScrollType  scroll_type,
142                                                 gfloat         position,
143                                                 gboolean       auto_start_selection,
144                                                 GtkList       *list);
145 static void gtk_list_signal_scroll_horizontal  (GtkListItem   *list_item,
146                                                 GtkScrollType  scroll_type,
147                                                 gfloat         position,
148                                                 GtkList       *list);
149 static void gtk_list_signal_scroll_vertical    (GtkListItem   *list_item,
150                                                 GtkScrollType  scroll_type,
151                                                 gfloat         position,
152                                                 GtkList       *list);
153 static void gtk_list_signal_toggle_add_mode    (GtkListItem   *list_item,
154                                                 GtkList       *list);
155 static void gtk_list_signal_item_select        (GtkListItem   *list_item,
156                                                 GtkList       *list);
157 static void gtk_list_signal_item_deselect      (GtkListItem   *list_item,
158                                                 GtkList       *list);
159 static void gtk_list_signal_item_toggle        (GtkListItem   *list_item,
160                                                 GtkList       *list);
161
162
163 static void gtk_list_drag_begin (GtkWidget      *widget,
164                                  GdkDragContext *context);
165
166
167 static GtkContainerClass *parent_class = NULL;
168 static guint list_signals[LAST_SIGNAL] = { 0 };
169
170 static const gchar *vadjustment_key = "gtk-vadjustment";
171 static guint        vadjustment_key_id = 0;
172 static const gchar *hadjustment_key = "gtk-hadjustment";
173 static guint        hadjustment_key_id = 0;
174
175 GtkType
176 gtk_list_get_type (void)
177 {
178   static GtkType list_type = 0;
179
180   if (!list_type)
181     {
182       static const GtkTypeInfo list_info =
183       {
184         "GtkList",
185         sizeof (GtkList),
186         sizeof (GtkListClass),
187         (GtkClassInitFunc) gtk_list_class_init,
188         (GtkObjectInitFunc) gtk_list_init,
189         /* reserved_1 */ NULL,
190         /* reserved_2 */ NULL,
191         (GtkClassInitFunc) NULL,
192       };
193
194       list_type = gtk_type_unique (GTK_TYPE_CONTAINER, &list_info);
195     }
196
197   return list_type;
198 }
199
200 static void
201 gtk_list_class_init (GtkListClass *class)
202 {
203   GObjectClass *gobject_class = G_OBJECT_CLASS (class);
204   GtkObjectClass *object_class;
205   GtkWidgetClass *widget_class;
206   GtkContainerClass *container_class;
207
208   object_class = (GtkObjectClass*) class;
209   widget_class = (GtkWidgetClass*) class;
210   container_class = (GtkContainerClass*) class;
211
212   parent_class = gtk_type_class (GTK_TYPE_CONTAINER);
213
214   vadjustment_key_id = g_quark_from_static_string (vadjustment_key);
215   hadjustment_key_id = g_quark_from_static_string (hadjustment_key);
216
217   gobject_class->shutdown = gtk_list_shutdown;
218
219   list_signals[SELECTION_CHANGED] =
220     gtk_signal_new ("selection_changed",
221                     GTK_RUN_FIRST,
222                     GTK_CLASS_TYPE (object_class),
223                     GTK_SIGNAL_OFFSET (GtkListClass, selection_changed),
224                     gtk_marshal_NONE__NONE,
225                     GTK_TYPE_NONE, 0);
226   list_signals[SELECT_CHILD] =
227     gtk_signal_new ("select_child",
228                     GTK_RUN_FIRST,
229                     GTK_CLASS_TYPE (object_class),
230                     GTK_SIGNAL_OFFSET (GtkListClass, select_child),
231                     gtk_marshal_NONE__POINTER,
232                     GTK_TYPE_NONE, 1,
233                     GTK_TYPE_WIDGET);
234   list_signals[UNSELECT_CHILD] =
235     gtk_signal_new ("unselect_child",
236                     GTK_RUN_FIRST,
237                     GTK_CLASS_TYPE (object_class),
238                     GTK_SIGNAL_OFFSET (GtkListClass, unselect_child),
239                     gtk_marshal_NONE__POINTER,
240                     GTK_TYPE_NONE, 1,
241                     GTK_TYPE_WIDGET);
242
243   gtk_object_class_add_signals (object_class, list_signals, LAST_SIGNAL);
244
245   object_class->set_arg = gtk_list_set_arg;
246   object_class->get_arg = gtk_list_get_arg;
247
248   widget_class->map = gtk_list_map;
249   widget_class->unmap = gtk_list_unmap;
250   widget_class->style_set = gtk_list_style_set;
251   widget_class->realize = gtk_list_realize;
252   widget_class->draw = gtk_list_draw;
253   widget_class->expose_event = gtk_list_expose;
254   widget_class->button_press_event = gtk_list_button_press;
255   widget_class->button_release_event = gtk_list_button_release;
256   widget_class->motion_notify_event = gtk_list_motion_notify;
257   widget_class->size_request = gtk_list_size_request;
258   widget_class->size_allocate = gtk_list_size_allocate;
259   widget_class->drag_begin = gtk_list_drag_begin;
260
261   container_class->add = gtk_list_add;
262   container_class->remove = gtk_list_remove;
263   container_class->forall = gtk_list_forall;
264   container_class->child_type = gtk_list_child_type;
265   container_class->set_focus_child = gtk_list_set_focus_child;
266   container_class->focus = gtk_list_focus;
267
268   class->selection_changed = NULL;
269   class->select_child = gtk_real_list_select_child;
270   class->unselect_child = gtk_real_list_unselect_child;
271   
272   gtk_object_add_arg_type ("GtkList::selection_mode",
273                            GTK_TYPE_SELECTION_MODE, GTK_ARG_READWRITE,
274                            ARG_SELECTION_MODE);
275 }
276
277 static void
278 gtk_list_init (GtkList *list)
279 {
280   list->children = NULL;
281   list->selection = NULL;
282
283   list->undo_selection = NULL;
284   list->undo_unselection = NULL;
285
286   list->last_focus_child = NULL;
287   list->undo_focus_child = NULL;
288
289   list->htimer = 0;
290   list->vtimer = 0;
291
292   list->anchor = -1;
293   list->drag_pos = -1;
294   list->anchor_state = GTK_STATE_SELECTED;
295
296   list->selection_mode = GTK_SELECTION_SINGLE;
297   list->drag_selection = FALSE;
298   list->add_mode = FALSE;
299 }
300
301 static void
302 gtk_list_set_arg (GtkObject      *object,
303                   GtkArg         *arg,
304                   guint           arg_id)
305 {
306   GtkList *list = GTK_LIST (object);
307   
308   switch (arg_id)
309     {
310     case ARG_SELECTION_MODE:
311       gtk_list_set_selection_mode (list, GTK_VALUE_ENUM (*arg));
312       break;
313     }
314 }
315
316 static void
317 gtk_list_get_arg (GtkObject      *object,
318                   GtkArg         *arg,
319                   guint           arg_id)
320 {
321   GtkList *list = GTK_LIST (object);
322   
323   switch (arg_id)
324     {
325     case ARG_SELECTION_MODE: 
326       GTK_VALUE_ENUM (*arg) = list->selection_mode; 
327       break;
328     default:
329       arg->type = GTK_TYPE_INVALID;
330       break;
331     }
332 }
333
334 GtkWidget*
335 gtk_list_new (void)
336 {
337   return GTK_WIDGET (gtk_type_new (GTK_TYPE_LIST));
338 }
339
340
341 /* Private GtkObject Methods :
342  * 
343  * gtk_list_shutdown
344  */
345 static void
346 gtk_list_shutdown (GObject *object)
347 {
348   gtk_list_clear_items (GTK_LIST (object), 0, -1);
349
350   G_OBJECT_CLASS (parent_class)->shutdown (object);
351 }
352
353
354 /* Private GtkWidget Methods :
355  * 
356  * gtk_list_size_request
357  * gtk_list_size_allocate
358  * gtk_list_realize
359  * gtk_list_map
360  * gtk_list_unmap
361  * gtk_list_motion_notify
362  * gtk_list_button_press
363  * gtk_list_button_release
364  */
365 static void
366 gtk_list_size_request (GtkWidget      *widget,
367                        GtkRequisition *requisition)
368 {
369   GtkList *list;
370   GtkWidget *child;
371   GList *children;
372
373   g_return_if_fail (widget != NULL);
374   g_return_if_fail (GTK_IS_LIST (widget));
375   g_return_if_fail (requisition != NULL);
376
377   list = GTK_LIST (widget);
378   requisition->width = 0;
379   requisition->height = 0;
380
381   children = list->children;
382   while (children)
383     {
384       child = children->data;
385       children = children->next;
386
387       if (GTK_WIDGET_VISIBLE (child))
388         {
389           GtkRequisition child_requisition;
390           
391           gtk_widget_size_request (child, &child_requisition);
392
393           requisition->width = MAX (requisition->width,
394                                     child_requisition.width);
395           requisition->height += child_requisition.height;
396         }
397     }
398
399   requisition->width += GTK_CONTAINER (list)->border_width * 2;
400   requisition->height += GTK_CONTAINER (list)->border_width * 2;
401
402   requisition->width = MAX (requisition->width, 1);
403   requisition->height = MAX (requisition->height, 1);
404 }
405
406 static void
407 gtk_list_size_allocate (GtkWidget     *widget,
408                         GtkAllocation *allocation)
409 {
410   GtkList *list;
411   GtkWidget *child;
412   GtkAllocation child_allocation;
413   GList *children;
414
415   g_return_if_fail (widget != NULL);
416   g_return_if_fail (GTK_IS_LIST (widget));
417   g_return_if_fail (allocation != NULL);
418
419   list = GTK_LIST (widget);
420
421   widget->allocation = *allocation;
422   if (GTK_WIDGET_REALIZED (widget))
423     gdk_window_move_resize (widget->window,
424                             allocation->x, allocation->y,
425                             allocation->width, allocation->height);
426
427   if (list->children)
428     {
429       child_allocation.x = GTK_CONTAINER (list)->border_width;
430       child_allocation.y = GTK_CONTAINER (list)->border_width;
431       child_allocation.width = MAX (1, (gint)allocation->width -
432                                     child_allocation.x * 2);
433
434       children = list->children;
435
436       while (children)
437         {
438           child = children->data;
439           children = children->next;
440
441           if (GTK_WIDGET_VISIBLE (child))
442             {
443               GtkRequisition child_requisition;
444               gtk_widget_get_child_requisition (child, &child_requisition);
445               
446               child_allocation.height = child_requisition.height;
447
448               gtk_widget_size_allocate (child, &child_allocation);
449
450               child_allocation.y += child_allocation.height;
451             }
452         }
453     }
454 }
455
456 static void
457 gtk_list_realize (GtkWidget *widget)
458 {
459   GdkWindowAttr attributes;
460   gint attributes_mask;
461
462   g_return_if_fail (widget != NULL);
463   g_return_if_fail (GTK_IS_LIST (widget));
464
465   GTK_WIDGET_SET_FLAGS (widget, GTK_REALIZED);
466
467   attributes.window_type = GDK_WINDOW_CHILD;
468   attributes.x = widget->allocation.x;
469   attributes.y = widget->allocation.y;
470   attributes.width = widget->allocation.width;
471   attributes.height = widget->allocation.height;
472   attributes.wclass = GDK_INPUT_OUTPUT;
473   attributes.visual = gtk_widget_get_visual (widget);
474   attributes.colormap = gtk_widget_get_colormap (widget);
475   attributes.event_mask = gtk_widget_get_events (widget) | GDK_EXPOSURE_MASK;
476
477   attributes_mask = GDK_WA_X | GDK_WA_Y | GDK_WA_VISUAL | GDK_WA_COLORMAP;
478
479   widget->window = gdk_window_new (gtk_widget_get_parent_window (widget),
480                                    &attributes, attributes_mask);
481   gdk_window_set_user_data (widget->window, widget);
482
483   widget->style = gtk_style_attach (widget->style, widget->window);
484   gdk_window_set_background (widget->window, 
485                              &widget->style->base[GTK_STATE_NORMAL]);
486 }
487
488 static void
489 gtk_list_map (GtkWidget *widget)
490 {
491   GtkList *list;
492   GtkWidget *child;
493   GList *children;
494
495   g_return_if_fail (widget != NULL);
496   g_return_if_fail (GTK_IS_LIST (widget));
497
498   GTK_WIDGET_SET_FLAGS (widget, GTK_MAPPED);
499   list = GTK_LIST (widget);
500
501   children = list->children;
502   while (children)
503     {
504       child = children->data;
505       children = children->next;
506
507       if (GTK_WIDGET_VISIBLE (child) &&
508           !GTK_WIDGET_MAPPED (child))
509         gtk_widget_map (child);
510     }
511
512   gdk_window_show (widget->window);
513 }
514
515 static void
516 gtk_list_unmap (GtkWidget *widget)
517 {
518   GtkList *list;
519
520   g_return_if_fail (widget != NULL);
521   g_return_if_fail (GTK_IS_LIST (widget));
522
523   if (!GTK_WIDGET_MAPPED (widget))
524     return;
525
526   list = GTK_LIST (widget);
527
528   GTK_WIDGET_UNSET_FLAGS (widget, GTK_MAPPED);
529
530   if (gdk_pointer_is_grabbed () && GTK_WIDGET_HAS_GRAB (list))
531     {
532       gtk_list_end_drag_selection (list);
533
534       if (list->anchor != -1 && list->selection_mode == GTK_SELECTION_EXTENDED)
535         gtk_list_end_selection (list);
536     }
537
538   gdk_window_hide (widget->window);
539 }
540
541 static gint
542 gtk_list_motion_notify (GtkWidget      *widget,
543                         GdkEventMotion *event)
544 {
545   GtkList *list;
546   GtkWidget *item = NULL;
547   GtkAdjustment *adj;
548   GtkContainer *container;
549   GList *work;
550   gint x;
551   gint y;
552   gint row = -1;
553   gint focus_row = 0;
554   gint length = 0;
555
556   g_return_val_if_fail (widget != NULL, FALSE);
557   g_return_val_if_fail (GTK_IS_LIST (widget), FALSE);
558   g_return_val_if_fail (event != NULL, FALSE);
559
560   list = GTK_LIST (widget);
561
562   if (!list->drag_selection || !list->children)
563     return FALSE;
564
565   container = GTK_CONTAINER (widget);
566
567   if (event->is_hint || event->window != widget->window)
568     gdk_window_get_pointer (widget->window, &x, &y, NULL);
569   else
570     {
571       x = event->x;
572       y = event->y;
573     }
574
575   adj = gtk_object_get_data_by_id (GTK_OBJECT (list), hadjustment_key_id);
576
577   /* horizontal autoscrolling */
578   if (adj && widget->allocation.width > adj->page_size &&
579       (x < adj->value || x >= adj->value + adj->page_size))
580     {
581       if (list->htimer == 0)
582         {
583           list->htimer = gtk_timeout_add
584             (SCROLL_TIME, (GtkFunction) gtk_list_horizontal_timeout, widget);
585           
586           if (!((x < adj->value && adj->value <= 0) ||
587                 (x > adj->value + adj->page_size &&
588                  adj->value >= adj->upper - adj->page_size)))
589             {
590               gfloat value;
591
592               if (x < adj->value)
593                 value = adj->value + (x - adj->value) / 2 - 1;
594               else
595                 value = adj->value + 1 + (x - adj->value - adj->page_size) / 2;
596
597               gtk_adjustment_set_value (adj,
598                                         CLAMP (value, 0.0,
599                                                adj->upper - adj->page_size));
600             }
601         }
602       else
603         return FALSE;
604     }
605
606   
607   /* vertical autoscrolling */
608   for (work = list->children; work; length++, work = work->next)
609     {
610       if (row < 0)
611         {
612           item = GTK_WIDGET (work->data);
613           if (item->allocation.y > y || 
614               (item->allocation.y <= y &&
615                item->allocation.y + item->allocation.height > y))
616             row = length;
617         }
618
619       if (work->data == container->focus_child)
620         focus_row = length;
621     }
622   
623   if (row < 0)
624     row = length - 1;
625
626   if (list->vtimer != 0)
627     return FALSE;
628
629   if (!((y < 0 && focus_row == 0) ||
630         (y > widget->allocation.height && focus_row >= length - 1)))
631     list->vtimer = gtk_timeout_add (SCROLL_TIME,
632                                     (GtkFunction) gtk_list_vertical_timeout,
633                                     list);
634
635   if (row != focus_row)
636     gtk_widget_grab_focus (item);
637
638   switch (list->selection_mode)
639     {
640     case GTK_SELECTION_BROWSE:
641       gtk_list_select_child (list, item);
642       break;
643     case GTK_SELECTION_EXTENDED:
644       gtk_list_update_extended_selection (list, row);
645       break;
646     default:
647       break;
648     }
649
650   return FALSE;
651 }
652
653 static gint
654 gtk_list_button_press (GtkWidget      *widget,
655                        GdkEventButton *event)
656 {
657   GtkList *list;
658   GtkWidget *item;
659
660   g_return_val_if_fail (widget != NULL, FALSE);
661   g_return_val_if_fail (GTK_IS_LIST (widget), FALSE);
662   g_return_val_if_fail (event != NULL, FALSE);
663
664   if (event->button != 1)
665     return FALSE;
666
667   list = GTK_LIST (widget);
668   item = gtk_get_event_widget ((GdkEvent*) event);
669
670   while (item && !GTK_IS_LIST_ITEM (item))
671     item = item->parent;
672
673   if (item && (item->parent == widget))
674     {
675       gint last_focus_row;
676       gint focus_row;
677
678       if (event->type == GDK_BUTTON_PRESS)
679         {
680           if (gdk_pointer_grab (widget->window, TRUE,
681                                 GDK_POINTER_MOTION_HINT_MASK |
682                                 GDK_BUTTON1_MOTION_MASK |
683                                 GDK_BUTTON_RELEASE_MASK,
684                                 NULL, NULL, event->time))
685             return FALSE;
686           
687           gtk_grab_add (widget);
688           list->drag_selection = TRUE;
689         }
690       else if (gdk_pointer_is_grabbed () && GTK_WIDGET_HAS_GRAB (list))
691         gtk_list_end_drag_selection (list);
692           
693       if (!GTK_WIDGET_HAS_FOCUS(item))
694         gtk_widget_grab_focus (item);
695
696       if (list->add_mode)
697         {
698           list->add_mode = FALSE;
699           gtk_widget_queue_draw (item);
700         }
701       
702       switch (list->selection_mode)
703         {
704         case GTK_SELECTION_SINGLE:
705         case GTK_SELECTION_MULTIPLE:
706           if (event->type != GDK_BUTTON_PRESS)
707             gtk_list_select_child (list, item);
708           else
709             list->undo_focus_child = item;
710           break;
711           
712         case GTK_SELECTION_BROWSE:
713           break;
714
715         case GTK_SELECTION_EXTENDED:
716           focus_row = g_list_index (list->children, item);
717
718           if (list->last_focus_child)
719             last_focus_row = g_list_index (list->children,
720                                            list->last_focus_child);
721           else
722             {
723               last_focus_row = focus_row;
724               list->last_focus_child = item;
725             }
726
727           if (event->type != GDK_BUTTON_PRESS)
728             {
729               if (list->anchor >= 0)
730                 {
731                   gtk_list_update_extended_selection (list, focus_row);
732                   gtk_list_end_selection (list);
733                 }
734               gtk_list_select_child (list, item);
735               break;
736             }
737               
738           if (event->state & GDK_CONTROL_MASK)
739             {
740               if (event->state & GDK_SHIFT_MASK)
741                 {
742                   if (list->anchor < 0)
743                     {
744                       g_list_free (list->undo_selection);
745                       g_list_free (list->undo_unselection);
746                       list->undo_selection = NULL;
747                       list->undo_unselection = NULL;
748
749                       list->anchor = last_focus_row;
750                       list->drag_pos = last_focus_row;
751                       list->undo_focus_child = list->last_focus_child;
752                     }
753                   gtk_list_update_extended_selection (list, focus_row);
754                 }
755               else
756                 {
757                   if (list->anchor < 0)
758                     gtk_list_set_anchor (list, TRUE,
759                                          focus_row, list->last_focus_child);
760                   else
761                     gtk_list_update_extended_selection (list, focus_row);
762                 }
763               break;
764             }
765
766           if (event->state & GDK_SHIFT_MASK)
767             {
768               gtk_list_set_anchor (list, FALSE,
769                                    last_focus_row, list->last_focus_child);
770               gtk_list_update_extended_selection (list, focus_row);
771               break;
772             }
773
774           if (list->anchor < 0)
775             gtk_list_set_anchor (list, FALSE, focus_row,
776                                  list->last_focus_child);
777           else
778             gtk_list_update_extended_selection (list, focus_row);
779           break;
780           
781         default:
782           break;
783         }
784     }
785
786   return FALSE;
787 }
788
789 static gint
790 gtk_list_button_release (GtkWidget      *widget,
791                          GdkEventButton *event)
792 {
793   GtkList *list;
794   GtkWidget *item;
795
796   g_return_val_if_fail (widget != NULL, FALSE);
797   g_return_val_if_fail (GTK_IS_LIST (widget), FALSE);
798   g_return_val_if_fail (event != NULL, FALSE);
799
800   list = GTK_LIST (widget);
801
802   /* we don't handle button 2 and 3 */
803   if (event->button != 1)
804     return FALSE;
805
806   if (list->drag_selection)
807     {
808       gtk_list_end_drag_selection (list);
809
810       switch (list->selection_mode)
811         {
812         case GTK_SELECTION_EXTENDED:
813           if (!(event->state & GDK_SHIFT_MASK))
814             gtk_list_end_selection (list);
815           break;
816
817         case GTK_SELECTION_SINGLE:
818         case GTK_SELECTION_MULTIPLE:
819
820           item = gtk_get_event_widget ((GdkEvent*) event);
821   
822           while (item && !GTK_IS_LIST_ITEM (item))
823             item = item->parent;
824           
825           if (item && item->parent == widget)
826             {
827               if (list->undo_focus_child == item)
828                 gtk_list_toggle_row (list, item);
829             }
830           list->undo_focus_child = NULL;
831           break;
832
833         default:
834           break;
835         }
836     }
837   
838   return FALSE;
839 }
840
841 static void
842 gtk_list_draw (GtkWidget    *widget,
843                GdkRectangle *area)
844 {
845   GtkList *list;
846   GtkWidget *child;
847   GdkRectangle child_area;
848   GList *children;
849
850   g_return_if_fail (widget != NULL);
851   g_return_if_fail (GTK_IS_LIST (widget));
852   g_return_if_fail (area != NULL);
853
854   if (GTK_WIDGET_DRAWABLE (widget))
855     {
856       list = GTK_LIST (widget);
857
858       children = list->children;
859       while (children)
860         {
861           child = children->data;
862           children = children->next;
863
864           if (gtk_widget_intersect (child, area, &child_area))
865             gtk_widget_draw (child, &child_area);
866         }
867     }
868 }
869
870 static gint
871 gtk_list_expose (GtkWidget      *widget,
872                  GdkEventExpose *event)
873 {
874   GtkList *list;
875   GtkWidget *child;
876   GdkEventExpose child_event;
877   GList *children;
878
879   g_return_val_if_fail (widget != NULL, FALSE);
880   g_return_val_if_fail (GTK_IS_LIST (widget), FALSE);
881   g_return_val_if_fail (event != NULL, FALSE);
882
883   if (GTK_WIDGET_DRAWABLE (widget))
884     {
885       list = GTK_LIST (widget);
886
887       child_event = *event;
888
889       children = list->children;
890       while (children)
891         {
892           child = children->data;
893           children = children->next;
894
895           if (GTK_WIDGET_NO_WINDOW (child) &&
896               gtk_widget_intersect (child, &event->area, &child_event.area))
897             gtk_widget_event (child, (GdkEvent*) &child_event);
898         }
899     }
900
901   return FALSE;
902 }
903
904 static void 
905 gtk_list_style_set      (GtkWidget      *widget,
906                          GtkStyle       *previous_style)
907 {
908   g_return_if_fail (widget != NULL);
909
910   if (previous_style && GTK_WIDGET_REALIZED (widget))
911     gdk_window_set_background (widget->window, &widget->style->base[GTK_WIDGET_STATE (widget)]);
912 }
913
914 /* GtkContainer Methods :
915  * gtk_list_add
916  * gtk_list_remove
917  * gtk_list_forall
918  * gtk_list_child_type
919  * gtk_list_set_focus_child
920  * gtk_list_focus
921  */
922 static void
923 gtk_list_add (GtkContainer *container,
924               GtkWidget    *widget)
925 {
926   GList *item_list;
927
928   g_return_if_fail (container != NULL);
929   g_return_if_fail (GTK_IS_LIST (container));
930   g_return_if_fail (widget != NULL);
931   g_return_if_fail (GTK_IS_LIST_ITEM (widget));
932
933   item_list = g_list_alloc ();
934   item_list->data = widget;
935   
936   gtk_list_append_items (GTK_LIST (container), item_list);
937 }
938
939 static void
940 gtk_list_remove (GtkContainer *container,
941                  GtkWidget    *widget)
942 {
943   GList *item_list;
944   
945   g_return_if_fail (container != NULL);
946   g_return_if_fail (GTK_IS_LIST (container));
947   g_return_if_fail (widget != NULL);
948   g_return_if_fail (container == GTK_CONTAINER (widget->parent));
949   
950   item_list = g_list_alloc ();
951   item_list->data = widget;
952   
953   gtk_list_remove_items (GTK_LIST (container), item_list);
954   
955   g_list_free (item_list);
956 }
957
958 static void
959 gtk_list_forall (GtkContainer  *container,
960                  gboolean       include_internals,
961                  GtkCallback    callback,
962                  gpointer       callback_data)
963 {
964   GtkList *list;
965   GtkWidget *child;
966   GList *children;
967
968   g_return_if_fail (container != NULL);
969   g_return_if_fail (GTK_IS_LIST (container));
970   g_return_if_fail (callback != NULL);
971
972   list = GTK_LIST (container);
973   children = list->children;
974
975   while (children)
976     {
977       child = children->data;
978       children = children->next;
979
980       (* callback) (child, callback_data);
981     }
982 }
983
984 static GtkType
985 gtk_list_child_type (GtkContainer *container)
986 {
987   return GTK_TYPE_LIST_ITEM;
988 }
989
990 static void
991 gtk_list_set_focus_child (GtkContainer *container,
992                           GtkWidget    *child)
993 {
994   GtkList *list;
995
996   g_return_if_fail (container != NULL);
997   g_return_if_fail (GTK_IS_LIST (container));
998  
999   if (child)
1000     g_return_if_fail (GTK_IS_WIDGET (child));
1001
1002   list = GTK_LIST (container);
1003
1004   if (child != container->focus_child)
1005     {
1006       if (container->focus_child)
1007         {
1008           list->last_focus_child = container->focus_child;
1009           gtk_widget_unref (container->focus_child);
1010         }
1011       container->focus_child = child;
1012       if (container->focus_child)
1013         gtk_widget_ref (container->focus_child);
1014     }
1015
1016   /* check for v adjustment */
1017   if (container->focus_child)
1018     {
1019       GtkAdjustment *adjustment;
1020
1021       adjustment = gtk_object_get_data_by_id (GTK_OBJECT (container),
1022                                               vadjustment_key_id);
1023       if (adjustment)
1024         gtk_adjustment_clamp_page (adjustment,
1025                                    container->focus_child->allocation.y,
1026                                    (container->focus_child->allocation.y +
1027                                     container->focus_child->allocation.height));
1028       switch (list->selection_mode)
1029         {
1030         case GTK_SELECTION_BROWSE:
1031           gtk_list_select_child (list, child);
1032           break;
1033         case GTK_SELECTION_EXTENDED:
1034           if (!list->last_focus_child && !list->add_mode)
1035             {
1036               list->undo_focus_child = list->last_focus_child;
1037               gtk_list_unselect_all (list);
1038               gtk_list_select_child (list, child);
1039             }
1040           break;
1041         default:
1042           break;
1043         }
1044     }
1045 }
1046
1047 static gint
1048 gtk_list_focus (GtkContainer     *container,
1049                 GtkDirectionType  direction)
1050 {
1051   gint return_val = FALSE;
1052
1053   g_return_val_if_fail (container != NULL, FALSE);
1054   g_return_val_if_fail (GTK_IS_LIST (container), FALSE);
1055
1056   if (container->focus_child == NULL ||
1057       !GTK_WIDGET_HAS_FOCUS (container->focus_child))
1058     {
1059       if (GTK_LIST (container)->last_focus_child)
1060         gtk_container_set_focus_child
1061           (container, GTK_LIST (container)->last_focus_child);
1062
1063       if (GTK_CONTAINER_CLASS (parent_class)->focus)
1064         return_val = GTK_CONTAINER_CLASS (parent_class)->focus (container,
1065                                                                 direction);
1066     }
1067
1068   if (!return_val)
1069     {
1070       GtkList *list;
1071
1072       list =  GTK_LIST (container);
1073       if (list->selection_mode == GTK_SELECTION_EXTENDED && list->anchor >= 0)
1074         gtk_list_end_selection (list);
1075
1076       if (container->focus_child)
1077         list->last_focus_child = container->focus_child;
1078     }
1079
1080   return return_val;
1081 }
1082
1083
1084 /* Public GtkList Methods :
1085  *
1086  * gtk_list_insert_items
1087  * gtk_list_append_items
1088  * gtk_list_prepend_items
1089  * gtk_list_remove_items
1090  * gtk_list_remove_items_no_unref
1091  * gtk_list_clear_items
1092  *
1093  * gtk_list_child_position
1094  */
1095 void
1096 gtk_list_insert_items (GtkList *list,
1097                        GList   *items,
1098                        gint     position)
1099 {
1100   GtkWidget *widget;
1101   GList *tmp_list;
1102   GList *last;
1103   gint nchildren;
1104
1105   g_return_if_fail (list != NULL);
1106   g_return_if_fail (GTK_IS_LIST (list));
1107
1108   if (!items)
1109     return;
1110
1111   gtk_list_end_drag_selection (list);
1112   if (list->selection_mode == GTK_SELECTION_EXTENDED && list->anchor >= 0)
1113     gtk_list_end_selection (list);
1114
1115   tmp_list = items;
1116   while (tmp_list)
1117     {
1118       widget = tmp_list->data;
1119       tmp_list = tmp_list->next;
1120
1121       gtk_widget_set_parent (widget, GTK_WIDGET (list));
1122       gtk_signal_connect (GTK_OBJECT (widget), "drag_begin",
1123                           GTK_SIGNAL_FUNC (gtk_list_signal_drag_begin),
1124                           list);
1125       gtk_signal_connect (GTK_OBJECT (widget), "toggle_focus_row",
1126                           GTK_SIGNAL_FUNC (gtk_list_signal_toggle_focus_row),
1127                           list);
1128       gtk_signal_connect (GTK_OBJECT (widget), "select_all",
1129                           GTK_SIGNAL_FUNC (gtk_list_signal_select_all),
1130                           list);
1131       gtk_signal_connect (GTK_OBJECT (widget), "unselect_all",
1132                           GTK_SIGNAL_FUNC (gtk_list_signal_unselect_all),
1133                           list);
1134       gtk_signal_connect (GTK_OBJECT (widget), "undo_selection",
1135                           GTK_SIGNAL_FUNC (gtk_list_signal_undo_selection),
1136                           list);
1137       gtk_signal_connect (GTK_OBJECT (widget), "start_selection",
1138                           GTK_SIGNAL_FUNC (gtk_list_signal_start_selection),
1139                           list);
1140       gtk_signal_connect (GTK_OBJECT (widget), "end_selection",
1141                           GTK_SIGNAL_FUNC (gtk_list_signal_end_selection),
1142                           list);
1143       gtk_signal_connect (GTK_OBJECT (widget), "extend_selection",
1144                           GTK_SIGNAL_FUNC (gtk_list_signal_extend_selection),
1145                           list);
1146       gtk_signal_connect (GTK_OBJECT (widget), "scroll_horizontal",
1147                           GTK_SIGNAL_FUNC (gtk_list_signal_scroll_horizontal),
1148                           list);
1149       gtk_signal_connect (GTK_OBJECT (widget), "scroll_vertical",
1150                           GTK_SIGNAL_FUNC (gtk_list_signal_scroll_vertical),
1151                           list);
1152       gtk_signal_connect (GTK_OBJECT (widget), "toggle_add_mode",
1153                           GTK_SIGNAL_FUNC (gtk_list_signal_toggle_add_mode),
1154                           list);
1155       gtk_signal_connect (GTK_OBJECT (widget), "select",
1156                           GTK_SIGNAL_FUNC (gtk_list_signal_item_select),
1157                           list);
1158       gtk_signal_connect (GTK_OBJECT (widget), "deselect",
1159                           GTK_SIGNAL_FUNC (gtk_list_signal_item_deselect),
1160                           list);
1161       gtk_signal_connect (GTK_OBJECT (widget), "toggle",
1162                           GTK_SIGNAL_FUNC (gtk_list_signal_item_toggle),
1163                           list);
1164
1165       if (GTK_WIDGET_REALIZED (widget->parent))
1166         gtk_widget_realize (widget);
1167
1168       if (GTK_WIDGET_VISIBLE (widget->parent) && GTK_WIDGET_VISIBLE (widget))
1169         {
1170           if (GTK_WIDGET_MAPPED (widget->parent))
1171             gtk_widget_map (widget);
1172
1173           gtk_widget_queue_resize (widget);
1174         }
1175     }
1176
1177
1178   nchildren = g_list_length (list->children);
1179   if ((position < 0) || (position > nchildren))
1180     position = nchildren;
1181
1182   if (position == nchildren)
1183     {
1184       if (list->children)
1185         {
1186           tmp_list = g_list_last (list->children);
1187           tmp_list->next = items;
1188           items->prev = tmp_list;
1189         }
1190       else
1191         {
1192           list->children = items;
1193         }
1194     }
1195   else
1196     {
1197       tmp_list = g_list_nth (list->children, position);
1198       last = g_list_last (items);
1199
1200       if (tmp_list->prev)
1201         tmp_list->prev->next = items;
1202       last->next = tmp_list;
1203       items->prev = tmp_list->prev;
1204       tmp_list->prev = last;
1205
1206       if (tmp_list == list->children)
1207         list->children = items;
1208     }
1209   
1210   if (list->children && !list->selection &&
1211       (list->selection_mode == GTK_SELECTION_BROWSE))
1212     {
1213       widget = list->children->data;
1214       gtk_list_select_child (list, widget);
1215     }
1216 }
1217
1218 void
1219 gtk_list_append_items (GtkList *list,
1220                        GList   *items)
1221 {
1222   g_return_if_fail (list != NULL);
1223   g_return_if_fail (GTK_IS_LIST (list));
1224
1225   gtk_list_insert_items (list, items, -1);
1226 }
1227
1228 void
1229 gtk_list_prepend_items (GtkList *list,
1230                         GList   *items)
1231 {
1232   g_return_if_fail (list != NULL);
1233   g_return_if_fail (GTK_IS_LIST (list));
1234
1235   gtk_list_insert_items (list, items, 0);
1236 }
1237
1238 void
1239 gtk_list_remove_items (GtkList  *list,
1240                        GList    *items)
1241 {
1242   gtk_list_remove_items_internal (list, items, FALSE);
1243 }
1244
1245 void
1246 gtk_list_remove_items_no_unref (GtkList  *list,
1247                                 GList    *items)
1248 {
1249   gtk_list_remove_items_internal (list, items, TRUE);
1250 }
1251
1252 void
1253 gtk_list_clear_items (GtkList *list,
1254                       gint     start,
1255                       gint     end)
1256 {
1257   GtkContainer *container;
1258   GtkWidget *widget;
1259   GtkWidget *new_focus_child = NULL;
1260   GList *start_list;
1261   GList *end_list;
1262   GList *tmp_list;
1263   guint nchildren;
1264   gboolean grab_focus = FALSE;
1265
1266   g_return_if_fail (list != NULL);
1267   g_return_if_fail (GTK_IS_LIST (list));
1268
1269   nchildren = g_list_length (list->children);
1270
1271   if (nchildren == 0)
1272     return;
1273
1274   if ((end < 0) || (end > nchildren))
1275     end = nchildren;
1276
1277   if (start >= end)
1278     return;
1279
1280   container = GTK_CONTAINER (list);
1281
1282   gtk_list_end_drag_selection (list);
1283   if (list->selection_mode == GTK_SELECTION_EXTENDED)
1284     {
1285       if (list->anchor >= 0)
1286         gtk_list_end_selection (list);
1287
1288       gtk_list_reset_extended_selection (list);
1289     }
1290
1291   start_list = g_list_nth (list->children, start);
1292   end_list = g_list_nth (list->children, end);
1293
1294   if (start_list->prev)
1295     start_list->prev->next = end_list;
1296   if (end_list && end_list->prev)
1297     end_list->prev->next = NULL;
1298   if (end_list)
1299     end_list->prev = start_list->prev;
1300   if (start_list == list->children)
1301     list->children = end_list;
1302
1303   if (container->focus_child)
1304     {
1305       if (g_list_find (start_list, container->focus_child))
1306         {
1307           if (start_list->prev)
1308             new_focus_child = start_list->prev->data;
1309           else if (list->children)
1310             new_focus_child = list->children->prev->data;
1311
1312           if (GTK_WIDGET_HAS_FOCUS (container->focus_child))
1313             grab_focus = TRUE;
1314         }
1315     }
1316
1317   tmp_list = start_list;
1318   while (tmp_list)
1319     {
1320       widget = tmp_list->data;
1321       tmp_list = tmp_list->next;
1322
1323       if (widget->state == GTK_STATE_SELECTED)
1324         gtk_list_unselect_child (list, widget);
1325
1326       if (widget == list->undo_focus_child)
1327         list->undo_focus_child = NULL;
1328       if (widget == list->last_focus_child)
1329         list->last_focus_child = NULL;
1330
1331       gtk_signal_disconnect_by_data (GTK_OBJECT (widget), (gpointer) list);
1332       gtk_widget_unparent (widget);
1333     }
1334
1335   g_list_free (start_list);
1336
1337   if (new_focus_child)
1338     {
1339       if (grab_focus)
1340         gtk_widget_grab_focus (new_focus_child);
1341       else if (container->focus_child)
1342         gtk_container_set_focus_child (container, new_focus_child);
1343
1344       if ((list->selection_mode == GTK_SELECTION_BROWSE ||
1345            list->selection_mode == GTK_SELECTION_EXTENDED) && !list->selection)
1346         {
1347           list->last_focus_child = new_focus_child; 
1348           gtk_list_select_child (list, new_focus_child);
1349         }
1350     }
1351
1352   if (GTK_WIDGET_VISIBLE (list))
1353     gtk_widget_queue_resize (GTK_WIDGET (list));
1354 }
1355
1356 gint
1357 gtk_list_child_position (GtkList   *list,
1358                          GtkWidget *child)
1359 {
1360   GList *children;
1361   gint pos;
1362
1363   g_return_val_if_fail (list != NULL, -1);
1364   g_return_val_if_fail (GTK_IS_LIST (list), -1);
1365   g_return_val_if_fail (child != NULL, -1);
1366
1367   pos = 0;
1368   children = list->children;
1369
1370   while (children)
1371     {
1372       if (child == GTK_WIDGET (children->data))
1373         return pos;
1374
1375       pos += 1;
1376       children = children->next;
1377     }
1378
1379   return -1;
1380 }
1381
1382
1383 /* Private GtkList Insert/Remove Item Functions:
1384  *
1385  * gtk_list_remove_items_internal
1386  */
1387 static void
1388 gtk_list_remove_items_internal (GtkList  *list,
1389                                 GList    *items,
1390                                 gboolean  no_unref)
1391 {
1392   GtkWidget *widget;
1393   GtkWidget *new_focus_child;
1394   GtkWidget *old_focus_child;
1395   GtkContainer *container;
1396   GList *tmp_list;
1397   GList *work;
1398   gboolean grab_focus = FALSE;
1399   
1400   g_return_if_fail (list != NULL);
1401   g_return_if_fail (GTK_IS_LIST (list));
1402
1403   if (!items)
1404     return;
1405   
1406   container = GTK_CONTAINER (list);
1407
1408   gtk_list_end_drag_selection (list);
1409   if (list->selection_mode == GTK_SELECTION_EXTENDED)
1410     {
1411       if (list->anchor >= 0)
1412         gtk_list_end_selection (list);
1413
1414       gtk_list_reset_extended_selection (list);
1415     }
1416
1417   tmp_list = items;
1418   while (tmp_list)
1419     {
1420       widget = tmp_list->data;
1421       tmp_list = tmp_list->next;
1422       
1423       if (widget->state == GTK_STATE_SELECTED)
1424         gtk_list_unselect_child (list, widget);
1425     }
1426
1427   if (container->focus_child)
1428     {
1429       old_focus_child = new_focus_child = container->focus_child;
1430       if (GTK_WIDGET_HAS_FOCUS (container->focus_child))
1431         grab_focus = TRUE;
1432     }
1433   else
1434     old_focus_child = new_focus_child = list->last_focus_child;
1435
1436   tmp_list = items;
1437   while (tmp_list)
1438     {
1439       widget = tmp_list->data;
1440       tmp_list = tmp_list->next;
1441
1442       if (no_unref)
1443         gtk_widget_ref (widget);
1444
1445       if (widget == new_focus_child) 
1446         {
1447           work = g_list_find (list->children, widget);
1448
1449           if (work)
1450             {
1451               if (work->next)
1452                 new_focus_child = work->next->data;
1453               else if (list->children != work && work->prev)
1454                 new_focus_child = work->prev->data;
1455               else
1456                 new_focus_child = NULL;
1457             }
1458         }
1459
1460       if (widget == list->undo_focus_child)
1461         list->undo_focus_child = NULL;
1462       if (widget == list->last_focus_child)
1463         list->last_focus_child = NULL;
1464
1465       gtk_signal_disconnect_by_data (GTK_OBJECT (widget), (gpointer) list);
1466       list->children = g_list_remove (list->children, widget);
1467       gtk_widget_unparent (widget);
1468     }
1469   
1470   if (new_focus_child && new_focus_child != old_focus_child)
1471     {
1472       if (grab_focus)
1473         gtk_widget_grab_focus (new_focus_child);
1474       else if (container->focus_child)
1475         gtk_container_set_focus_child (container, new_focus_child);
1476
1477       if (list->selection_mode == GTK_SELECTION_BROWSE && !list->selection)
1478         {
1479           list->last_focus_child = new_focus_child; 
1480           gtk_list_select_child (list, new_focus_child);
1481         }
1482     }
1483
1484   if (GTK_WIDGET_VISIBLE (list))
1485     gtk_widget_queue_resize (GTK_WIDGET (list));
1486 }
1487
1488
1489 /* Public GtkList Selection Methods :
1490  *
1491  * gtk_list_set_selection_mode
1492  * gtk_list_select_item
1493  * gtk_list_unselect_item
1494  * gtk_list_select_child
1495  * gtk_list_unselect_child
1496  * gtk_list_select_all
1497  * gtk_list_unselect_all
1498  * gtk_list_extend_selection
1499  * gtk_list_end_drag_selection
1500  * gtk_list_start_selection
1501  * gtk_list_end_selection
1502  * gtk_list_toggle_row
1503  * gtk_list_toggle_focus_row
1504  * gtk_list_toggle_add_mode
1505  * gtk_list_undo_selection
1506  */
1507 void
1508 gtk_list_set_selection_mode (GtkList          *list,
1509                              GtkSelectionMode  mode)
1510 {
1511   g_return_if_fail (list != NULL);
1512   g_return_if_fail (GTK_IS_LIST (list));
1513
1514   if (list->selection_mode == mode)
1515     return;
1516
1517   list->selection_mode = mode;
1518
1519   switch (mode)
1520     {
1521     case GTK_SELECTION_SINGLE:
1522     case GTK_SELECTION_BROWSE:
1523       gtk_list_unselect_all (list);
1524       break;
1525     default:
1526       break;
1527     }
1528 }
1529
1530 void
1531 gtk_list_select_item (GtkList *list,
1532                       gint     item)
1533 {
1534   GList *tmp_list;
1535
1536   g_return_if_fail (list != NULL);
1537   g_return_if_fail (GTK_IS_LIST (list));
1538
1539   tmp_list = g_list_nth (list->children, item);
1540   if (tmp_list)
1541     gtk_list_select_child (list, GTK_WIDGET (tmp_list->data));
1542 }
1543
1544 void
1545 gtk_list_unselect_item (GtkList *list,
1546                         gint     item)
1547 {
1548   GList *tmp_list;
1549
1550   g_return_if_fail (list != NULL);
1551   g_return_if_fail (GTK_IS_LIST (list));
1552
1553   tmp_list = g_list_nth (list->children, item);
1554   if (tmp_list)
1555     gtk_list_unselect_child (list, GTK_WIDGET (tmp_list->data));
1556 }
1557
1558 void
1559 gtk_list_select_child (GtkList   *list,
1560                        GtkWidget *child)
1561 {
1562   gtk_signal_emit (GTK_OBJECT (list), list_signals[SELECT_CHILD], child);
1563 }
1564
1565 void
1566 gtk_list_unselect_child (GtkList   *list,
1567                          GtkWidget *child)
1568 {
1569   gtk_signal_emit (GTK_OBJECT (list), list_signals[UNSELECT_CHILD], child);
1570 }
1571
1572 void
1573 gtk_list_select_all (GtkList *list)
1574 {
1575   GtkContainer *container;
1576   GList *work;
1577  
1578   g_return_if_fail (list != NULL);
1579   g_return_if_fail (GTK_IS_LIST (list));
1580
1581   if (!list->children)
1582     return;
1583   
1584   if (gdk_pointer_is_grabbed () && GTK_WIDGET_HAS_GRAB (list))
1585     gtk_list_end_drag_selection (list);
1586
1587   if (list->selection_mode == GTK_SELECTION_EXTENDED && list->anchor >= 0)
1588     gtk_list_end_selection (list);
1589
1590   container = GTK_CONTAINER (list);
1591
1592   switch (list->selection_mode)
1593     {
1594     case GTK_SELECTION_BROWSE:
1595       if (container->focus_child)
1596         {
1597           gtk_list_select_child (list, container->focus_child);
1598           return;
1599         }
1600       break;
1601     case GTK_SELECTION_EXTENDED:
1602       g_list_free (list->undo_selection);
1603       g_list_free (list->undo_unselection);
1604       list->undo_selection = NULL;
1605       list->undo_unselection = NULL;
1606
1607       if (list->children &&
1608           GTK_WIDGET_STATE (list->children->data) != GTK_STATE_SELECTED)
1609         gtk_list_fake_toggle_row (list, GTK_WIDGET (list->children->data));
1610
1611       list->anchor_state =  GTK_STATE_SELECTED;
1612       list->anchor = 0;
1613       list->drag_pos = 0;
1614       list->undo_focus_child = container->focus_child;
1615       gtk_list_update_extended_selection (list, g_list_length(list->children));
1616       gtk_list_end_selection (list);
1617       return;
1618     case GTK_SELECTION_MULTIPLE:
1619       for (work = list->children; work; work = work->next)
1620         {
1621           if (GTK_WIDGET_STATE (work->data) == GTK_STATE_NORMAL)
1622             gtk_list_select_child (list, GTK_WIDGET (work->data));
1623         }
1624       return;
1625     default:
1626       break;
1627     }
1628 }
1629
1630 void
1631 gtk_list_unselect_all (GtkList *list)
1632 {
1633   GtkContainer *container;
1634   GtkWidget *item;
1635   GList *work;
1636  
1637   g_return_if_fail (list != NULL);
1638   g_return_if_fail (GTK_IS_LIST (list));
1639
1640   if (!list->children)
1641     return;
1642
1643   if (gdk_pointer_is_grabbed () && GTK_WIDGET_HAS_GRAB (list))
1644     gtk_list_end_drag_selection (list);
1645
1646   if (list->selection_mode == GTK_SELECTION_EXTENDED && list->anchor >= 0)
1647     gtk_list_end_selection (list);
1648
1649   container = GTK_CONTAINER (list);
1650
1651   switch (list->selection_mode)
1652     {
1653     case GTK_SELECTION_BROWSE:
1654       if (container->focus_child)
1655         {
1656           gtk_list_select_child (list, container->focus_child);
1657           return;
1658         }
1659       break;
1660     case GTK_SELECTION_EXTENDED:
1661       gtk_list_reset_extended_selection (list);
1662       break;
1663     default:
1664       break;
1665     }
1666
1667   work = list->selection;
1668
1669   while (work)
1670     {
1671       item = work->data;
1672       work = work->next;
1673       gtk_list_unselect_child (list, item);
1674     }
1675 }
1676
1677 void
1678 gtk_list_extend_selection (GtkList       *list,
1679                            GtkScrollType  scroll_type,
1680                            gfloat         position,
1681                            gboolean       auto_start_selection)
1682 {
1683   GtkContainer *container;
1684
1685   g_return_if_fail (list != NULL);
1686   g_return_if_fail (GTK_IS_LIST (list));
1687
1688   if ((gdk_pointer_is_grabbed () && GTK_WIDGET_HAS_GRAB (list)) ||
1689       list->selection_mode != GTK_SELECTION_EXTENDED)
1690     return;
1691
1692   container = GTK_CONTAINER (list);
1693
1694   if (auto_start_selection)
1695     {
1696       gint focus_row;
1697
1698       focus_row = g_list_index (list->children, container->focus_child);
1699       gtk_list_set_anchor (list, list->add_mode, focus_row,
1700                            container->focus_child);
1701     }
1702   else if (list->anchor < 0)
1703     return;
1704
1705   gtk_list_move_focus_child (list, scroll_type, position);
1706   gtk_list_update_extended_selection 
1707     (list, g_list_index (list->children, container->focus_child));
1708 }
1709
1710 void
1711 gtk_list_end_drag_selection (GtkList *list)
1712 {
1713   g_return_if_fail (list != NULL);
1714   g_return_if_fail (GTK_IS_LIST (list));
1715
1716   list->drag_selection = FALSE;
1717   if (GTK_WIDGET_HAS_GRAB (list))
1718     {
1719       gtk_grab_remove (GTK_WIDGET (list));
1720       if (gdk_pointer_is_grabbed())
1721         gdk_pointer_ungrab (GDK_CURRENT_TIME);
1722     }
1723   if (list->htimer)
1724     {
1725       gtk_timeout_remove (list->htimer);
1726       list->htimer = 0;
1727     }
1728   if (list->vtimer)
1729     {
1730       gtk_timeout_remove (list->vtimer);
1731       list->vtimer = 0;
1732     }
1733 }
1734
1735 void
1736 gtk_list_start_selection (GtkList *list)
1737 {
1738   GtkContainer *container;
1739   gint focus_row;
1740
1741   g_return_if_fail (list != NULL);
1742   g_return_if_fail (GTK_IS_LIST (list));
1743
1744   if (gdk_pointer_is_grabbed () && GTK_WIDGET_HAS_GRAB (list))
1745     return;
1746
1747   container = GTK_CONTAINER (list);
1748
1749   if ((focus_row = g_list_index (list->selection, container->focus_child))
1750       >= 0)
1751     gtk_list_set_anchor (list, list->add_mode,
1752                          focus_row, container->focus_child);
1753 }
1754
1755 void
1756 gtk_list_end_selection (GtkList *list)
1757 {
1758   gint i;
1759   gint e;
1760   gboolean top_down;
1761   GList *work;
1762   GtkWidget *item;
1763   gint item_index;
1764
1765   g_return_if_fail (list != NULL);
1766   g_return_if_fail (GTK_IS_LIST (list));
1767
1768   if ((gdk_pointer_is_grabbed () && GTK_WIDGET_HAS_GRAB (list)) ||
1769       list->anchor < 0)
1770     return;
1771
1772   i = MIN (list->anchor, list->drag_pos);
1773   e = MAX (list->anchor, list->drag_pos);
1774
1775   top_down = (list->anchor < list->drag_pos);
1776
1777   list->anchor = -1;
1778   list->drag_pos = -1;
1779   
1780   if (list->undo_selection)
1781     {
1782       work = list->selection;
1783       list->selection = list->undo_selection;
1784       list->undo_selection = work;
1785       work = list->selection;
1786       while (work)
1787         {
1788           item = work->data;
1789           work = work->next;
1790           item_index = g_list_index (list->children, item);
1791           if (item_index < i || item_index > e)
1792             {
1793               gtk_widget_set_state (item, GTK_STATE_SELECTED);
1794               gtk_list_unselect_child (list, item);
1795               list->undo_selection = g_list_prepend (list->undo_selection,
1796                                                      item);
1797             }
1798         }
1799     }    
1800
1801   if (top_down)
1802     {
1803       for (work = g_list_nth (list->children, i); i <= e;
1804            i++, work = work->next)
1805         {
1806           item = work->data;
1807           if (g_list_find (list->selection, item))
1808             {
1809               if (item->state == GTK_STATE_NORMAL)
1810                 {
1811                   gtk_widget_set_state (item, GTK_STATE_SELECTED);
1812                   gtk_list_unselect_child (list, item);
1813                   list->undo_selection = g_list_prepend (list->undo_selection,
1814                                                          item);
1815                 }
1816             }
1817           else if (item->state == GTK_STATE_SELECTED)
1818             {
1819               gtk_widget_set_state (item, GTK_STATE_NORMAL);
1820               list->undo_unselection = g_list_prepend (list->undo_unselection,
1821                                                        item);
1822             }
1823         }
1824     }
1825   else
1826     {
1827       for (work = g_list_nth (list->children, e); i <= e;
1828            e--, work = work->prev)
1829         {
1830           item = work->data;
1831           if (g_list_find (list->selection, item))
1832             {
1833               if (item->state == GTK_STATE_NORMAL)
1834                 {
1835                   gtk_widget_set_state (item, GTK_STATE_SELECTED);
1836                   gtk_list_unselect_child (list, item);
1837                   list->undo_selection = g_list_prepend (list->undo_selection,
1838                                                          item);
1839                 }
1840             }
1841           else if (item->state == GTK_STATE_SELECTED)
1842             {
1843               gtk_widget_set_state (item, GTK_STATE_NORMAL);
1844               list->undo_unselection = g_list_prepend (list->undo_unselection,
1845                                                        item);
1846             }
1847         }
1848     }
1849
1850   for (work = g_list_reverse (list->undo_unselection); work; work = work->next)
1851     gtk_list_select_child (list, GTK_WIDGET (work->data));
1852
1853
1854 }
1855
1856 void
1857 gtk_list_toggle_row (GtkList   *list,
1858                      GtkWidget *item)
1859 {
1860   g_return_if_fail (list != NULL);
1861   g_return_if_fail (GTK_IS_LIST (list));
1862   g_return_if_fail (item != NULL);
1863   g_return_if_fail (GTK_IS_LIST_ITEM (item));
1864
1865   switch (list->selection_mode)
1866     {
1867     case GTK_SELECTION_EXTENDED:
1868     case GTK_SELECTION_MULTIPLE:
1869     case GTK_SELECTION_SINGLE:
1870       if (item->state == GTK_STATE_SELECTED)
1871         {
1872           gtk_list_unselect_child (list, item);
1873           return;
1874         }
1875     case GTK_SELECTION_BROWSE:
1876       gtk_list_select_child (list, item);
1877       break;
1878     }
1879 }
1880
1881 void
1882 gtk_list_toggle_focus_row (GtkList *list)
1883 {
1884   GtkContainer *container;
1885   gint focus_row;
1886
1887   g_return_if_fail (list != 0);
1888   g_return_if_fail (GTK_IS_LIST (list));
1889
1890   container = GTK_CONTAINER (list);
1891
1892   if ((gdk_pointer_is_grabbed () && GTK_WIDGET_HAS_GRAB (list)) ||
1893       !container->focus_child)
1894     return;
1895
1896   switch (list->selection_mode)
1897     {
1898     case  GTK_SELECTION_SINGLE:
1899     case  GTK_SELECTION_MULTIPLE:
1900       gtk_list_toggle_row (list, container->focus_child);
1901       break;
1902     case GTK_SELECTION_EXTENDED:
1903       if ((focus_row = g_list_index (list->children, container->focus_child))
1904           < 0)
1905         return;
1906
1907       g_list_free (list->undo_selection);
1908       g_list_free (list->undo_unselection);
1909       list->undo_selection = NULL;
1910       list->undo_unselection = NULL;
1911
1912       list->anchor = focus_row;
1913       list->drag_pos = focus_row;
1914       list->undo_focus_child = container->focus_child;
1915
1916       if (list->add_mode)
1917         gtk_list_fake_toggle_row (list, container->focus_child);
1918       else
1919         gtk_list_fake_unselect_all (list, container->focus_child);
1920       
1921       gtk_list_end_selection (list);
1922       break;
1923     default:
1924       break;
1925     }
1926 }
1927
1928 void
1929 gtk_list_toggle_add_mode (GtkList *list)
1930 {
1931   GtkContainer *container;
1932
1933   g_return_if_fail (list != 0);
1934   g_return_if_fail (GTK_IS_LIST (list));
1935   
1936   if ((gdk_pointer_is_grabbed () && GTK_WIDGET_HAS_GRAB (list)) ||
1937       list->selection_mode != GTK_SELECTION_EXTENDED)
1938     return;
1939   
1940   container = GTK_CONTAINER (list);
1941
1942   if (list->add_mode)
1943     {
1944       list->add_mode = FALSE;
1945       list->anchor_state = GTK_STATE_SELECTED;
1946     }
1947   else
1948     list->add_mode = TRUE;
1949   
1950   if (container->focus_child)
1951     gtk_widget_queue_draw (container->focus_child);
1952 }
1953
1954 void
1955 gtk_list_undo_selection (GtkList *list)
1956 {
1957   GList *work;
1958
1959   g_return_if_fail (list != NULL);
1960   g_return_if_fail (GTK_IS_LIST (list));
1961
1962   if (list->selection_mode != GTK_SELECTION_EXTENDED ||
1963       (gdk_pointer_is_grabbed () && GTK_WIDGET_HAS_GRAB (list)))
1964     return;
1965   
1966   if (list->anchor >= 0)
1967     gtk_list_end_selection (list);
1968
1969   if (!(list->undo_selection || list->undo_unselection))
1970     {
1971       gtk_list_unselect_all (list);
1972       return;
1973     }
1974
1975   for (work = list->undo_selection; work; work = work->next)
1976     gtk_list_select_child (list, GTK_WIDGET (work->data));
1977
1978   for (work = list->undo_unselection; work; work = work->next)
1979     gtk_list_unselect_child (list, GTK_WIDGET (work->data));
1980
1981   if (list->undo_focus_child)
1982     {
1983       GtkContainer *container;
1984
1985       container = GTK_CONTAINER (list);
1986
1987       if (container->focus_child &&
1988           GTK_WIDGET_HAS_FOCUS (container->focus_child))
1989         gtk_widget_grab_focus (list->undo_focus_child);
1990       else
1991         gtk_container_set_focus_child (container, list->undo_focus_child);
1992     }
1993
1994   list->undo_focus_child = NULL;
1995  
1996   g_list_free (list->undo_selection);
1997   g_list_free (list->undo_unselection);
1998   list->undo_selection = NULL;
1999   list->undo_unselection = NULL;
2000 }
2001
2002
2003 /* Private GtkList Selection Methods :
2004  *
2005  * gtk_real_list_select_child
2006  * gtk_real_list_unselect_child
2007  */
2008 static void
2009 gtk_real_list_select_child (GtkList   *list,
2010                             GtkWidget *child)
2011 {
2012   g_return_if_fail (list != NULL);
2013   g_return_if_fail (GTK_IS_LIST (list));
2014   g_return_if_fail (child != NULL);
2015   g_return_if_fail (GTK_IS_LIST_ITEM (child));
2016
2017   switch (child->state)
2018     {
2019     case GTK_STATE_SELECTED:
2020     case GTK_STATE_INSENSITIVE:
2021       break;
2022     default:
2023       gtk_list_item_select (GTK_LIST_ITEM (child));
2024       break;
2025     }
2026 }
2027
2028 static void
2029 gtk_real_list_unselect_child (GtkList   *list,
2030                               GtkWidget *child)
2031 {
2032   g_return_if_fail (list != NULL);
2033   g_return_if_fail (GTK_IS_LIST (list));
2034   g_return_if_fail (child != NULL);
2035   g_return_if_fail (GTK_IS_LIST_ITEM (child));
2036
2037   if (child->state == GTK_STATE_SELECTED)
2038     gtk_list_item_deselect (GTK_LIST_ITEM (child));
2039 }
2040
2041
2042 /* Private GtkList Selection Functions :
2043  *
2044  * gtk_list_set_anchor
2045  * gtk_list_fake_unselect_all
2046  * gtk_list_fake_toggle_row
2047  * gtk_list_update_extended_selection
2048  * gtk_list_reset_extended_selection
2049  */
2050 static void
2051 gtk_list_set_anchor (GtkList   *list,
2052                      gboolean   add_mode,
2053                      gint       anchor,
2054                      GtkWidget *undo_focus_child)
2055 {
2056   GList *work;
2057
2058   g_return_if_fail (list != NULL);
2059   g_return_if_fail (GTK_IS_LIST (list));
2060   
2061   if (list->selection_mode != GTK_SELECTION_EXTENDED || list->anchor >= 0)
2062     return;
2063
2064   g_list_free (list->undo_selection);
2065   g_list_free (list->undo_unselection);
2066   list->undo_selection = NULL;
2067   list->undo_unselection = NULL;
2068
2069   if ((work = g_list_nth (list->children, anchor)))
2070     {
2071       if (add_mode)
2072         gtk_list_fake_toggle_row (list, GTK_WIDGET (work->data));
2073       else
2074         {
2075           gtk_list_fake_unselect_all (list, GTK_WIDGET (work->data));
2076           list->anchor_state = GTK_STATE_SELECTED;
2077         }
2078     }
2079
2080   list->anchor = anchor;
2081   list->drag_pos = anchor;
2082   list->undo_focus_child = undo_focus_child;
2083 }
2084
2085 static void
2086 gtk_list_fake_unselect_all (GtkList   *list,
2087                             GtkWidget *item)
2088 {
2089   GList *work;
2090
2091   if (item && item->state == GTK_STATE_NORMAL)
2092     gtk_widget_set_state (item, GTK_STATE_SELECTED);
2093
2094   list->undo_selection = list->selection;
2095   list->selection = NULL;
2096   
2097   for (work = list->undo_selection; work; work = work->next)
2098     if (work->data != item)
2099       gtk_widget_set_state (GTK_WIDGET (work->data), GTK_STATE_NORMAL);
2100 }
2101
2102 static void
2103 gtk_list_fake_toggle_row (GtkList   *list,
2104                           GtkWidget *item)
2105 {
2106   if (!item)
2107     return;
2108   
2109   if (item->state == GTK_STATE_NORMAL)
2110     {
2111       list->anchor_state = GTK_STATE_SELECTED;
2112       gtk_widget_set_state (item, GTK_STATE_SELECTED);
2113     }
2114   else
2115     {
2116       list->anchor_state = GTK_STATE_NORMAL;
2117       gtk_widget_set_state (item, GTK_STATE_NORMAL);
2118     }
2119 }
2120
2121 static void
2122 gtk_list_update_extended_selection (GtkList *list,
2123                                     gint     row)
2124 {
2125   gint i;
2126   GList *work;
2127   gint s1 = -1;
2128   gint s2 = -1;
2129   gint e1 = -1;
2130   gint e2 = -1;
2131   gint length;
2132
2133   if (row < 0)
2134     row = 0;
2135
2136   length = g_list_length (list->children);
2137   if (row >= length)
2138     row = length - 1;
2139
2140   if (list->selection_mode != GTK_SELECTION_EXTENDED || !list->anchor < 0)
2141     return;
2142
2143   /* extending downwards */
2144   if (row > list->drag_pos && list->anchor <= list->drag_pos)
2145     {
2146       s2 = list->drag_pos + 1;
2147       e2 = row;
2148     }
2149   /* extending upwards */
2150   else if (row < list->drag_pos && list->anchor >= list->drag_pos)
2151     {
2152       s2 = row;
2153       e2 = list->drag_pos - 1;
2154     }
2155   else if (row < list->drag_pos && list->anchor < list->drag_pos)
2156     {
2157       e1 = list->drag_pos;
2158       /* row and drag_pos on different sides of anchor :
2159          take back the selection between anchor and drag_pos,
2160          select between anchor and row */
2161       if (row < list->anchor)
2162         {
2163           s1 = list->anchor + 1;
2164           s2 = row;
2165           e2 = list->anchor - 1;
2166         }
2167       /* take back the selection between anchor and drag_pos */
2168       else
2169         s1 = row + 1;
2170     }
2171   else if (row > list->drag_pos && list->anchor > list->drag_pos)
2172     {
2173       s1 = list->drag_pos;
2174       /* row and drag_pos on different sides of anchor :
2175          take back the selection between anchor and drag_pos,
2176          select between anchor and row */
2177       if (row > list->anchor)
2178         {
2179           e1 = list->anchor - 1;
2180           s2 = list->anchor + 1;
2181           e2 = row;
2182         }
2183       /* take back the selection between anchor and drag_pos */
2184       else
2185         e1 = row - 1;
2186     }
2187
2188   list->drag_pos = row;
2189
2190   /* restore the elements between s1 and e1 */
2191   if (s1 >= 0)
2192     {
2193       for (i = s1, work = g_list_nth (list->children, i); i <= e1;
2194            i++, work = work->next)
2195         {
2196           if (g_list_find (list->selection, work->data))
2197             gtk_widget_set_state (GTK_WIDGET (work->data), GTK_STATE_SELECTED);
2198           else
2199             gtk_widget_set_state (GTK_WIDGET (work->data), GTK_STATE_NORMAL);
2200         }
2201     }
2202
2203   /* extend the selection between s2 and e2 */
2204   if (s2 >= 0)
2205     {
2206       for (i = s2, work = g_list_nth (list->children, i); i <= e2;
2207            i++, work = work->next)
2208         if (GTK_WIDGET (work->data)->state != list->anchor_state)
2209           gtk_widget_set_state (GTK_WIDGET (work->data), list->anchor_state);
2210     }
2211 }
2212
2213 static void
2214 gtk_list_reset_extended_selection (GtkList *list)
2215
2216   g_return_if_fail (list != 0);
2217   g_return_if_fail (GTK_IS_LIST (list));
2218
2219   g_list_free (list->undo_selection);
2220   g_list_free (list->undo_unselection);
2221   list->undo_selection = NULL;
2222   list->undo_unselection = NULL;
2223
2224   list->anchor = -1;
2225   list->drag_pos = -1;
2226   list->undo_focus_child = GTK_CONTAINER (list)->focus_child;
2227 }
2228
2229 /* Public GtkList Scroll Methods :
2230  *
2231  * gtk_list_scroll_horizontal
2232  * gtk_list_scroll_vertical
2233  */
2234 void
2235 gtk_list_scroll_horizontal (GtkList       *list,
2236                             GtkScrollType  scroll_type,
2237                             gfloat         position)
2238 {
2239   GtkAdjustment *adj;
2240
2241   g_return_if_fail (list != 0);
2242   g_return_if_fail (GTK_IS_LIST (list));
2243
2244   if (gdk_pointer_is_grabbed () && GTK_WIDGET_HAS_GRAB (list))
2245     return;
2246
2247   if (!(adj =
2248         gtk_object_get_data_by_id (GTK_OBJECT (list), hadjustment_key_id)))
2249     return;
2250
2251   switch (scroll_type)
2252     {
2253     case GTK_SCROLL_STEP_BACKWARD:
2254       adj->value = CLAMP (adj->value - adj->step_increment, adj->lower,
2255                           adj->upper - adj->page_size);
2256       break;
2257     case GTK_SCROLL_STEP_FORWARD:
2258       adj->value = CLAMP (adj->value + adj->step_increment, adj->lower,
2259                           adj->upper - adj->page_size);
2260       break;
2261     case GTK_SCROLL_PAGE_BACKWARD:
2262       adj->value = CLAMP (adj->value - adj->page_increment, adj->lower,
2263                           adj->upper - adj->page_size);
2264       break;
2265     case GTK_SCROLL_PAGE_FORWARD:
2266       adj->value = CLAMP (adj->value + adj->page_increment, adj->lower,
2267                           adj->upper - adj->page_size);
2268       break;
2269     case GTK_SCROLL_JUMP:
2270       adj->value = CLAMP (adj->lower + (adj->upper - adj->lower) * position,
2271                           adj->lower, adj->upper - adj->page_size);
2272       break;
2273     default:
2274       break;
2275     }
2276   gtk_adjustment_value_changed (adj);
2277 }
2278
2279 void
2280 gtk_list_scroll_vertical (GtkList       *list,
2281                           GtkScrollType  scroll_type,
2282                           gfloat         position)
2283 {
2284   g_return_if_fail (list != NULL);
2285   g_return_if_fail (GTK_IS_LIST (list));
2286
2287   if (gdk_pointer_is_grabbed () && GTK_WIDGET_HAS_GRAB (list))
2288     return;
2289
2290   if (list->selection_mode == GTK_SELECTION_EXTENDED)
2291     {
2292       GtkContainer *container;
2293
2294       if (list->anchor >= 0)
2295         return;
2296
2297       container = GTK_CONTAINER (list);
2298       list->undo_focus_child = container->focus_child;
2299       gtk_list_move_focus_child (list, scroll_type, position);
2300       if (container->focus_child != list->undo_focus_child && !list->add_mode)
2301         {
2302           gtk_list_unselect_all (list);
2303           gtk_list_select_child (list, container->focus_child);
2304         }
2305     }
2306   else
2307     gtk_list_move_focus_child (list, scroll_type, position);
2308 }
2309
2310
2311 /* Private GtkList Scroll/Focus Functions :
2312  *
2313  * gtk_list_move_focus_child
2314  * gtk_list_horizontal_timeout
2315  * gtk_list_vertical_timeout
2316  */
2317 static void
2318 gtk_list_move_focus_child (GtkList       *list,
2319                            GtkScrollType  scroll_type,
2320                            gfloat         position)
2321 {
2322   GtkContainer *container;
2323   GList *work;
2324   GtkWidget *item;
2325   GtkAdjustment *adj;
2326   gint new_value;
2327
2328   g_return_if_fail (list != 0);
2329   g_return_if_fail (GTK_IS_LIST (list));
2330
2331   container = GTK_CONTAINER (list);
2332
2333   if (container->focus_child)
2334     work = g_list_find (list->children, container->focus_child);
2335   else
2336     work = list->children;
2337
2338   if (!work)
2339     return;
2340
2341   switch (scroll_type)
2342     {
2343     case GTK_SCROLL_STEP_BACKWARD:
2344       work = work->prev;
2345       if (work)
2346         gtk_widget_grab_focus (GTK_WIDGET (work->data));
2347       break;
2348     case GTK_SCROLL_STEP_FORWARD:
2349       work = work->next;
2350       if (work)
2351         gtk_widget_grab_focus (GTK_WIDGET (work->data));
2352       break;
2353     case GTK_SCROLL_PAGE_BACKWARD:
2354       if (!work->prev)
2355         return;
2356
2357       item = work->data;
2358       adj = gtk_object_get_data_by_id (GTK_OBJECT (list), vadjustment_key_id);
2359
2360       if (adj)
2361         {
2362           gboolean correct = FALSE;
2363
2364           new_value = adj->value;
2365
2366           if (item->allocation.y <= adj->value)
2367             {
2368               new_value = MAX (item->allocation.y + item->allocation.height
2369                                - adj->page_size, adj->lower);
2370               correct = TRUE;
2371             }
2372
2373           if (item->allocation.y > new_value)
2374             for (; work; work = work->prev)
2375               {
2376                 item = GTK_WIDGET (work->data);
2377                 if (item->allocation.y <= new_value &&
2378                     item->allocation.y + item->allocation.height > new_value)
2379                   break;
2380               }
2381           else
2382             for (; work; work = work->next)
2383               {
2384                 item = GTK_WIDGET (work->data);
2385                 if (item->allocation.y <= new_value &&
2386                     item->allocation.y + item->allocation.height > new_value)
2387                   break;
2388               }
2389
2390           if (correct && work && work->next && item->allocation.y < new_value)
2391             item = work->next->data;
2392         }
2393       else
2394         item = list->children->data;
2395           
2396       gtk_widget_grab_focus (item);
2397       break;
2398     case GTK_SCROLL_PAGE_FORWARD:
2399       if (!work->next)
2400         return;
2401
2402       item = work->data;
2403       adj = gtk_object_get_data_by_id (GTK_OBJECT (list), vadjustment_key_id);
2404
2405       if (adj)
2406         {
2407           gboolean correct = FALSE;
2408
2409           new_value = adj->value;
2410
2411           if (item->allocation.y + item->allocation.height >=
2412               adj->value + adj->page_size)
2413             {
2414               new_value = item->allocation.y;
2415               correct = TRUE;
2416             }
2417
2418           new_value = MIN (new_value + adj->page_size, adj->upper);
2419
2420           if (item->allocation.y > new_value)
2421             for (; work; work = work->prev)
2422               {
2423                 item = GTK_WIDGET (work->data);
2424                 if (item->allocation.y <= new_value &&
2425                     item->allocation.y + item->allocation.height > new_value)
2426                   break;
2427               }
2428           else
2429             for (; work; work = work->next)
2430               {
2431                 item = GTK_WIDGET (work->data);
2432                 if (item->allocation.y <= new_value &&
2433                     item->allocation.y + item->allocation.height > new_value)
2434                   break;
2435               }
2436
2437           if (correct && work && work->prev &&
2438               item->allocation.y + item->allocation.height - 1 > new_value)
2439             item = work->prev->data;
2440         }
2441       else
2442         item = g_list_last (work)->data;
2443           
2444       gtk_widget_grab_focus (item);
2445       break;
2446     case GTK_SCROLL_JUMP:
2447       new_value = GTK_WIDGET(list)->allocation.height * CLAMP (position, 0, 1);
2448
2449       for (item = NULL, work = list->children; work; work =work->next)
2450         {
2451           item = GTK_WIDGET (work->data);
2452           if (item->allocation.y <= new_value &&
2453               item->allocation.y + item->allocation.height > new_value)
2454             break;
2455         }
2456
2457       gtk_widget_grab_focus (item);
2458       break;
2459     default:
2460       break;
2461     }
2462 }
2463
2464 static gint
2465 gtk_list_horizontal_timeout (GtkWidget *list)
2466 {
2467   GdkEventMotion event = { 0 };
2468
2469   GDK_THREADS_ENTER ();
2470
2471   GTK_LIST (list)->htimer = 0;
2472
2473   event.type = GDK_MOTION_NOTIFY;
2474   event.send_event = TRUE;
2475
2476   gtk_list_motion_notify (list, &event);
2477
2478   GDK_THREADS_LEAVE ();
2479
2480   return FALSE;
2481 }
2482
2483 static gint
2484 gtk_list_vertical_timeout (GtkWidget *list)
2485 {
2486   GdkEventMotion event = { 0 };
2487
2488   GDK_THREADS_ENTER ();
2489
2490   GTK_LIST (list)->vtimer = 0;
2491
2492   event.type = GDK_MOTION_NOTIFY;
2493   event.send_event = TRUE;
2494
2495   gtk_list_motion_notify (list, &event);
2496
2497   GDK_THREADS_LEAVE ();
2498
2499   return FALSE;
2500 }
2501
2502
2503 /* Private GtkListItem Signal Functions :
2504  *
2505  * gtk_list_signal_toggle_focus_row
2506  * gtk_list_signal_select_all
2507  * gtk_list_signal_unselect_all
2508  * gtk_list_signal_undo_selection
2509  * gtk_list_signal_start_selection
2510  * gtk_list_signal_end_selection
2511  * gtk_list_signal_extend_selection
2512  * gtk_list_signal_scroll_horizontal
2513  * gtk_list_signal_scroll_vertical
2514  * gtk_list_signal_toggle_add_mode
2515  * gtk_list_signal_item_select
2516  * gtk_list_signal_item_deselect
2517  * gtk_list_signal_item_toggle
2518  */
2519 static void
2520 gtk_list_signal_toggle_focus_row (GtkListItem *list_item,
2521                                   GtkList     *list)
2522 {
2523   g_return_if_fail (list_item != 0);
2524   g_return_if_fail (GTK_IS_LIST_ITEM (list_item));
2525   g_return_if_fail (list != NULL);
2526   g_return_if_fail (GTK_IS_LIST (list));
2527
2528   gtk_list_toggle_focus_row (list);
2529 }
2530
2531 static void
2532 gtk_list_signal_select_all (GtkListItem *list_item,
2533                             GtkList     *list)
2534 {
2535   g_return_if_fail (list_item != 0);
2536   g_return_if_fail (GTK_IS_LIST_ITEM (list_item));
2537   g_return_if_fail (list != NULL);
2538   g_return_if_fail (GTK_IS_LIST (list));
2539
2540   gtk_list_select_all (list);
2541 }
2542
2543 static void
2544 gtk_list_signal_unselect_all (GtkListItem *list_item,
2545                               GtkList     *list)
2546 {
2547   g_return_if_fail (list_item != 0);
2548   g_return_if_fail (GTK_IS_LIST_ITEM (list_item));
2549   g_return_if_fail (list != NULL);
2550   g_return_if_fail (GTK_IS_LIST (list));
2551
2552   gtk_list_unselect_all (list);
2553 }
2554
2555 static void
2556 gtk_list_signal_undo_selection (GtkListItem *list_item,
2557                                 GtkList     *list)
2558 {
2559   g_return_if_fail (list_item != 0);
2560   g_return_if_fail (GTK_IS_LIST_ITEM (list_item));
2561   g_return_if_fail (list != NULL);
2562   g_return_if_fail (GTK_IS_LIST (list));
2563
2564   gtk_list_undo_selection (list);
2565 }
2566
2567 static void
2568 gtk_list_signal_start_selection (GtkListItem *list_item,
2569                                  GtkList     *list)
2570 {
2571   g_return_if_fail (list_item != 0);
2572   g_return_if_fail (GTK_IS_LIST_ITEM (list_item));
2573   g_return_if_fail (list != NULL);
2574   g_return_if_fail (GTK_IS_LIST (list));
2575
2576   gtk_list_start_selection (list);
2577 }
2578
2579 static void
2580 gtk_list_signal_end_selection (GtkListItem *list_item,
2581                                GtkList     *list)
2582 {
2583   g_return_if_fail (list_item != 0);
2584   g_return_if_fail (GTK_IS_LIST_ITEM (list_item));
2585   g_return_if_fail (list != NULL);
2586   g_return_if_fail (GTK_IS_LIST (list));
2587
2588   gtk_list_end_selection (list);
2589 }
2590
2591 static void
2592 gtk_list_signal_extend_selection (GtkListItem   *list_item,
2593                                   GtkScrollType  scroll_type,
2594                                   gfloat         position,
2595                                   gboolean       auto_start_selection,
2596                                   GtkList       *list)
2597 {
2598   g_return_if_fail (list_item != 0);
2599   g_return_if_fail (GTK_IS_LIST_ITEM (list_item));
2600   g_return_if_fail (list != NULL);
2601   g_return_if_fail (GTK_IS_LIST (list));
2602
2603   gtk_list_extend_selection (list, scroll_type, position,
2604                              auto_start_selection);
2605 }
2606
2607 static void
2608 gtk_list_signal_scroll_horizontal (GtkListItem   *list_item,
2609                                    GtkScrollType  scroll_type,
2610                                    gfloat         position,
2611                                    GtkList       *list)
2612 {
2613   g_return_if_fail (list_item != 0);
2614   g_return_if_fail (GTK_IS_LIST_ITEM (list_item));
2615   g_return_if_fail (list != NULL);
2616   g_return_if_fail (GTK_IS_LIST (list));
2617
2618   gtk_list_scroll_horizontal (list, scroll_type, position);
2619 }
2620
2621 static void
2622 gtk_list_signal_scroll_vertical (GtkListItem   *list_item,
2623                                  GtkScrollType  scroll_type,
2624                                  gfloat         position,
2625                                  GtkList       *list)
2626 {
2627   g_return_if_fail (list_item != 0);
2628   g_return_if_fail (GTK_IS_LIST_ITEM (list_item));
2629   g_return_if_fail (list != NULL);
2630   g_return_if_fail (GTK_IS_LIST (list));
2631
2632   gtk_list_scroll_vertical (list, scroll_type, position);
2633 }
2634
2635 static void
2636 gtk_list_signal_toggle_add_mode (GtkListItem *list_item,
2637                                  GtkList     *list)
2638 {
2639   g_return_if_fail (list_item != 0);
2640   g_return_if_fail (GTK_IS_LIST_ITEM (list_item));
2641   g_return_if_fail (list != NULL);
2642   g_return_if_fail (GTK_IS_LIST (list));
2643
2644   gtk_list_toggle_add_mode (list);
2645 }
2646
2647 static void
2648 gtk_list_signal_item_select (GtkListItem *list_item,
2649                              GtkList     *list)
2650 {
2651   GList *selection;
2652   GList *tmp_list;
2653   GList *sel_list;
2654
2655   g_return_if_fail (list_item != 0);
2656   g_return_if_fail (GTK_IS_LIST_ITEM (list_item));
2657   g_return_if_fail (list != NULL);
2658   g_return_if_fail (GTK_IS_LIST (list));
2659
2660   if (GTK_WIDGET (list_item)->state != GTK_STATE_SELECTED)
2661     return;
2662
2663   switch (list->selection_mode)
2664     {
2665     case GTK_SELECTION_SINGLE:
2666     case GTK_SELECTION_BROWSE:
2667       sel_list = NULL;
2668       selection = list->selection;
2669
2670       while (selection)
2671         {
2672           tmp_list = selection;
2673           selection = selection->next;
2674
2675           if (tmp_list->data == list_item)
2676             sel_list = tmp_list;
2677           else
2678             gtk_list_item_deselect (GTK_LIST_ITEM (tmp_list->data));
2679         }
2680
2681       if (!sel_list)
2682         {
2683           list->selection = g_list_prepend (list->selection, list_item);
2684           gtk_widget_ref (GTK_WIDGET (list_item));
2685         }
2686       gtk_signal_emit (GTK_OBJECT (list), list_signals[SELECTION_CHANGED]);
2687       break;
2688     case GTK_SELECTION_EXTENDED:
2689       if (list->anchor >= 0)
2690         return;
2691     case GTK_SELECTION_MULTIPLE:
2692       if (!g_list_find (list->selection, list_item))
2693         {
2694           list->selection = g_list_prepend (list->selection, list_item);
2695           gtk_widget_ref (GTK_WIDGET (list_item));
2696           gtk_signal_emit (GTK_OBJECT (list), list_signals[SELECTION_CHANGED]);
2697         }
2698       break;
2699     }
2700 }
2701
2702 static void
2703 gtk_list_signal_item_deselect (GtkListItem *list_item,
2704                                GtkList     *list)
2705 {
2706   GList *node;
2707
2708   g_return_if_fail (list_item != 0);
2709   g_return_if_fail (GTK_IS_LIST_ITEM (list_item));
2710   g_return_if_fail (list != NULL);
2711   g_return_if_fail (GTK_IS_LIST (list));
2712
2713   if (GTK_WIDGET (list_item)->state != GTK_STATE_NORMAL)
2714     return;
2715
2716   node = g_list_find (list->selection, list_item);
2717
2718   if (node)
2719     {
2720       list->selection = g_list_remove_link (list->selection, node);
2721       g_list_free_1 (node);
2722       gtk_widget_unref (GTK_WIDGET (list_item));
2723       gtk_signal_emit (GTK_OBJECT (list), list_signals[SELECTION_CHANGED]);
2724     }
2725 }
2726
2727 static void
2728 gtk_list_signal_item_toggle (GtkListItem *list_item,
2729                              GtkList     *list)
2730 {
2731   g_return_if_fail (list_item != 0);
2732   g_return_if_fail (GTK_IS_LIST_ITEM (list_item));
2733   g_return_if_fail (list != NULL);
2734   g_return_if_fail (GTK_IS_LIST (list));
2735
2736   switch (GTK_WIDGET (list_item)->state)
2737     {
2738     case GTK_STATE_SELECTED:
2739       gtk_list_signal_item_select (list_item, list);
2740       break;
2741     case GTK_STATE_NORMAL:
2742       gtk_list_signal_item_deselect (list_item, list);
2743       break;
2744     default:
2745       break;
2746     }
2747 }
2748
2749 static void
2750 gtk_list_signal_drag_begin (GtkWidget      *widget,
2751                             GdkDragContext *context,
2752                             GtkList         *list)
2753 {
2754   g_return_if_fail (widget != NULL);
2755   g_return_if_fail (GTK_IS_LIST_ITEM (widget));
2756   g_return_if_fail (list != NULL);
2757   g_return_if_fail (GTK_IS_LIST (list));
2758
2759   gtk_list_drag_begin (GTK_WIDGET (list), context);
2760 }
2761
2762 static void
2763 gtk_list_drag_begin (GtkWidget      *widget,
2764                      GdkDragContext *context)
2765 {
2766   GtkList *list;
2767
2768   g_return_if_fail (widget != NULL);
2769   g_return_if_fail (GTK_IS_LIST (widget));
2770   g_return_if_fail (context != NULL);
2771
2772   list = GTK_LIST (widget);
2773
2774   if (list->drag_selection)
2775     {
2776       gtk_list_end_drag_selection (list);
2777
2778       switch (list->selection_mode)
2779         {
2780         case GTK_SELECTION_EXTENDED:
2781           gtk_list_end_selection (list);
2782           break;
2783         case GTK_SELECTION_SINGLE:
2784         case GTK_SELECTION_MULTIPLE:
2785           list->undo_focus_child = NULL;
2786           break;
2787         default:
2788           break;
2789         }
2790     }
2791 }