source: trunk/third/gtk/gtk/gtklist.c @ 15781

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