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