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