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