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