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