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