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