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