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