]> Pileus Git - ~andy/gtk/blob - gtk/gtklist.c
in case of GTK_SELECTION_BROWSE select first inserted row.
[~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   gboolean top_down;
1694   GList *work;
1695   GtkWidget *item;
1696   gint item_index;
1697
1698   g_return_if_fail (list != NULL);
1699   g_return_if_fail (GTK_IS_LIST (list));
1700
1701   if ((gdk_pointer_is_grabbed () && GTK_WIDGET_HAS_GRAB (list)) ||
1702       list->anchor < 0)
1703     return;
1704
1705   i = MIN (list->anchor, list->drag_pos);
1706   e = MAX (list->anchor, list->drag_pos);
1707
1708   top_down = (list->anchor < list->drag_pos);
1709
1710   list->anchor = -1;
1711   list->drag_pos = -1;
1712   
1713   if (list->undo_selection)
1714     {
1715       work = list->selection;
1716       list->selection = list->undo_selection;
1717       list->undo_selection = work;
1718       work = list->selection;
1719       while (work)
1720         {
1721           item = work->data;
1722           work = work->next;
1723           item_index = g_list_index (list->children, item);
1724           if (item_index < i || item_index > e)
1725             {
1726               gtk_widget_set_state (item, GTK_STATE_SELECTED);
1727               gtk_list_unselect_child (list, item);
1728               list->undo_selection = g_list_prepend (list->undo_selection,
1729                                                      item);
1730             }
1731         }
1732     }    
1733
1734   if (top_down)
1735     {
1736       for (work = g_list_nth (list->children, i); i <= e;
1737            i++, work = work->next)
1738         {
1739           item = work->data;
1740           if (g_list_find (list->selection, item))
1741             {
1742               if (item->state == GTK_STATE_NORMAL)
1743                 {
1744                   gtk_widget_set_state (item, GTK_STATE_SELECTED);
1745                   gtk_list_unselect_child (list, item);
1746                   list->undo_selection = g_list_prepend (list->undo_selection,
1747                                                          item);
1748                 }
1749             }
1750           else if (item->state == GTK_STATE_SELECTED)
1751             {
1752               gtk_widget_set_state (item, GTK_STATE_NORMAL);
1753               list->undo_unselection = g_list_prepend (list->undo_unselection,
1754                                                        item);
1755             }
1756         }
1757     }
1758   else
1759     {
1760       for (work = g_list_nth (list->children, e); i <= e;
1761            e--, work = work->prev)
1762         {
1763           item = work->data;
1764           if (g_list_find (list->selection, item))
1765             {
1766               if (item->state == GTK_STATE_NORMAL)
1767                 {
1768                   gtk_widget_set_state (item, GTK_STATE_SELECTED);
1769                   gtk_list_unselect_child (list, item);
1770                   list->undo_selection = g_list_prepend (list->undo_selection,
1771                                                          item);
1772                 }
1773             }
1774           else if (item->state == GTK_STATE_SELECTED)
1775             {
1776               gtk_widget_set_state (item, GTK_STATE_NORMAL);
1777               list->undo_unselection = g_list_prepend (list->undo_unselection,
1778                                                        item);
1779             }
1780         }
1781     }
1782
1783   for (work = g_list_reverse (list->undo_unselection); work; work = work->next)
1784     gtk_list_select_child (list, GTK_WIDGET (work->data));
1785
1786
1787 }
1788
1789 void
1790 gtk_list_toggle_row (GtkList   *list,
1791                      GtkWidget *item)
1792 {
1793   g_return_if_fail (list != NULL);
1794   g_return_if_fail (GTK_IS_LIST (list));
1795   g_return_if_fail (item != NULL);
1796   g_return_if_fail (GTK_IS_LIST_ITEM (item));
1797
1798   switch (list->selection_mode)
1799     {
1800     case GTK_SELECTION_EXTENDED:
1801     case GTK_SELECTION_MULTIPLE:
1802     case GTK_SELECTION_SINGLE:
1803       if (item->state == GTK_STATE_SELECTED)
1804         {
1805           gtk_list_unselect_child (list, item);
1806           return;
1807         }
1808     case GTK_SELECTION_BROWSE:
1809       gtk_list_select_child (list, item);
1810       break;
1811     }
1812 }
1813
1814 void
1815 gtk_list_toggle_focus_row (GtkList *list)
1816 {
1817   GtkContainer *container;
1818   gint focus_row;
1819
1820   g_return_if_fail (list != 0);
1821   g_return_if_fail (GTK_IS_LIST (list));
1822
1823   container = GTK_CONTAINER (list);
1824
1825   if ((gdk_pointer_is_grabbed () && GTK_WIDGET_HAS_GRAB (list)) ||
1826       !container->focus_child)
1827     return;
1828
1829   switch (list->selection_mode)
1830     {
1831     case  GTK_SELECTION_SINGLE:
1832     case  GTK_SELECTION_MULTIPLE:
1833       gtk_list_toggle_row (list, container->focus_child);
1834       break;
1835     case GTK_SELECTION_EXTENDED:
1836       if ((focus_row = g_list_index (list->children, container->focus_child))
1837           < 0)
1838         return;
1839
1840       g_list_free (list->undo_selection);
1841       g_list_free (list->undo_unselection);
1842       list->undo_selection = NULL;
1843       list->undo_unselection = NULL;
1844
1845       list->anchor = focus_row;
1846       list->drag_pos = focus_row;
1847       list->undo_focus_child = container->focus_child;
1848
1849       if (list->add_mode)
1850         gtk_list_fake_toggle_row (list, container->focus_child);
1851       else
1852         gtk_list_fake_unselect_all (list, container->focus_child);
1853       
1854       gtk_list_end_selection (list);
1855       break;
1856     default:
1857       break;
1858     }
1859 }
1860
1861 void
1862 gtk_list_toggle_add_mode (GtkList *list)
1863 {
1864   GtkContainer *container;
1865
1866   g_return_if_fail (list != 0);
1867   g_return_if_fail (GTK_IS_LIST (list));
1868   
1869   if ((gdk_pointer_is_grabbed () && GTK_WIDGET_HAS_GRAB (list)) ||
1870       list->selection_mode != GTK_SELECTION_EXTENDED)
1871     return;
1872   
1873   container = GTK_CONTAINER (list);
1874
1875   if (list->add_mode)
1876     {
1877       list->add_mode = FALSE;
1878       list->anchor_state = GTK_STATE_SELECTED;
1879     }
1880   else
1881     list->add_mode = TRUE;
1882   
1883   if (container->focus_child)
1884     gtk_widget_queue_draw (container->focus_child);
1885 }
1886
1887 void
1888 gtk_list_undo_selection (GtkList *list)
1889 {
1890   GList *work;
1891
1892   g_return_if_fail (list != NULL);
1893   g_return_if_fail (GTK_IS_LIST (list));
1894
1895   if (list->selection_mode != GTK_SELECTION_EXTENDED ||
1896       (gdk_pointer_is_grabbed () && GTK_WIDGET_HAS_GRAB (list)))
1897     return;
1898   
1899   if (list->anchor >= 0)
1900     gtk_list_end_selection (list);
1901
1902   if (!(list->undo_selection || list->undo_unselection))
1903     {
1904       gtk_list_unselect_all (list);
1905       return;
1906     }
1907
1908   for (work = list->undo_selection; work; work = work->next)
1909     gtk_list_select_child (list, GTK_WIDGET (work->data));
1910
1911   for (work = list->undo_unselection; work; work = work->next)
1912     gtk_list_unselect_child (list, GTK_WIDGET (work->data));
1913
1914   if (list->undo_focus_child)
1915     {
1916       GtkContainer *container;
1917
1918       container = GTK_CONTAINER (list);
1919
1920       if (container->focus_child &&
1921           GTK_WIDGET_HAS_FOCUS (container->focus_child))
1922         gtk_widget_grab_focus (list->undo_focus_child);
1923       else
1924         gtk_container_set_focus_child (container, list->undo_focus_child);
1925     }
1926
1927   list->undo_focus_child = NULL;
1928  
1929   g_list_free (list->undo_selection);
1930   g_list_free (list->undo_unselection);
1931   list->undo_selection = NULL;
1932   list->undo_unselection = NULL;
1933 }
1934
1935
1936 /* Private GtkList Selection Methods :
1937  *
1938  * gtk_real_list_select_child
1939  * gtk_real_list_unselect_child
1940  */
1941 static void
1942 gtk_real_list_select_child (GtkList   *list,
1943                             GtkWidget *child)
1944 {
1945   g_return_if_fail (list != NULL);
1946   g_return_if_fail (GTK_IS_LIST (list));
1947   g_return_if_fail (child != NULL);
1948   g_return_if_fail (GTK_IS_LIST_ITEM (child));
1949
1950   switch (child->state)
1951     {
1952     case GTK_STATE_SELECTED:
1953     case GTK_STATE_INSENSITIVE:
1954       break;
1955     default:
1956       gtk_list_item_select (GTK_LIST_ITEM (child));
1957       break;
1958     }
1959 }
1960
1961 static void
1962 gtk_real_list_unselect_child (GtkList   *list,
1963                               GtkWidget *child)
1964 {
1965   g_return_if_fail (list != NULL);
1966   g_return_if_fail (GTK_IS_LIST (list));
1967   g_return_if_fail (child != NULL);
1968   g_return_if_fail (GTK_IS_LIST_ITEM (child));
1969
1970   if (child->state == GTK_STATE_SELECTED)
1971     gtk_list_item_deselect (GTK_LIST_ITEM (child));
1972 }
1973
1974
1975 /* Private GtkList Selection Functions :
1976  *
1977  * gtk_list_set_anchor
1978  * gtk_list_fake_unselect_all
1979  * gtk_list_fake_toggle_row
1980  * gtk_list_update_extended_selection
1981  * gtk_list_reset_extended_selection
1982  */
1983 static void
1984 gtk_list_set_anchor (GtkList   *list,
1985                      gboolean   add_mode,
1986                      gint       anchor,
1987                      GtkWidget *undo_focus_child)
1988 {
1989   GList *work;
1990
1991   g_return_if_fail (list != NULL);
1992   g_return_if_fail (GTK_IS_LIST (list));
1993   
1994   if (list->selection_mode != GTK_SELECTION_EXTENDED || list->anchor >= 0)
1995     return;
1996
1997   g_list_free (list->undo_selection);
1998   g_list_free (list->undo_unselection);
1999   list->undo_selection = NULL;
2000   list->undo_unselection = NULL;
2001
2002   if ((work = g_list_nth (list->children, anchor)))
2003     {
2004       if (add_mode)
2005         gtk_list_fake_toggle_row (list, GTK_WIDGET (work->data));
2006       else
2007         {
2008           gtk_list_fake_unselect_all (list, GTK_WIDGET (work->data));
2009           list->anchor_state = GTK_STATE_SELECTED;
2010         }
2011     }
2012
2013   list->anchor = anchor;
2014   list->drag_pos = anchor;
2015   list->undo_focus_child = undo_focus_child;
2016 }
2017
2018 static void
2019 gtk_list_fake_unselect_all (GtkList   *list,
2020                             GtkWidget *item)
2021 {
2022   GList *work;
2023
2024   if (item && item->state == GTK_STATE_NORMAL)
2025     gtk_widget_set_state (item, GTK_STATE_SELECTED);
2026
2027   list->undo_selection = list->selection;
2028   list->selection = NULL;
2029   
2030   for (work = list->undo_selection; work; work = work->next)
2031     if (work->data != item)
2032       gtk_widget_set_state (GTK_WIDGET (work->data), GTK_STATE_NORMAL);
2033 }
2034
2035 static void
2036 gtk_list_fake_toggle_row (GtkList   *list,
2037                           GtkWidget *item)
2038 {
2039   if (!item)
2040     return;
2041   
2042   if (item->state == GTK_STATE_NORMAL)
2043     {
2044       list->anchor_state = GTK_STATE_SELECTED;
2045       gtk_widget_set_state (item, GTK_STATE_SELECTED);
2046     }
2047   else
2048     {
2049       list->anchor_state = GTK_STATE_NORMAL;
2050       gtk_widget_set_state (item, GTK_STATE_NORMAL);
2051     }
2052 }
2053
2054 static void
2055 gtk_list_update_extended_selection (GtkList *list,
2056                                     gint     row)
2057 {
2058   gint i;
2059   GList *work;
2060   gint s1 = -1;
2061   gint s2 = -1;
2062   gint e1 = -1;
2063   gint e2 = -1;
2064   gint length;
2065
2066   if (row < 0)
2067     row = 0;
2068
2069   length = g_list_length (list->children);
2070   if (row >= length)
2071     row = length - 1;
2072
2073   if (list->selection_mode != GTK_SELECTION_EXTENDED || !list->anchor < 0)
2074     return;
2075
2076   /* extending downwards */
2077   if (row > list->drag_pos && list->anchor <= list->drag_pos)
2078     {
2079       s2 = list->drag_pos + 1;
2080       e2 = row;
2081     }
2082   /* extending upwards */
2083   else if (row < list->drag_pos && list->anchor >= list->drag_pos)
2084     {
2085       s2 = row;
2086       e2 = list->drag_pos - 1;
2087     }
2088   else if (row < list->drag_pos && list->anchor < list->drag_pos)
2089     {
2090       e1 = list->drag_pos;
2091       /* row and drag_pos on different sides of anchor :
2092          take back the selection between anchor and drag_pos,
2093          select between anchor and row */
2094       if (row < list->anchor)
2095         {
2096           s1 = list->anchor + 1;
2097           s2 = row;
2098           e2 = list->anchor - 1;
2099         }
2100       /* take back the selection between anchor and drag_pos */
2101       else
2102         s1 = row + 1;
2103     }
2104   else if (row > list->drag_pos && list->anchor > list->drag_pos)
2105     {
2106       s1 = list->drag_pos;
2107       /* row and drag_pos on different sides of anchor :
2108          take back the selection between anchor and drag_pos,
2109          select between anchor and row */
2110       if (row > list->anchor)
2111         {
2112           e1 = list->anchor - 1;
2113           s2 = list->anchor + 1;
2114           e2 = row;
2115         }
2116       /* take back the selection between anchor and drag_pos */
2117       else
2118         e1 = row - 1;
2119     }
2120
2121   list->drag_pos = row;
2122
2123   /* restore the elements between s1 and e1 */
2124   if (s1 >= 0)
2125     {
2126       for (i = s1, work = g_list_nth (list->children, i); i <= e1;
2127            i++, work = work->next)
2128         {
2129           if (g_list_find (list->selection, work->data))
2130             gtk_widget_set_state (GTK_WIDGET (work->data), GTK_STATE_SELECTED);
2131           else
2132             gtk_widget_set_state (GTK_WIDGET (work->data), GTK_STATE_NORMAL);
2133         }
2134     }
2135
2136   /* extend the selection between s2 and e2 */
2137   if (s2 >= 0)
2138     {
2139       for (i = s2, work = g_list_nth (list->children, i); i <= e2;
2140            i++, work = work->next)
2141         if (GTK_WIDGET (work->data)->state != list->anchor_state)
2142           gtk_widget_set_state (GTK_WIDGET (work->data), list->anchor_state);
2143     }
2144 }
2145
2146 static void
2147 gtk_list_reset_extended_selection (GtkList *list)
2148
2149   g_return_if_fail (list != 0);
2150   g_return_if_fail (GTK_IS_LIST (list));
2151
2152   g_list_free (list->undo_selection);
2153   g_list_free (list->undo_unselection);
2154   list->undo_selection = NULL;
2155   list->undo_unselection = NULL;
2156
2157   list->anchor = -1;
2158   list->drag_pos = -1;
2159   list->undo_focus_child = GTK_CONTAINER (list)->focus_child;
2160 }
2161
2162 /* Public GtkList Scroll Methods :
2163  *
2164  * gtk_list_scroll_horizontal
2165  * gtk_list_scroll_vertical
2166  */
2167 void
2168 gtk_list_scroll_horizontal (GtkList       *list,
2169                             GtkScrollType  scroll_type,
2170                             gfloat         position)
2171 {
2172   GtkAdjustment *adj;
2173
2174   g_return_if_fail (list != 0);
2175   g_return_if_fail (GTK_IS_LIST (list));
2176
2177   if (gdk_pointer_is_grabbed () && GTK_WIDGET_HAS_GRAB (list))
2178     return;
2179
2180   if (!(adj =
2181         gtk_object_get_data_by_id (GTK_OBJECT (list), hadjustment_key_id)))
2182     return;
2183
2184   switch (scroll_type)
2185     {
2186     case GTK_SCROLL_STEP_BACKWARD:
2187       adj->value = CLAMP (adj->value - adj->step_increment, adj->lower,
2188                           adj->upper - adj->page_size);
2189       break;
2190     case GTK_SCROLL_STEP_FORWARD:
2191       adj->value = CLAMP (adj->value + adj->step_increment, adj->lower,
2192                           adj->upper - adj->page_size);
2193       break;
2194     case GTK_SCROLL_PAGE_BACKWARD:
2195       adj->value = CLAMP (adj->value - adj->page_increment, adj->lower,
2196                           adj->upper - adj->page_size);
2197       break;
2198     case GTK_SCROLL_PAGE_FORWARD:
2199       adj->value = CLAMP (adj->value + adj->page_increment, adj->lower,
2200                           adj->upper - adj->page_size);
2201       break;
2202     case GTK_SCROLL_JUMP:
2203       adj->value = CLAMP (adj->lower + (adj->upper - adj->lower) * position,
2204                           adj->lower, adj->upper - adj->page_size);
2205       break;
2206     default:
2207       break;
2208     }
2209   gtk_adjustment_value_changed (adj);
2210 }
2211
2212 void
2213 gtk_list_scroll_vertical (GtkList       *list,
2214                           GtkScrollType  scroll_type,
2215                           gfloat         position)
2216 {
2217   g_return_if_fail (list != NULL);
2218   g_return_if_fail (GTK_IS_LIST (list));
2219
2220   if (gdk_pointer_is_grabbed () && GTK_WIDGET_HAS_GRAB (list))
2221     return;
2222
2223   if (list->selection_mode == GTK_SELECTION_EXTENDED)
2224     {
2225       GtkContainer *container;
2226
2227       if (list->anchor >= 0)
2228         return;
2229
2230       container = GTK_CONTAINER (list);
2231       list->undo_focus_child = container->focus_child;
2232       gtk_list_move_focus_child (list, scroll_type, position);
2233       if (container->focus_child != list->undo_focus_child && !list->add_mode)
2234         {
2235           gtk_list_unselect_all (list);
2236           gtk_list_select_child (list, container->focus_child);
2237         }
2238     }
2239   else
2240     gtk_list_move_focus_child (list, scroll_type, position);
2241 }
2242
2243
2244 /* Private GtkList Scroll/Focus Functions :
2245  *
2246  * gtk_list_move_focus_child
2247  * gtk_list_horizontal_timeout
2248  * gtk_list_vertical_timeout
2249  */
2250 static void
2251 gtk_list_move_focus_child (GtkList       *list,
2252                            GtkScrollType  scroll_type,
2253                            gfloat         position)
2254 {
2255   GtkContainer *container;
2256   GList *work;
2257   GtkWidget *item;
2258   GtkAdjustment *adj;
2259   gint new_value;
2260
2261   g_return_if_fail (list != 0);
2262   g_return_if_fail (GTK_IS_LIST (list));
2263
2264   container = GTK_CONTAINER (list);
2265
2266   if (container->focus_child)
2267     work = g_list_find (list->children, container->focus_child);
2268   else
2269     work = list->children;
2270
2271   if (!work)
2272     return;
2273
2274   switch (scroll_type)
2275     {
2276     case GTK_SCROLL_STEP_BACKWARD:
2277       work = work->prev;
2278       if (work)
2279         gtk_widget_grab_focus (GTK_WIDGET (work->data));
2280       break;
2281     case GTK_SCROLL_STEP_FORWARD:
2282       work = work->next;
2283       if (work)
2284         gtk_widget_grab_focus (GTK_WIDGET (work->data));
2285       break;
2286     case GTK_SCROLL_PAGE_BACKWARD:
2287       if (!work->prev)
2288         return;
2289
2290       item = work->data;
2291       adj = gtk_object_get_data_by_id (GTK_OBJECT (list), vadjustment_key_id);
2292
2293       if (adj)
2294         {
2295           gboolean correct = FALSE;
2296
2297           new_value = adj->value;
2298
2299           if (item->allocation.y <= adj->value)
2300             {
2301               new_value = MAX (item->allocation.y + item->allocation.height
2302                                - adj->page_size, adj->lower);
2303               correct = TRUE;
2304             }
2305
2306           if (item->allocation.y > new_value)
2307             for (; work; work = work->prev)
2308               {
2309                 item = GTK_WIDGET (work->data);
2310                 if (item->allocation.y <= new_value &&
2311                     item->allocation.y + item->allocation.height > new_value)
2312                   break;
2313               }
2314           else
2315             for (; work; work = work->next)
2316               {
2317                 item = GTK_WIDGET (work->data);
2318                 if (item->allocation.y <= new_value &&
2319                     item->allocation.y + item->allocation.height > new_value)
2320                   break;
2321               }
2322
2323           if (correct && work && work->next && item->allocation.y < new_value)
2324             item = work->next->data;
2325         }
2326       else
2327         item = list->children->data;
2328           
2329       gtk_widget_grab_focus (item);
2330       break;
2331     case GTK_SCROLL_PAGE_FORWARD:
2332       if (!work->next)
2333         return;
2334
2335       item = work->data;
2336       adj = gtk_object_get_data_by_id (GTK_OBJECT (list), vadjustment_key_id);
2337
2338       if (adj)
2339         {
2340           gboolean correct = FALSE;
2341
2342           new_value = adj->value;
2343
2344           if (item->allocation.y + item->allocation.height >=
2345               adj->value + adj->page_size)
2346             {
2347               new_value = item->allocation.y;
2348               correct = TRUE;
2349             }
2350
2351           new_value = MIN (new_value + adj->page_size, adj->upper);
2352
2353           if (item->allocation.y > new_value)
2354             for (; work; work = work->prev)
2355               {
2356                 item = GTK_WIDGET (work->data);
2357                 if (item->allocation.y <= new_value &&
2358                     item->allocation.y + item->allocation.height > new_value)
2359                   break;
2360               }
2361           else
2362             for (; work; work = work->next)
2363               {
2364                 item = GTK_WIDGET (work->data);
2365                 if (item->allocation.y <= new_value &&
2366                     item->allocation.y + item->allocation.height > new_value)
2367                   break;
2368               }
2369
2370           if (correct && work && work->prev &&
2371               item->allocation.y + item->allocation.height - 1 > new_value)
2372             item = work->prev->data;
2373         }
2374       else
2375         item = g_list_last (work)->data;
2376           
2377       gtk_widget_grab_focus (item);
2378       break;
2379     case GTK_SCROLL_JUMP:
2380       new_value = GTK_WIDGET(list)->allocation.height * CLAMP (position, 0, 1);
2381
2382       for (item = NULL, work = list->children; work; work =work->next)
2383         {
2384           item = GTK_WIDGET (work->data);
2385           if (item->allocation.y <= new_value &&
2386               item->allocation.y + item->allocation.height > new_value)
2387             break;
2388         }
2389
2390       gtk_widget_grab_focus (item);
2391       break;
2392     default:
2393       break;
2394     }
2395 }
2396
2397 static gint
2398 gtk_list_horizontal_timeout (GtkWidget *list)
2399 {
2400   gint x, y;
2401   GdkEventMotion event;
2402   GdkModifierType mask;
2403
2404   GDK_THREADS_ENTER ();
2405
2406   GTK_LIST (list)->htimer = 0;
2407   gdk_window_get_pointer (list->window, &x, &y, &mask);
2408
2409   event.is_hint = 0;
2410   event.x = x;
2411   event.y = y;
2412   event.state = mask;
2413
2414   gtk_list_motion_notify (list, &event);
2415
2416   GDK_THREADS_LEAVE ();
2417
2418   return FALSE;
2419 }
2420
2421 static gint
2422 gtk_list_vertical_timeout (GtkWidget *list)
2423 {
2424   gint x;
2425   gint y;
2426   GdkEventMotion event;
2427   GdkModifierType mask;
2428
2429   GDK_THREADS_ENTER ();
2430
2431   GTK_LIST (list)->vtimer = 0;
2432   gdk_window_get_pointer (list->window, &x, &y, &mask);
2433
2434   event.is_hint = 0;
2435   event.x = x;
2436   event.y = y;
2437   event.state = mask;
2438
2439   gtk_list_motion_notify (list, &event);
2440
2441   GDK_THREADS_LEAVE ();
2442
2443   return FALSE;
2444 }
2445
2446
2447 /* Private GtkListItem Signal Functions :
2448  *
2449  * gtk_list_signal_toggle_focus_row
2450  * gtk_list_signal_select_all
2451  * gtk_list_signal_unselect_all
2452  * gtk_list_signal_undo_selection
2453  * gtk_list_signal_start_selection
2454  * gtk_list_signal_end_selection
2455  * gtk_list_signal_extend_selection
2456  * gtk_list_signal_scroll_horizontal
2457  * gtk_list_signal_scroll_vertical
2458  * gtk_list_signal_toggle_add_mode
2459  * gtk_list_signal_item_select
2460  * gtk_list_signal_item_deselect
2461  * gtk_list_signal_item_toggle
2462  */
2463 static void
2464 gtk_list_signal_toggle_focus_row (GtkListItem *list_item,
2465                                   GtkList     *list)
2466 {
2467   g_return_if_fail (list_item != 0);
2468   g_return_if_fail (GTK_IS_LIST_ITEM (list_item));
2469   g_return_if_fail (list != NULL);
2470   g_return_if_fail (GTK_IS_LIST (list));
2471
2472   gtk_list_toggle_focus_row (list);
2473 }
2474
2475 static void
2476 gtk_list_signal_select_all (GtkListItem *list_item,
2477                             GtkList     *list)
2478 {
2479   g_return_if_fail (list_item != 0);
2480   g_return_if_fail (GTK_IS_LIST_ITEM (list_item));
2481   g_return_if_fail (list != NULL);
2482   g_return_if_fail (GTK_IS_LIST (list));
2483
2484   gtk_list_select_all (list);
2485 }
2486
2487 static void
2488 gtk_list_signal_unselect_all (GtkListItem *list_item,
2489                               GtkList     *list)
2490 {
2491   g_return_if_fail (list_item != 0);
2492   g_return_if_fail (GTK_IS_LIST_ITEM (list_item));
2493   g_return_if_fail (list != NULL);
2494   g_return_if_fail (GTK_IS_LIST (list));
2495
2496   gtk_list_unselect_all (list);
2497 }
2498
2499 static void
2500 gtk_list_signal_undo_selection (GtkListItem *list_item,
2501                                 GtkList     *list)
2502 {
2503   g_return_if_fail (list_item != 0);
2504   g_return_if_fail (GTK_IS_LIST_ITEM (list_item));
2505   g_return_if_fail (list != NULL);
2506   g_return_if_fail (GTK_IS_LIST (list));
2507
2508   gtk_list_undo_selection (list);
2509 }
2510
2511 static void
2512 gtk_list_signal_start_selection (GtkListItem *list_item,
2513                                  GtkList     *list)
2514 {
2515   g_return_if_fail (list_item != 0);
2516   g_return_if_fail (GTK_IS_LIST_ITEM (list_item));
2517   g_return_if_fail (list != NULL);
2518   g_return_if_fail (GTK_IS_LIST (list));
2519
2520   gtk_list_start_selection (list);
2521 }
2522
2523 static void
2524 gtk_list_signal_end_selection (GtkListItem *list_item,
2525                                GtkList     *list)
2526 {
2527   g_return_if_fail (list_item != 0);
2528   g_return_if_fail (GTK_IS_LIST_ITEM (list_item));
2529   g_return_if_fail (list != NULL);
2530   g_return_if_fail (GTK_IS_LIST (list));
2531
2532   gtk_list_end_selection (list);
2533 }
2534
2535 static void
2536 gtk_list_signal_extend_selection (GtkListItem   *list_item,
2537                                   GtkScrollType  scroll_type,
2538                                   gfloat         position,
2539                                   gboolean       auto_start_selection,
2540                                   GtkList       *list)
2541 {
2542   g_return_if_fail (list_item != 0);
2543   g_return_if_fail (GTK_IS_LIST_ITEM (list_item));
2544   g_return_if_fail (list != NULL);
2545   g_return_if_fail (GTK_IS_LIST (list));
2546
2547   gtk_list_extend_selection (list, scroll_type, position,
2548                              auto_start_selection);
2549 }
2550
2551 static void
2552 gtk_list_signal_scroll_horizontal (GtkListItem   *list_item,
2553                                    GtkScrollType  scroll_type,
2554                                    gfloat         position,
2555                                    GtkList       *list)
2556 {
2557   g_return_if_fail (list_item != 0);
2558   g_return_if_fail (GTK_IS_LIST_ITEM (list_item));
2559   g_return_if_fail (list != NULL);
2560   g_return_if_fail (GTK_IS_LIST (list));
2561
2562   gtk_list_scroll_horizontal (list, scroll_type, position);
2563 }
2564
2565 static void
2566 gtk_list_signal_scroll_vertical (GtkListItem   *list_item,
2567                                  GtkScrollType  scroll_type,
2568                                  gfloat         position,
2569                                  GtkList       *list)
2570 {
2571   g_return_if_fail (list_item != 0);
2572   g_return_if_fail (GTK_IS_LIST_ITEM (list_item));
2573   g_return_if_fail (list != NULL);
2574   g_return_if_fail (GTK_IS_LIST (list));
2575
2576   gtk_list_scroll_vertical (list, scroll_type, position);
2577 }
2578
2579 static void
2580 gtk_list_signal_toggle_add_mode (GtkListItem *list_item,
2581                                  GtkList     *list)
2582 {
2583   g_return_if_fail (list_item != 0);
2584   g_return_if_fail (GTK_IS_LIST_ITEM (list_item));
2585   g_return_if_fail (list != NULL);
2586   g_return_if_fail (GTK_IS_LIST (list));
2587
2588   gtk_list_toggle_add_mode (list);
2589 }
2590
2591 static void
2592 gtk_list_signal_item_select (GtkListItem *list_item,
2593                              GtkList     *list)
2594 {
2595   GList *selection;
2596   GList *tmp_list;
2597   GList *sel_list;
2598
2599   g_return_if_fail (list_item != 0);
2600   g_return_if_fail (GTK_IS_LIST_ITEM (list_item));
2601   g_return_if_fail (list != NULL);
2602   g_return_if_fail (GTK_IS_LIST (list));
2603
2604   if (GTK_WIDGET (list_item)->state != GTK_STATE_SELECTED)
2605     return;
2606
2607   switch (list->selection_mode)
2608     {
2609     case GTK_SELECTION_SINGLE:
2610     case GTK_SELECTION_BROWSE:
2611       sel_list = NULL;
2612       selection = list->selection;
2613
2614       while (selection)
2615         {
2616           tmp_list = selection;
2617           selection = selection->next;
2618
2619           if (tmp_list->data == list_item)
2620             sel_list = tmp_list;
2621           else
2622             gtk_list_item_deselect (GTK_LIST_ITEM (tmp_list->data));
2623         }
2624
2625       if (!sel_list)
2626         {
2627           list->selection = g_list_prepend (list->selection, list_item);
2628           gtk_widget_ref (GTK_WIDGET (list_item));
2629         }
2630       gtk_signal_emit (GTK_OBJECT (list), list_signals[SELECTION_CHANGED]);
2631       break;
2632     case GTK_SELECTION_EXTENDED:
2633       if (list->anchor >= 0)
2634         return;
2635     case GTK_SELECTION_MULTIPLE:
2636       if (!g_list_find (list->selection, list_item))
2637         {
2638           list->selection = g_list_prepend (list->selection, list_item);
2639           gtk_widget_ref (GTK_WIDGET (list_item));
2640           gtk_signal_emit (GTK_OBJECT (list), list_signals[SELECTION_CHANGED]);
2641         }
2642       break;
2643     }
2644 }
2645
2646 static void
2647 gtk_list_signal_item_deselect (GtkListItem *list_item,
2648                                GtkList     *list)
2649 {
2650   GList *node;
2651
2652   g_return_if_fail (list_item != 0);
2653   g_return_if_fail (GTK_IS_LIST_ITEM (list_item));
2654   g_return_if_fail (list != NULL);
2655   g_return_if_fail (GTK_IS_LIST (list));
2656
2657   if (GTK_WIDGET (list_item)->state != GTK_STATE_NORMAL)
2658     return;
2659
2660   node = g_list_find (list->selection, list_item);
2661
2662   if (node)
2663     {
2664       list->selection = g_list_remove_link (list->selection, node);
2665       g_list_free_1 (node);
2666       gtk_widget_unref (GTK_WIDGET (list_item));
2667       gtk_signal_emit (GTK_OBJECT (list), list_signals[SELECTION_CHANGED]);
2668     }
2669 }
2670
2671 static void
2672 gtk_list_signal_item_toggle (GtkListItem *list_item,
2673                              GtkList     *list)
2674 {
2675   g_return_if_fail (list_item != 0);
2676   g_return_if_fail (GTK_IS_LIST_ITEM (list_item));
2677   g_return_if_fail (list != NULL);
2678   g_return_if_fail (GTK_IS_LIST (list));
2679
2680   switch (GTK_WIDGET (list_item)->state)
2681     {
2682     case GTK_STATE_SELECTED:
2683       gtk_list_signal_item_select (list_item, list);
2684       break;
2685     case GTK_STATE_NORMAL:
2686       gtk_list_signal_item_deselect (list_item, list);
2687       break;
2688     default:
2689       break;
2690     }
2691 }
2692
2693 static void
2694 gtk_list_signal_drag_begin (GtkWidget      *widget,
2695                             GdkDragContext *context,
2696                             GtkList         *list)
2697 {
2698   g_return_if_fail (widget != NULL);
2699   g_return_if_fail (GTK_IS_LIST_ITEM (widget));
2700   g_return_if_fail (list != NULL);
2701   g_return_if_fail (GTK_IS_LIST (list));
2702
2703   gtk_list_drag_begin (GTK_WIDGET (list), context);
2704 }
2705
2706 static void
2707 gtk_list_drag_begin (GtkWidget      *widget,
2708                      GdkDragContext *context)
2709 {
2710   GtkList *list;
2711
2712   g_return_if_fail (widget != NULL);
2713   g_return_if_fail (GTK_IS_LIST (widget));
2714   g_return_if_fail (context != NULL);
2715
2716   list = GTK_LIST (widget);
2717
2718   if (list->drag_selection)
2719     {
2720       gtk_list_end_drag_selection (list);
2721
2722       switch (list->selection_mode)
2723         {
2724         case GTK_SELECTION_EXTENDED:
2725           gtk_list_end_selection (list);
2726           break;
2727         case GTK_SELECTION_SINGLE:
2728         case GTK_SELECTION_MULTIPLE:
2729           list->undo_focus_child = NULL;
2730           break;
2731         default:
2732           break;
2733         }
2734     }
2735 }