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