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