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