1 /* GTK - The GIMP Toolkit
2 * Copyright (C) 1995-1997 Peter Mattis, Spencer Kimball and Josh MacDonald
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.
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.
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.
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/.
27 #include <string.h> /* memset */
30 #include "gtklistitem.h"
32 #include "gtksignal.h"
47 #define SCROLL_TIME 100
49 /*** GtkList Methods ***/
50 static void gtk_list_class_init (GtkListClass *klass);
51 static void gtk_list_init (GtkList *list);
52 static void gtk_list_set_arg (GtkObject *object,
55 static void gtk_list_get_arg (GtkObject *object,
58 /*** GtkObject Methods ***/
59 static void gtk_list_shutdown (GObject *object);
61 /*** GtkWidget Methods ***/
62 static void gtk_list_size_request (GtkWidget *widget,
63 GtkRequisition *requisition);
64 static void gtk_list_size_allocate (GtkWidget *widget,
65 GtkAllocation *allocation);
66 static void gtk_list_realize (GtkWidget *widget);
67 static void gtk_list_map (GtkWidget *widget);
68 static void gtk_list_unmap (GtkWidget *widget);
69 static void gtk_list_style_set (GtkWidget *widget,
70 GtkStyle *previous_style);
71 static gint gtk_list_motion_notify (GtkWidget *widget,
72 GdkEventMotion *event);
73 static gint gtk_list_button_press (GtkWidget *widget,
74 GdkEventButton *event);
75 static gint gtk_list_button_release (GtkWidget *widget,
76 GdkEventButton *event);
78 /*** GtkContainer Methods ***/
79 static void gtk_list_add (GtkContainer *container,
81 static void gtk_list_remove (GtkContainer *container,
83 static void gtk_list_forall (GtkContainer *container,
84 gboolean include_internals,
86 gpointer callback_data);
87 static GtkType gtk_list_child_type (GtkContainer *container);
88 static void gtk_list_set_focus_child (GtkContainer *container,
90 static gint gtk_list_focus (GtkContainer *container,
91 GtkDirectionType direction);
93 /*** GtkList Private Functions ***/
94 static void gtk_list_move_focus_child (GtkList *list,
95 GtkScrollType scroll_type,
97 static gint gtk_list_horizontal_timeout (GtkWidget *list);
98 static gint gtk_list_vertical_timeout (GtkWidget *list);
99 static void gtk_list_remove_items_internal (GtkList *list,
103 /*** GtkList Selection Methods ***/
104 static void gtk_real_list_select_child (GtkList *list,
106 static void gtk_real_list_unselect_child (GtkList *list,
109 /*** GtkList Selection Functions ***/
110 static void gtk_list_set_anchor (GtkList *list,
113 GtkWidget *undo_focus_child);
114 static void gtk_list_fake_unselect_all (GtkList *list,
116 static void gtk_list_fake_toggle_row (GtkList *list,
118 static void gtk_list_update_extended_selection (GtkList *list,
120 static void gtk_list_reset_extended_selection (GtkList *list);
122 /*** GtkListItem Signal Functions ***/
123 static void gtk_list_signal_drag_begin (GtkWidget *widget,
124 GdkDragContext *context,
126 static void gtk_list_signal_toggle_focus_row (GtkListItem *list_item,
128 static void gtk_list_signal_select_all (GtkListItem *list_item,
130 static void gtk_list_signal_unselect_all (GtkListItem *list_item,
132 static void gtk_list_signal_undo_selection (GtkListItem *list_item,
134 static void gtk_list_signal_start_selection (GtkListItem *list_item,
136 static void gtk_list_signal_end_selection (GtkListItem *list_item,
138 static void gtk_list_signal_extend_selection (GtkListItem *list_item,
139 GtkScrollType scroll_type,
141 gboolean auto_start_selection,
143 static void gtk_list_signal_scroll_horizontal (GtkListItem *list_item,
144 GtkScrollType scroll_type,
147 static void gtk_list_signal_scroll_vertical (GtkListItem *list_item,
148 GtkScrollType scroll_type,
151 static void gtk_list_signal_toggle_add_mode (GtkListItem *list_item,
153 static void gtk_list_signal_item_select (GtkListItem *list_item,
155 static void gtk_list_signal_item_deselect (GtkListItem *list_item,
157 static void gtk_list_signal_item_toggle (GtkListItem *list_item,
161 static void gtk_list_drag_begin (GtkWidget *widget,
162 GdkDragContext *context);
165 static GtkContainerClass *parent_class = NULL;
166 static guint list_signals[LAST_SIGNAL] = { 0 };
168 static const gchar *vadjustment_key = "gtk-vadjustment";
169 static guint vadjustment_key_id = 0;
170 static const gchar *hadjustment_key = "gtk-hadjustment";
171 static guint hadjustment_key_id = 0;
174 gtk_list_get_type (void)
176 static GtkType list_type = 0;
180 static const GtkTypeInfo list_info =
184 sizeof (GtkListClass),
185 (GtkClassInitFunc) gtk_list_class_init,
186 (GtkObjectInitFunc) gtk_list_init,
187 /* reserved_1 */ NULL,
188 /* reserved_2 */ NULL,
189 (GtkClassInitFunc) NULL,
192 list_type = gtk_type_unique (GTK_TYPE_CONTAINER, &list_info);
199 gtk_list_class_init (GtkListClass *class)
201 GObjectClass *gobject_class = G_OBJECT_CLASS (class);
202 GtkObjectClass *object_class;
203 GtkWidgetClass *widget_class;
204 GtkContainerClass *container_class;
206 object_class = (GtkObjectClass*) class;
207 widget_class = (GtkWidgetClass*) class;
208 container_class = (GtkContainerClass*) class;
210 parent_class = gtk_type_class (GTK_TYPE_CONTAINER);
212 vadjustment_key_id = g_quark_from_static_string (vadjustment_key);
213 hadjustment_key_id = g_quark_from_static_string (hadjustment_key);
215 gobject_class->shutdown = gtk_list_shutdown;
218 object_class->set_arg = gtk_list_set_arg;
219 object_class->get_arg = gtk_list_get_arg;
221 widget_class->map = gtk_list_map;
222 widget_class->unmap = gtk_list_unmap;
223 widget_class->style_set = gtk_list_style_set;
224 widget_class->realize = gtk_list_realize;
225 widget_class->button_press_event = gtk_list_button_press;
226 widget_class->button_release_event = gtk_list_button_release;
227 widget_class->motion_notify_event = gtk_list_motion_notify;
228 widget_class->size_request = gtk_list_size_request;
229 widget_class->size_allocate = gtk_list_size_allocate;
230 widget_class->drag_begin = gtk_list_drag_begin;
232 container_class->add = gtk_list_add;
233 container_class->remove = gtk_list_remove;
234 container_class->forall = gtk_list_forall;
235 container_class->child_type = gtk_list_child_type;
236 container_class->set_focus_child = gtk_list_set_focus_child;
237 container_class->focus = gtk_list_focus;
239 class->selection_changed = NULL;
240 class->select_child = gtk_real_list_select_child;
241 class->unselect_child = gtk_real_list_unselect_child;
243 list_signals[SELECTION_CHANGED] =
244 gtk_signal_new ("selection_changed",
246 GTK_CLASS_TYPE (object_class),
247 GTK_SIGNAL_OFFSET (GtkListClass, selection_changed),
248 gtk_marshal_VOID__VOID,
250 list_signals[SELECT_CHILD] =
251 gtk_signal_new ("select_child",
253 GTK_CLASS_TYPE (object_class),
254 GTK_SIGNAL_OFFSET (GtkListClass, select_child),
255 gtk_marshal_VOID__OBJECT,
258 list_signals[UNSELECT_CHILD] =
259 gtk_signal_new ("unselect_child",
261 GTK_CLASS_TYPE (object_class),
262 GTK_SIGNAL_OFFSET (GtkListClass, unselect_child),
263 gtk_marshal_VOID__OBJECT,
267 gtk_object_add_arg_type ("GtkList::selection_mode",
268 GTK_TYPE_SELECTION_MODE, GTK_ARG_READWRITE,
273 gtk_list_init (GtkList *list)
275 list->children = NULL;
276 list->selection = NULL;
278 list->undo_selection = NULL;
279 list->undo_unselection = NULL;
281 list->last_focus_child = NULL;
282 list->undo_focus_child = NULL;
289 list->anchor_state = GTK_STATE_SELECTED;
291 list->selection_mode = GTK_SELECTION_SINGLE;
292 list->drag_selection = FALSE;
293 list->add_mode = FALSE;
297 gtk_list_set_arg (GtkObject *object,
301 GtkList *list = GTK_LIST (object);
305 case ARG_SELECTION_MODE:
306 gtk_list_set_selection_mode (list, GTK_VALUE_ENUM (*arg));
312 gtk_list_get_arg (GtkObject *object,
316 GtkList *list = GTK_LIST (object);
320 case ARG_SELECTION_MODE:
321 GTK_VALUE_ENUM (*arg) = list->selection_mode;
324 arg->type = GTK_TYPE_INVALID;
332 return GTK_WIDGET (gtk_type_new (GTK_TYPE_LIST));
336 /* Private GtkObject Methods :
341 gtk_list_shutdown (GObject *object)
343 gtk_list_clear_items (GTK_LIST (object), 0, -1);
345 G_OBJECT_CLASS (parent_class)->shutdown (object);
349 /* Private GtkWidget Methods :
351 * gtk_list_size_request
352 * gtk_list_size_allocate
356 * gtk_list_motion_notify
357 * gtk_list_button_press
358 * gtk_list_button_release
361 gtk_list_size_request (GtkWidget *widget,
362 GtkRequisition *requisition)
368 g_return_if_fail (widget != NULL);
369 g_return_if_fail (GTK_IS_LIST (widget));
370 g_return_if_fail (requisition != NULL);
372 list = GTK_LIST (widget);
373 requisition->width = 0;
374 requisition->height = 0;
376 children = list->children;
379 child = children->data;
380 children = children->next;
382 if (GTK_WIDGET_VISIBLE (child))
384 GtkRequisition child_requisition;
386 gtk_widget_size_request (child, &child_requisition);
388 requisition->width = MAX (requisition->width,
389 child_requisition.width);
390 requisition->height += child_requisition.height;
394 requisition->width += GTK_CONTAINER (list)->border_width * 2;
395 requisition->height += GTK_CONTAINER (list)->border_width * 2;
397 requisition->width = MAX (requisition->width, 1);
398 requisition->height = MAX (requisition->height, 1);
402 gtk_list_size_allocate (GtkWidget *widget,
403 GtkAllocation *allocation)
407 GtkAllocation child_allocation;
410 g_return_if_fail (widget != NULL);
411 g_return_if_fail (GTK_IS_LIST (widget));
412 g_return_if_fail (allocation != NULL);
414 list = GTK_LIST (widget);
416 widget->allocation = *allocation;
417 if (GTK_WIDGET_REALIZED (widget))
418 gdk_window_move_resize (widget->window,
419 allocation->x, allocation->y,
420 allocation->width, allocation->height);
424 child_allocation.x = GTK_CONTAINER (list)->border_width;
425 child_allocation.y = GTK_CONTAINER (list)->border_width;
426 child_allocation.width = MAX (1, (gint)allocation->width -
427 child_allocation.x * 2);
429 children = list->children;
433 child = children->data;
434 children = children->next;
436 if (GTK_WIDGET_VISIBLE (child))
438 GtkRequisition child_requisition;
439 gtk_widget_get_child_requisition (child, &child_requisition);
441 child_allocation.height = child_requisition.height;
443 gtk_widget_size_allocate (child, &child_allocation);
445 child_allocation.y += child_allocation.height;
452 gtk_list_realize (GtkWidget *widget)
454 GdkWindowAttr attributes;
455 gint attributes_mask;
457 g_return_if_fail (widget != NULL);
458 g_return_if_fail (GTK_IS_LIST (widget));
460 GTK_WIDGET_SET_FLAGS (widget, GTK_REALIZED);
462 attributes.window_type = GDK_WINDOW_CHILD;
463 attributes.x = widget->allocation.x;
464 attributes.y = widget->allocation.y;
465 attributes.width = widget->allocation.width;
466 attributes.height = widget->allocation.height;
467 attributes.wclass = GDK_INPUT_OUTPUT;
468 attributes.visual = gtk_widget_get_visual (widget);
469 attributes.colormap = gtk_widget_get_colormap (widget);
470 attributes.event_mask = gtk_widget_get_events (widget) | GDK_EXPOSURE_MASK;
472 attributes_mask = GDK_WA_X | GDK_WA_Y | GDK_WA_VISUAL | GDK_WA_COLORMAP;
474 widget->window = gdk_window_new (gtk_widget_get_parent_window (widget),
475 &attributes, attributes_mask);
476 gdk_window_set_user_data (widget->window, widget);
478 widget->style = gtk_style_attach (widget->style, widget->window);
479 gdk_window_set_background (widget->window,
480 &widget->style->base[GTK_STATE_NORMAL]);
484 gtk_list_map (GtkWidget *widget)
490 g_return_if_fail (widget != NULL);
491 g_return_if_fail (GTK_IS_LIST (widget));
493 GTK_WIDGET_SET_FLAGS (widget, GTK_MAPPED);
494 list = GTK_LIST (widget);
496 children = list->children;
499 child = children->data;
500 children = children->next;
502 if (GTK_WIDGET_VISIBLE (child) &&
503 !GTK_WIDGET_MAPPED (child))
504 gtk_widget_map (child);
507 gdk_window_show (widget->window);
511 gtk_list_unmap (GtkWidget *widget)
515 g_return_if_fail (widget != NULL);
516 g_return_if_fail (GTK_IS_LIST (widget));
518 if (!GTK_WIDGET_MAPPED (widget))
521 list = GTK_LIST (widget);
523 GTK_WIDGET_UNSET_FLAGS (widget, GTK_MAPPED);
525 if (gdk_pointer_is_grabbed () && GTK_WIDGET_HAS_GRAB (list))
527 gtk_list_end_drag_selection (list);
529 if (list->anchor != -1 && list->selection_mode == GTK_SELECTION_EXTENDED)
530 gtk_list_end_selection (list);
533 gdk_window_hide (widget->window);
537 gtk_list_motion_notify (GtkWidget *widget,
538 GdkEventMotion *event)
541 GtkWidget *item = NULL;
543 GtkContainer *container;
551 g_return_val_if_fail (widget != NULL, FALSE);
552 g_return_val_if_fail (GTK_IS_LIST (widget), FALSE);
553 g_return_val_if_fail (event != NULL, FALSE);
555 list = GTK_LIST (widget);
557 if (!list->drag_selection || !list->children)
560 container = GTK_CONTAINER (widget);
562 if (event->is_hint || event->window != widget->window)
563 gdk_window_get_pointer (widget->window, &x, &y, NULL);
570 adj = gtk_object_get_data_by_id (GTK_OBJECT (list), hadjustment_key_id);
572 /* horizontal autoscrolling */
573 if (adj && widget->allocation.width > adj->page_size &&
574 (x < adj->value || x >= adj->value + adj->page_size))
576 if (list->htimer == 0)
578 list->htimer = gtk_timeout_add
579 (SCROLL_TIME, (GtkFunction) gtk_list_horizontal_timeout, widget);
581 if (!((x < adj->value && adj->value <= 0) ||
582 (x > adj->value + adj->page_size &&
583 adj->value >= adj->upper - adj->page_size)))
588 value = adj->value + (x - adj->value) / 2 - 1;
590 value = adj->value + 1 + (x - adj->value - adj->page_size) / 2;
592 gtk_adjustment_set_value (adj,
594 adj->upper - adj->page_size));
602 /* vertical autoscrolling */
603 for (work = list->children; work; length++, work = work->next)
607 item = GTK_WIDGET (work->data);
608 if (item->allocation.y > y ||
609 (item->allocation.y <= y &&
610 item->allocation.y + item->allocation.height > y))
614 if (work->data == container->focus_child)
621 if (list->vtimer != 0)
624 if (!((y < 0 && focus_row == 0) ||
625 (y > widget->allocation.height && focus_row >= length - 1)))
626 list->vtimer = gtk_timeout_add (SCROLL_TIME,
627 (GtkFunction) gtk_list_vertical_timeout,
630 if (row != focus_row)
631 gtk_widget_grab_focus (item);
633 switch (list->selection_mode)
635 case GTK_SELECTION_BROWSE:
636 gtk_list_select_child (list, item);
638 case GTK_SELECTION_EXTENDED:
639 gtk_list_update_extended_selection (list, row);
649 gtk_list_button_press (GtkWidget *widget,
650 GdkEventButton *event)
655 g_return_val_if_fail (widget != NULL, FALSE);
656 g_return_val_if_fail (GTK_IS_LIST (widget), FALSE);
657 g_return_val_if_fail (event != NULL, FALSE);
659 if (event->button != 1)
662 list = GTK_LIST (widget);
663 item = gtk_get_event_widget ((GdkEvent*) event);
665 while (item && !GTK_IS_LIST_ITEM (item))
668 if (item && (item->parent == widget))
673 if (event->type == GDK_BUTTON_PRESS)
675 gtk_grab_add (widget);
676 list->drag_selection = TRUE;
678 else if (gdk_pointer_is_grabbed () && GTK_WIDGET_HAS_GRAB (list))
679 gtk_list_end_drag_selection (list);
681 if (!GTK_WIDGET_HAS_FOCUS(item))
682 gtk_widget_grab_focus (item);
686 list->add_mode = FALSE;
687 gtk_widget_queue_draw (item);
690 switch (list->selection_mode)
692 case GTK_SELECTION_SINGLE:
693 case GTK_SELECTION_MULTIPLE:
694 if (event->type != GDK_BUTTON_PRESS)
695 gtk_list_select_child (list, item);
697 list->undo_focus_child = item;
700 case GTK_SELECTION_BROWSE:
703 case GTK_SELECTION_EXTENDED:
704 focus_row = g_list_index (list->children, item);
706 if (list->last_focus_child)
707 last_focus_row = g_list_index (list->children,
708 list->last_focus_child);
711 last_focus_row = focus_row;
712 list->last_focus_child = item;
715 if (event->type != GDK_BUTTON_PRESS)
717 if (list->anchor >= 0)
719 gtk_list_update_extended_selection (list, focus_row);
720 gtk_list_end_selection (list);
722 gtk_list_select_child (list, item);
726 if (event->state & GDK_CONTROL_MASK)
728 if (event->state & GDK_SHIFT_MASK)
730 if (list->anchor < 0)
732 g_list_free (list->undo_selection);
733 g_list_free (list->undo_unselection);
734 list->undo_selection = NULL;
735 list->undo_unselection = NULL;
737 list->anchor = last_focus_row;
738 list->drag_pos = last_focus_row;
739 list->undo_focus_child = list->last_focus_child;
741 gtk_list_update_extended_selection (list, focus_row);
745 if (list->anchor < 0)
746 gtk_list_set_anchor (list, TRUE,
747 focus_row, list->last_focus_child);
749 gtk_list_update_extended_selection (list, focus_row);
754 if (event->state & GDK_SHIFT_MASK)
756 gtk_list_set_anchor (list, FALSE,
757 last_focus_row, list->last_focus_child);
758 gtk_list_update_extended_selection (list, focus_row);
762 if (list->anchor < 0)
763 gtk_list_set_anchor (list, FALSE, focus_row,
764 list->last_focus_child);
766 gtk_list_update_extended_selection (list, focus_row);
780 gtk_list_button_release (GtkWidget *widget,
781 GdkEventButton *event)
786 g_return_val_if_fail (widget != NULL, FALSE);
787 g_return_val_if_fail (GTK_IS_LIST (widget), FALSE);
788 g_return_val_if_fail (event != NULL, FALSE);
790 list = GTK_LIST (widget);
792 /* we don't handle button 2 and 3 */
793 if (event->button != 1)
796 if (list->drag_selection)
798 gtk_list_end_drag_selection (list);
800 switch (list->selection_mode)
802 case GTK_SELECTION_EXTENDED:
803 if (!(event->state & GDK_SHIFT_MASK))
804 gtk_list_end_selection (list);
807 case GTK_SELECTION_SINGLE:
808 case GTK_SELECTION_MULTIPLE:
810 item = gtk_get_event_widget ((GdkEvent*) event);
812 while (item && !GTK_IS_LIST_ITEM (item))
815 if (item && item->parent == widget)
817 if (list->undo_focus_child == item)
818 gtk_list_toggle_row (list, item);
820 list->undo_focus_child = NULL;
834 gtk_list_style_set (GtkWidget *widget,
835 GtkStyle *previous_style)
837 g_return_if_fail (widget != NULL);
839 if (previous_style && GTK_WIDGET_REALIZED (widget))
840 gdk_window_set_background (widget->window, &widget->style->base[GTK_WIDGET_STATE (widget)]);
843 /* GtkContainer Methods :
847 * gtk_list_child_type
848 * gtk_list_set_focus_child
852 gtk_list_add (GtkContainer *container,
857 g_return_if_fail (container != NULL);
858 g_return_if_fail (GTK_IS_LIST (container));
859 g_return_if_fail (widget != NULL);
860 g_return_if_fail (GTK_IS_LIST_ITEM (widget));
862 item_list = g_list_alloc ();
863 item_list->data = widget;
865 gtk_list_append_items (GTK_LIST (container), item_list);
869 gtk_list_remove (GtkContainer *container,
874 g_return_if_fail (container != NULL);
875 g_return_if_fail (GTK_IS_LIST (container));
876 g_return_if_fail (widget != NULL);
877 g_return_if_fail (container == GTK_CONTAINER (widget->parent));
879 item_list = g_list_alloc ();
880 item_list->data = widget;
882 gtk_list_remove_items (GTK_LIST (container), item_list);
884 g_list_free (item_list);
888 gtk_list_forall (GtkContainer *container,
889 gboolean include_internals,
890 GtkCallback callback,
891 gpointer callback_data)
897 g_return_if_fail (container != NULL);
898 g_return_if_fail (GTK_IS_LIST (container));
899 g_return_if_fail (callback != NULL);
901 list = GTK_LIST (container);
902 children = list->children;
906 child = children->data;
907 children = children->next;
909 (* callback) (child, callback_data);
914 gtk_list_child_type (GtkContainer *container)
916 return GTK_TYPE_LIST_ITEM;
920 gtk_list_set_focus_child (GtkContainer *container,
925 g_return_if_fail (container != NULL);
926 g_return_if_fail (GTK_IS_LIST (container));
929 g_return_if_fail (GTK_IS_WIDGET (child));
931 list = GTK_LIST (container);
933 if (child != container->focus_child)
935 if (container->focus_child)
937 list->last_focus_child = container->focus_child;
938 gtk_widget_unref (container->focus_child);
940 container->focus_child = child;
941 if (container->focus_child)
942 gtk_widget_ref (container->focus_child);
945 /* check for v adjustment */
946 if (container->focus_child)
948 GtkAdjustment *adjustment;
950 adjustment = gtk_object_get_data_by_id (GTK_OBJECT (container),
953 gtk_adjustment_clamp_page (adjustment,
954 container->focus_child->allocation.y,
955 (container->focus_child->allocation.y +
956 container->focus_child->allocation.height));
957 switch (list->selection_mode)
959 case GTK_SELECTION_BROWSE:
960 gtk_list_select_child (list, child);
962 case GTK_SELECTION_EXTENDED:
963 if (!list->last_focus_child && !list->add_mode)
965 list->undo_focus_child = list->last_focus_child;
966 gtk_list_unselect_all (list);
967 gtk_list_select_child (list, child);
977 gtk_list_focus (GtkContainer *container,
978 GtkDirectionType direction)
980 gint return_val = FALSE;
982 g_return_val_if_fail (container != NULL, FALSE);
983 g_return_val_if_fail (GTK_IS_LIST (container), FALSE);
985 if (container->focus_child == NULL ||
986 !GTK_WIDGET_HAS_FOCUS (container->focus_child))
988 if (GTK_LIST (container)->last_focus_child)
989 gtk_container_set_focus_child
990 (container, GTK_LIST (container)->last_focus_child);
992 if (GTK_CONTAINER_CLASS (parent_class)->focus)
993 return_val = GTK_CONTAINER_CLASS (parent_class)->focus (container,
1001 list = GTK_LIST (container);
1002 if (list->selection_mode == GTK_SELECTION_EXTENDED && list->anchor >= 0)
1003 gtk_list_end_selection (list);
1005 if (container->focus_child)
1006 list->last_focus_child = container->focus_child;
1013 /* Public GtkList Methods :
1015 * gtk_list_insert_items
1016 * gtk_list_append_items
1017 * gtk_list_prepend_items
1018 * gtk_list_remove_items
1019 * gtk_list_remove_items_no_unref
1020 * gtk_list_clear_items
1022 * gtk_list_child_position
1025 gtk_list_insert_items (GtkList *list,
1034 g_return_if_fail (list != NULL);
1035 g_return_if_fail (GTK_IS_LIST (list));
1040 gtk_list_end_drag_selection (list);
1041 if (list->selection_mode == GTK_SELECTION_EXTENDED && list->anchor >= 0)
1042 gtk_list_end_selection (list);
1047 widget = tmp_list->data;
1048 tmp_list = tmp_list->next;
1050 gtk_widget_set_parent (widget, GTK_WIDGET (list));
1051 gtk_signal_connect (GTK_OBJECT (widget), "drag_begin",
1052 GTK_SIGNAL_FUNC (gtk_list_signal_drag_begin),
1054 gtk_signal_connect (GTK_OBJECT (widget), "toggle_focus_row",
1055 GTK_SIGNAL_FUNC (gtk_list_signal_toggle_focus_row),
1057 gtk_signal_connect (GTK_OBJECT (widget), "select_all",
1058 GTK_SIGNAL_FUNC (gtk_list_signal_select_all),
1060 gtk_signal_connect (GTK_OBJECT (widget), "unselect_all",
1061 GTK_SIGNAL_FUNC (gtk_list_signal_unselect_all),
1063 gtk_signal_connect (GTK_OBJECT (widget), "undo_selection",
1064 GTK_SIGNAL_FUNC (gtk_list_signal_undo_selection),
1066 gtk_signal_connect (GTK_OBJECT (widget), "start_selection",
1067 GTK_SIGNAL_FUNC (gtk_list_signal_start_selection),
1069 gtk_signal_connect (GTK_OBJECT (widget), "end_selection",
1070 GTK_SIGNAL_FUNC (gtk_list_signal_end_selection),
1072 gtk_signal_connect (GTK_OBJECT (widget), "extend_selection",
1073 GTK_SIGNAL_FUNC (gtk_list_signal_extend_selection),
1075 gtk_signal_connect (GTK_OBJECT (widget), "scroll_horizontal",
1076 GTK_SIGNAL_FUNC (gtk_list_signal_scroll_horizontal),
1078 gtk_signal_connect (GTK_OBJECT (widget), "scroll_vertical",
1079 GTK_SIGNAL_FUNC (gtk_list_signal_scroll_vertical),
1081 gtk_signal_connect (GTK_OBJECT (widget), "toggle_add_mode",
1082 GTK_SIGNAL_FUNC (gtk_list_signal_toggle_add_mode),
1084 gtk_signal_connect (GTK_OBJECT (widget), "select",
1085 GTK_SIGNAL_FUNC (gtk_list_signal_item_select),
1087 gtk_signal_connect (GTK_OBJECT (widget), "deselect",
1088 GTK_SIGNAL_FUNC (gtk_list_signal_item_deselect),
1090 gtk_signal_connect (GTK_OBJECT (widget), "toggle",
1091 GTK_SIGNAL_FUNC (gtk_list_signal_item_toggle),
1094 if (GTK_WIDGET_REALIZED (widget->parent))
1095 gtk_widget_realize (widget);
1097 if (GTK_WIDGET_VISIBLE (widget->parent) && GTK_WIDGET_VISIBLE (widget))
1099 if (GTK_WIDGET_MAPPED (widget->parent))
1100 gtk_widget_map (widget);
1102 gtk_widget_queue_resize (widget);
1107 nchildren = g_list_length (list->children);
1108 if ((position < 0) || (position > nchildren))
1109 position = nchildren;
1111 if (position == nchildren)
1115 tmp_list = g_list_last (list->children);
1116 tmp_list->next = items;
1117 items->prev = tmp_list;
1121 list->children = items;
1126 tmp_list = g_list_nth (list->children, position);
1127 last = g_list_last (items);
1130 tmp_list->prev->next = items;
1131 last->next = tmp_list;
1132 items->prev = tmp_list->prev;
1133 tmp_list->prev = last;
1135 if (tmp_list == list->children)
1136 list->children = items;
1139 if (list->children && !list->selection &&
1140 (list->selection_mode == GTK_SELECTION_BROWSE))
1142 widget = list->children->data;
1143 gtk_list_select_child (list, widget);
1148 gtk_list_append_items (GtkList *list,
1151 g_return_if_fail (list != NULL);
1152 g_return_if_fail (GTK_IS_LIST (list));
1154 gtk_list_insert_items (list, items, -1);
1158 gtk_list_prepend_items (GtkList *list,
1161 g_return_if_fail (list != NULL);
1162 g_return_if_fail (GTK_IS_LIST (list));
1164 gtk_list_insert_items (list, items, 0);
1168 gtk_list_remove_items (GtkList *list,
1171 gtk_list_remove_items_internal (list, items, FALSE);
1175 gtk_list_remove_items_no_unref (GtkList *list,
1178 gtk_list_remove_items_internal (list, items, TRUE);
1182 gtk_list_clear_items (GtkList *list,
1186 GtkContainer *container;
1188 GtkWidget *new_focus_child = NULL;
1193 gboolean grab_focus = FALSE;
1195 g_return_if_fail (list != NULL);
1196 g_return_if_fail (GTK_IS_LIST (list));
1198 nchildren = g_list_length (list->children);
1203 if ((end < 0) || (end > nchildren))
1209 container = GTK_CONTAINER (list);
1211 gtk_list_end_drag_selection (list);
1212 if (list->selection_mode == GTK_SELECTION_EXTENDED)
1214 if (list->anchor >= 0)
1215 gtk_list_end_selection (list);
1217 gtk_list_reset_extended_selection (list);
1220 start_list = g_list_nth (list->children, start);
1221 end_list = g_list_nth (list->children, end);
1223 if (start_list->prev)
1224 start_list->prev->next = end_list;
1225 if (end_list && end_list->prev)
1226 end_list->prev->next = NULL;
1228 end_list->prev = start_list->prev;
1229 if (start_list == list->children)
1230 list->children = end_list;
1232 if (container->focus_child)
1234 if (g_list_find (start_list, container->focus_child))
1236 if (start_list->prev)
1237 new_focus_child = start_list->prev->data;
1238 else if (list->children)
1239 new_focus_child = list->children->prev->data;
1241 if (GTK_WIDGET_HAS_FOCUS (container->focus_child))
1246 tmp_list = start_list;
1249 widget = tmp_list->data;
1250 tmp_list = tmp_list->next;
1252 if (widget->state == GTK_STATE_SELECTED)
1253 gtk_list_unselect_child (list, widget);
1255 if (widget == list->undo_focus_child)
1256 list->undo_focus_child = NULL;
1257 if (widget == list->last_focus_child)
1258 list->last_focus_child = NULL;
1260 gtk_signal_disconnect_by_data (GTK_OBJECT (widget), (gpointer) list);
1261 gtk_widget_unparent (widget);
1264 g_list_free (start_list);
1266 if (new_focus_child)
1269 gtk_widget_grab_focus (new_focus_child);
1270 else if (container->focus_child)
1271 gtk_container_set_focus_child (container, new_focus_child);
1273 if ((list->selection_mode == GTK_SELECTION_BROWSE ||
1274 list->selection_mode == GTK_SELECTION_EXTENDED) && !list->selection)
1276 list->last_focus_child = new_focus_child;
1277 gtk_list_select_child (list, new_focus_child);
1281 if (GTK_WIDGET_VISIBLE (list))
1282 gtk_widget_queue_resize (GTK_WIDGET (list));
1286 gtk_list_child_position (GtkList *list,
1292 g_return_val_if_fail (list != NULL, -1);
1293 g_return_val_if_fail (GTK_IS_LIST (list), -1);
1294 g_return_val_if_fail (child != NULL, -1);
1297 children = list->children;
1301 if (child == GTK_WIDGET (children->data))
1305 children = children->next;
1312 /* Private GtkList Insert/Remove Item Functions:
1314 * gtk_list_remove_items_internal
1317 gtk_list_remove_items_internal (GtkList *list,
1322 GtkWidget *new_focus_child;
1323 GtkWidget *old_focus_child;
1324 GtkContainer *container;
1327 gboolean grab_focus = FALSE;
1329 g_return_if_fail (list != NULL);
1330 g_return_if_fail (GTK_IS_LIST (list));
1335 container = GTK_CONTAINER (list);
1337 gtk_list_end_drag_selection (list);
1338 if (list->selection_mode == GTK_SELECTION_EXTENDED)
1340 if (list->anchor >= 0)
1341 gtk_list_end_selection (list);
1343 gtk_list_reset_extended_selection (list);
1349 widget = tmp_list->data;
1350 tmp_list = tmp_list->next;
1352 if (widget->state == GTK_STATE_SELECTED)
1353 gtk_list_unselect_child (list, widget);
1356 if (container->focus_child)
1358 old_focus_child = new_focus_child = container->focus_child;
1359 if (GTK_WIDGET_HAS_FOCUS (container->focus_child))
1363 old_focus_child = new_focus_child = list->last_focus_child;
1368 widget = tmp_list->data;
1369 tmp_list = tmp_list->next;
1372 gtk_widget_ref (widget);
1374 if (widget == new_focus_child)
1376 work = g_list_find (list->children, widget);
1381 new_focus_child = work->next->data;
1382 else if (list->children != work && work->prev)
1383 new_focus_child = work->prev->data;
1385 new_focus_child = NULL;
1389 if (widget == list->undo_focus_child)
1390 list->undo_focus_child = NULL;
1391 if (widget == list->last_focus_child)
1392 list->last_focus_child = NULL;
1394 gtk_signal_disconnect_by_data (GTK_OBJECT (widget), (gpointer) list);
1395 list->children = g_list_remove (list->children, widget);
1396 gtk_widget_unparent (widget);
1399 if (new_focus_child && new_focus_child != old_focus_child)
1402 gtk_widget_grab_focus (new_focus_child);
1403 else if (container->focus_child)
1404 gtk_container_set_focus_child (container, new_focus_child);
1406 if (list->selection_mode == GTK_SELECTION_BROWSE && !list->selection)
1408 list->last_focus_child = new_focus_child;
1409 gtk_list_select_child (list, new_focus_child);
1413 if (GTK_WIDGET_VISIBLE (list))
1414 gtk_widget_queue_resize (GTK_WIDGET (list));
1418 /* Public GtkList Selection Methods :
1420 * gtk_list_set_selection_mode
1421 * gtk_list_select_item
1422 * gtk_list_unselect_item
1423 * gtk_list_select_child
1424 * gtk_list_unselect_child
1425 * gtk_list_select_all
1426 * gtk_list_unselect_all
1427 * gtk_list_extend_selection
1428 * gtk_list_end_drag_selection
1429 * gtk_list_start_selection
1430 * gtk_list_end_selection
1431 * gtk_list_toggle_row
1432 * gtk_list_toggle_focus_row
1433 * gtk_list_toggle_add_mode
1434 * gtk_list_undo_selection
1437 gtk_list_set_selection_mode (GtkList *list,
1438 GtkSelectionMode mode)
1440 g_return_if_fail (list != NULL);
1441 g_return_if_fail (GTK_IS_LIST (list));
1443 if (list->selection_mode == mode)
1446 list->selection_mode = mode;
1450 case GTK_SELECTION_SINGLE:
1451 case GTK_SELECTION_BROWSE:
1452 gtk_list_unselect_all (list);
1460 gtk_list_select_item (GtkList *list,
1465 g_return_if_fail (list != NULL);
1466 g_return_if_fail (GTK_IS_LIST (list));
1468 tmp_list = g_list_nth (list->children, item);
1470 gtk_list_select_child (list, GTK_WIDGET (tmp_list->data));
1474 gtk_list_unselect_item (GtkList *list,
1479 g_return_if_fail (list != NULL);
1480 g_return_if_fail (GTK_IS_LIST (list));
1482 tmp_list = g_list_nth (list->children, item);
1484 gtk_list_unselect_child (list, GTK_WIDGET (tmp_list->data));
1488 gtk_list_select_child (GtkList *list,
1491 gtk_signal_emit (GTK_OBJECT (list), list_signals[SELECT_CHILD], child);
1495 gtk_list_unselect_child (GtkList *list,
1498 gtk_signal_emit (GTK_OBJECT (list), list_signals[UNSELECT_CHILD], child);
1502 gtk_list_select_all (GtkList *list)
1504 GtkContainer *container;
1507 g_return_if_fail (list != NULL);
1508 g_return_if_fail (GTK_IS_LIST (list));
1510 if (!list->children)
1513 if (gdk_pointer_is_grabbed () && GTK_WIDGET_HAS_GRAB (list))
1514 gtk_list_end_drag_selection (list);
1516 if (list->selection_mode == GTK_SELECTION_EXTENDED && list->anchor >= 0)
1517 gtk_list_end_selection (list);
1519 container = GTK_CONTAINER (list);
1521 switch (list->selection_mode)
1523 case GTK_SELECTION_BROWSE:
1524 if (container->focus_child)
1526 gtk_list_select_child (list, container->focus_child);
1530 case GTK_SELECTION_EXTENDED:
1531 g_list_free (list->undo_selection);
1532 g_list_free (list->undo_unselection);
1533 list->undo_selection = NULL;
1534 list->undo_unselection = NULL;
1536 if (list->children &&
1537 GTK_WIDGET_STATE (list->children->data) != GTK_STATE_SELECTED)
1538 gtk_list_fake_toggle_row (list, GTK_WIDGET (list->children->data));
1540 list->anchor_state = GTK_STATE_SELECTED;
1543 list->undo_focus_child = container->focus_child;
1544 gtk_list_update_extended_selection (list, g_list_length(list->children));
1545 gtk_list_end_selection (list);
1547 case GTK_SELECTION_MULTIPLE:
1548 for (work = list->children; work; work = work->next)
1550 if (GTK_WIDGET_STATE (work->data) == GTK_STATE_NORMAL)
1551 gtk_list_select_child (list, GTK_WIDGET (work->data));
1560 gtk_list_unselect_all (GtkList *list)
1562 GtkContainer *container;
1566 g_return_if_fail (list != NULL);
1567 g_return_if_fail (GTK_IS_LIST (list));
1569 if (!list->children)
1572 if (gdk_pointer_is_grabbed () && GTK_WIDGET_HAS_GRAB (list))
1573 gtk_list_end_drag_selection (list);
1575 if (list->selection_mode == GTK_SELECTION_EXTENDED && list->anchor >= 0)
1576 gtk_list_end_selection (list);
1578 container = GTK_CONTAINER (list);
1580 switch (list->selection_mode)
1582 case GTK_SELECTION_BROWSE:
1583 if (container->focus_child)
1585 gtk_list_select_child (list, container->focus_child);
1589 case GTK_SELECTION_EXTENDED:
1590 gtk_list_reset_extended_selection (list);
1596 work = list->selection;
1602 gtk_list_unselect_child (list, item);
1607 gtk_list_extend_selection (GtkList *list,
1608 GtkScrollType scroll_type,
1610 gboolean auto_start_selection)
1612 GtkContainer *container;
1614 g_return_if_fail (list != NULL);
1615 g_return_if_fail (GTK_IS_LIST (list));
1617 if ((gdk_pointer_is_grabbed () && GTK_WIDGET_HAS_GRAB (list)) ||
1618 list->selection_mode != GTK_SELECTION_EXTENDED)
1621 container = GTK_CONTAINER (list);
1623 if (auto_start_selection)
1627 focus_row = g_list_index (list->children, container->focus_child);
1628 gtk_list_set_anchor (list, list->add_mode, focus_row,
1629 container->focus_child);
1631 else if (list->anchor < 0)
1634 gtk_list_move_focus_child (list, scroll_type, position);
1635 gtk_list_update_extended_selection
1636 (list, g_list_index (list->children, container->focus_child));
1640 gtk_list_end_drag_selection (GtkList *list)
1642 g_return_if_fail (list != NULL);
1643 g_return_if_fail (GTK_IS_LIST (list));
1645 list->drag_selection = FALSE;
1646 if (GTK_WIDGET_HAS_GRAB (list))
1647 gtk_grab_remove (GTK_WIDGET (list));
1651 gtk_timeout_remove (list->htimer);
1656 gtk_timeout_remove (list->vtimer);
1662 gtk_list_start_selection (GtkList *list)
1664 GtkContainer *container;
1667 g_return_if_fail (list != NULL);
1668 g_return_if_fail (GTK_IS_LIST (list));
1670 if (gdk_pointer_is_grabbed () && GTK_WIDGET_HAS_GRAB (list))
1673 container = GTK_CONTAINER (list);
1675 if ((focus_row = g_list_index (list->selection, container->focus_child))
1677 gtk_list_set_anchor (list, list->add_mode,
1678 focus_row, container->focus_child);
1682 gtk_list_end_selection (GtkList *list)
1691 g_return_if_fail (list != NULL);
1692 g_return_if_fail (GTK_IS_LIST (list));
1694 if ((gdk_pointer_is_grabbed () && GTK_WIDGET_HAS_GRAB (list)) ||
1698 i = MIN (list->anchor, list->drag_pos);
1699 e = MAX (list->anchor, list->drag_pos);
1701 top_down = (list->anchor < list->drag_pos);
1704 list->drag_pos = -1;
1706 if (list->undo_selection)
1708 work = list->selection;
1709 list->selection = list->undo_selection;
1710 list->undo_selection = work;
1711 work = list->selection;
1716 item_index = g_list_index (list->children, item);
1717 if (item_index < i || item_index > e)
1719 gtk_widget_set_state (item, GTK_STATE_SELECTED);
1720 gtk_list_unselect_child (list, item);
1721 list->undo_selection = g_list_prepend (list->undo_selection,
1729 for (work = g_list_nth (list->children, i); i <= e;
1730 i++, work = work->next)
1733 if (g_list_find (list->selection, item))
1735 if (item->state == GTK_STATE_NORMAL)
1737 gtk_widget_set_state (item, GTK_STATE_SELECTED);
1738 gtk_list_unselect_child (list, item);
1739 list->undo_selection = g_list_prepend (list->undo_selection,
1743 else if (item->state == GTK_STATE_SELECTED)
1745 gtk_widget_set_state (item, GTK_STATE_NORMAL);
1746 list->undo_unselection = g_list_prepend (list->undo_unselection,
1753 for (work = g_list_nth (list->children, e); i <= e;
1754 e--, work = work->prev)
1757 if (g_list_find (list->selection, item))
1759 if (item->state == GTK_STATE_NORMAL)
1761 gtk_widget_set_state (item, GTK_STATE_SELECTED);
1762 gtk_list_unselect_child (list, item);
1763 list->undo_selection = g_list_prepend (list->undo_selection,
1767 else if (item->state == GTK_STATE_SELECTED)
1769 gtk_widget_set_state (item, GTK_STATE_NORMAL);
1770 list->undo_unselection = g_list_prepend (list->undo_unselection,
1776 for (work = g_list_reverse (list->undo_unselection); work; work = work->next)
1777 gtk_list_select_child (list, GTK_WIDGET (work->data));
1783 gtk_list_toggle_row (GtkList *list,
1786 g_return_if_fail (list != NULL);
1787 g_return_if_fail (GTK_IS_LIST (list));
1788 g_return_if_fail (item != NULL);
1789 g_return_if_fail (GTK_IS_LIST_ITEM (item));
1791 switch (list->selection_mode)
1793 case GTK_SELECTION_EXTENDED:
1794 case GTK_SELECTION_MULTIPLE:
1795 case GTK_SELECTION_SINGLE:
1796 if (item->state == GTK_STATE_SELECTED)
1798 gtk_list_unselect_child (list, item);
1801 case GTK_SELECTION_BROWSE:
1802 gtk_list_select_child (list, item);
1808 gtk_list_toggle_focus_row (GtkList *list)
1810 GtkContainer *container;
1813 g_return_if_fail (list != 0);
1814 g_return_if_fail (GTK_IS_LIST (list));
1816 container = GTK_CONTAINER (list);
1818 if ((gdk_pointer_is_grabbed () && GTK_WIDGET_HAS_GRAB (list)) ||
1819 !container->focus_child)
1822 switch (list->selection_mode)
1824 case GTK_SELECTION_SINGLE:
1825 case GTK_SELECTION_MULTIPLE:
1826 gtk_list_toggle_row (list, container->focus_child);
1828 case GTK_SELECTION_EXTENDED:
1829 if ((focus_row = g_list_index (list->children, container->focus_child))
1833 g_list_free (list->undo_selection);
1834 g_list_free (list->undo_unselection);
1835 list->undo_selection = NULL;
1836 list->undo_unselection = NULL;
1838 list->anchor = focus_row;
1839 list->drag_pos = focus_row;
1840 list->undo_focus_child = container->focus_child;
1843 gtk_list_fake_toggle_row (list, container->focus_child);
1845 gtk_list_fake_unselect_all (list, container->focus_child);
1847 gtk_list_end_selection (list);
1855 gtk_list_toggle_add_mode (GtkList *list)
1857 GtkContainer *container;
1859 g_return_if_fail (list != 0);
1860 g_return_if_fail (GTK_IS_LIST (list));
1862 if ((gdk_pointer_is_grabbed () && GTK_WIDGET_HAS_GRAB (list)) ||
1863 list->selection_mode != GTK_SELECTION_EXTENDED)
1866 container = GTK_CONTAINER (list);
1870 list->add_mode = FALSE;
1871 list->anchor_state = GTK_STATE_SELECTED;
1874 list->add_mode = TRUE;
1876 if (container->focus_child)
1877 gtk_widget_queue_draw (container->focus_child);
1881 gtk_list_undo_selection (GtkList *list)
1885 g_return_if_fail (list != NULL);
1886 g_return_if_fail (GTK_IS_LIST (list));
1888 if (list->selection_mode != GTK_SELECTION_EXTENDED ||
1889 (gdk_pointer_is_grabbed () && GTK_WIDGET_HAS_GRAB (list)))
1892 if (list->anchor >= 0)
1893 gtk_list_end_selection (list);
1895 if (!(list->undo_selection || list->undo_unselection))
1897 gtk_list_unselect_all (list);
1901 for (work = list->undo_selection; work; work = work->next)
1902 gtk_list_select_child (list, GTK_WIDGET (work->data));
1904 for (work = list->undo_unselection; work; work = work->next)
1905 gtk_list_unselect_child (list, GTK_WIDGET (work->data));
1907 if (list->undo_focus_child)
1909 GtkContainer *container;
1911 container = GTK_CONTAINER (list);
1913 if (container->focus_child &&
1914 GTK_WIDGET_HAS_FOCUS (container->focus_child))
1915 gtk_widget_grab_focus (list->undo_focus_child);
1917 gtk_container_set_focus_child (container, list->undo_focus_child);
1920 list->undo_focus_child = NULL;
1922 g_list_free (list->undo_selection);
1923 g_list_free (list->undo_unselection);
1924 list->undo_selection = NULL;
1925 list->undo_unselection = NULL;
1929 /* Private GtkList Selection Methods :
1931 * gtk_real_list_select_child
1932 * gtk_real_list_unselect_child
1935 gtk_real_list_select_child (GtkList *list,
1938 g_return_if_fail (list != NULL);
1939 g_return_if_fail (GTK_IS_LIST (list));
1940 g_return_if_fail (child != NULL);
1941 g_return_if_fail (GTK_IS_LIST_ITEM (child));
1943 switch (child->state)
1945 case GTK_STATE_SELECTED:
1946 case GTK_STATE_INSENSITIVE:
1949 gtk_list_item_select (GTK_LIST_ITEM (child));
1955 gtk_real_list_unselect_child (GtkList *list,
1958 g_return_if_fail (list != NULL);
1959 g_return_if_fail (GTK_IS_LIST (list));
1960 g_return_if_fail (child != NULL);
1961 g_return_if_fail (GTK_IS_LIST_ITEM (child));
1963 if (child->state == GTK_STATE_SELECTED)
1964 gtk_list_item_deselect (GTK_LIST_ITEM (child));
1968 /* Private GtkList Selection Functions :
1970 * gtk_list_set_anchor
1971 * gtk_list_fake_unselect_all
1972 * gtk_list_fake_toggle_row
1973 * gtk_list_update_extended_selection
1974 * gtk_list_reset_extended_selection
1977 gtk_list_set_anchor (GtkList *list,
1980 GtkWidget *undo_focus_child)
1984 g_return_if_fail (list != NULL);
1985 g_return_if_fail (GTK_IS_LIST (list));
1987 if (list->selection_mode != GTK_SELECTION_EXTENDED || list->anchor >= 0)
1990 g_list_free (list->undo_selection);
1991 g_list_free (list->undo_unselection);
1992 list->undo_selection = NULL;
1993 list->undo_unselection = NULL;
1995 if ((work = g_list_nth (list->children, anchor)))
1998 gtk_list_fake_toggle_row (list, GTK_WIDGET (work->data));
2001 gtk_list_fake_unselect_all (list, GTK_WIDGET (work->data));
2002 list->anchor_state = GTK_STATE_SELECTED;
2006 list->anchor = anchor;
2007 list->drag_pos = anchor;
2008 list->undo_focus_child = undo_focus_child;
2012 gtk_list_fake_unselect_all (GtkList *list,
2017 if (item && item->state == GTK_STATE_NORMAL)
2018 gtk_widget_set_state (item, GTK_STATE_SELECTED);
2020 list->undo_selection = list->selection;
2021 list->selection = NULL;
2023 for (work = list->undo_selection; work; work = work->next)
2024 if (work->data != item)
2025 gtk_widget_set_state (GTK_WIDGET (work->data), GTK_STATE_NORMAL);
2029 gtk_list_fake_toggle_row (GtkList *list,
2035 if (item->state == GTK_STATE_NORMAL)
2037 list->anchor_state = GTK_STATE_SELECTED;
2038 gtk_widget_set_state (item, GTK_STATE_SELECTED);
2042 list->anchor_state = GTK_STATE_NORMAL;
2043 gtk_widget_set_state (item, GTK_STATE_NORMAL);
2048 gtk_list_update_extended_selection (GtkList *list,
2062 length = g_list_length (list->children);
2066 if (list->selection_mode != GTK_SELECTION_EXTENDED || !list->anchor < 0)
2069 /* extending downwards */
2070 if (row > list->drag_pos && list->anchor <= list->drag_pos)
2072 s2 = list->drag_pos + 1;
2075 /* extending upwards */
2076 else if (row < list->drag_pos && list->anchor >= list->drag_pos)
2079 e2 = list->drag_pos - 1;
2081 else if (row < list->drag_pos && list->anchor < list->drag_pos)
2083 e1 = list->drag_pos;
2084 /* row and drag_pos on different sides of anchor :
2085 take back the selection between anchor and drag_pos,
2086 select between anchor and row */
2087 if (row < list->anchor)
2089 s1 = list->anchor + 1;
2091 e2 = list->anchor - 1;
2093 /* take back the selection between anchor and drag_pos */
2097 else if (row > list->drag_pos && list->anchor > list->drag_pos)
2099 s1 = list->drag_pos;
2100 /* row and drag_pos on different sides of anchor :
2101 take back the selection between anchor and drag_pos,
2102 select between anchor and row */
2103 if (row > list->anchor)
2105 e1 = list->anchor - 1;
2106 s2 = list->anchor + 1;
2109 /* take back the selection between anchor and drag_pos */
2114 list->drag_pos = row;
2116 /* restore the elements between s1 and e1 */
2119 for (i = s1, work = g_list_nth (list->children, i); i <= e1;
2120 i++, work = work->next)
2122 if (g_list_find (list->selection, work->data))
2123 gtk_widget_set_state (GTK_WIDGET (work->data), GTK_STATE_SELECTED);
2125 gtk_widget_set_state (GTK_WIDGET (work->data), GTK_STATE_NORMAL);
2129 /* extend the selection between s2 and e2 */
2132 for (i = s2, work = g_list_nth (list->children, i); i <= e2;
2133 i++, work = work->next)
2134 if (GTK_WIDGET (work->data)->state != list->anchor_state)
2135 gtk_widget_set_state (GTK_WIDGET (work->data), list->anchor_state);
2140 gtk_list_reset_extended_selection (GtkList *list)
2142 g_return_if_fail (list != 0);
2143 g_return_if_fail (GTK_IS_LIST (list));
2145 g_list_free (list->undo_selection);
2146 g_list_free (list->undo_unselection);
2147 list->undo_selection = NULL;
2148 list->undo_unselection = NULL;
2151 list->drag_pos = -1;
2152 list->undo_focus_child = GTK_CONTAINER (list)->focus_child;
2155 /* Public GtkList Scroll Methods :
2157 * gtk_list_scroll_horizontal
2158 * gtk_list_scroll_vertical
2161 gtk_list_scroll_horizontal (GtkList *list,
2162 GtkScrollType scroll_type,
2167 g_return_if_fail (list != 0);
2168 g_return_if_fail (GTK_IS_LIST (list));
2170 if (gdk_pointer_is_grabbed () && GTK_WIDGET_HAS_GRAB (list))
2174 gtk_object_get_data_by_id (GTK_OBJECT (list), hadjustment_key_id)))
2177 switch (scroll_type)
2179 case GTK_SCROLL_STEP_UP:
2180 case GTK_SCROLL_STEP_BACKWARD:
2181 adj->value = CLAMP (adj->value - adj->step_increment, adj->lower,
2182 adj->upper - adj->page_size);
2184 case GTK_SCROLL_STEP_DOWN:
2185 case GTK_SCROLL_STEP_FORWARD:
2186 adj->value = CLAMP (adj->value + adj->step_increment, adj->lower,
2187 adj->upper - adj->page_size);
2189 case GTK_SCROLL_PAGE_UP:
2190 case GTK_SCROLL_PAGE_BACKWARD:
2191 adj->value = CLAMP (adj->value - adj->page_increment, adj->lower,
2192 adj->upper - adj->page_size);
2194 case GTK_SCROLL_PAGE_DOWN:
2195 case GTK_SCROLL_PAGE_FORWARD:
2196 adj->value = CLAMP (adj->value + adj->page_increment, adj->lower,
2197 adj->upper - adj->page_size);
2199 case GTK_SCROLL_JUMP:
2200 adj->value = CLAMP (adj->lower + (adj->upper - adj->lower) * position,
2201 adj->lower, adj->upper - adj->page_size);
2206 gtk_adjustment_value_changed (adj);
2210 gtk_list_scroll_vertical (GtkList *list,
2211 GtkScrollType scroll_type,
2214 g_return_if_fail (list != NULL);
2215 g_return_if_fail (GTK_IS_LIST (list));
2217 if (gdk_pointer_is_grabbed () && GTK_WIDGET_HAS_GRAB (list))
2220 if (list->selection_mode == GTK_SELECTION_EXTENDED)
2222 GtkContainer *container;
2224 if (list->anchor >= 0)
2227 container = GTK_CONTAINER (list);
2228 list->undo_focus_child = container->focus_child;
2229 gtk_list_move_focus_child (list, scroll_type, position);
2230 if (container->focus_child != list->undo_focus_child && !list->add_mode)
2232 gtk_list_unselect_all (list);
2233 gtk_list_select_child (list, container->focus_child);
2237 gtk_list_move_focus_child (list, scroll_type, position);
2241 /* Private GtkList Scroll/Focus Functions :
2243 * gtk_list_move_focus_child
2244 * gtk_list_horizontal_timeout
2245 * gtk_list_vertical_timeout
2248 gtk_list_move_focus_child (GtkList *list,
2249 GtkScrollType scroll_type,
2252 GtkContainer *container;
2258 g_return_if_fail (list != 0);
2259 g_return_if_fail (GTK_IS_LIST (list));
2261 container = GTK_CONTAINER (list);
2263 if (container->focus_child)
2264 work = g_list_find (list->children, container->focus_child);
2266 work = list->children;
2271 switch (scroll_type)
2273 case GTK_SCROLL_STEP_BACKWARD:
2276 gtk_widget_grab_focus (GTK_WIDGET (work->data));
2278 case GTK_SCROLL_STEP_FORWARD:
2281 gtk_widget_grab_focus (GTK_WIDGET (work->data));
2283 case GTK_SCROLL_PAGE_BACKWARD:
2288 adj = gtk_object_get_data_by_id (GTK_OBJECT (list), vadjustment_key_id);
2292 gboolean correct = FALSE;
2294 new_value = adj->value;
2296 if (item->allocation.y <= adj->value)
2298 new_value = MAX (item->allocation.y + item->allocation.height
2299 - adj->page_size, adj->lower);
2303 if (item->allocation.y > new_value)
2304 for (; work; work = work->prev)
2306 item = GTK_WIDGET (work->data);
2307 if (item->allocation.y <= new_value &&
2308 item->allocation.y + item->allocation.height > new_value)
2312 for (; work; work = work->next)
2314 item = GTK_WIDGET (work->data);
2315 if (item->allocation.y <= new_value &&
2316 item->allocation.y + item->allocation.height > new_value)
2320 if (correct && work && work->next && item->allocation.y < new_value)
2321 item = work->next->data;
2324 item = list->children->data;
2326 gtk_widget_grab_focus (item);
2328 case GTK_SCROLL_PAGE_FORWARD:
2333 adj = gtk_object_get_data_by_id (GTK_OBJECT (list), vadjustment_key_id);
2337 gboolean correct = FALSE;
2339 new_value = adj->value;
2341 if (item->allocation.y + item->allocation.height >=
2342 adj->value + adj->page_size)
2344 new_value = item->allocation.y;
2348 new_value = MIN (new_value + adj->page_size, adj->upper);
2350 if (item->allocation.y > new_value)
2351 for (; work; work = work->prev)
2353 item = GTK_WIDGET (work->data);
2354 if (item->allocation.y <= new_value &&
2355 item->allocation.y + item->allocation.height > new_value)
2359 for (; work; work = work->next)
2361 item = GTK_WIDGET (work->data);
2362 if (item->allocation.y <= new_value &&
2363 item->allocation.y + item->allocation.height > new_value)
2367 if (correct && work && work->prev &&
2368 item->allocation.y + item->allocation.height - 1 > new_value)
2369 item = work->prev->data;
2372 item = g_list_last (work)->data;
2374 gtk_widget_grab_focus (item);
2376 case GTK_SCROLL_JUMP:
2377 new_value = GTK_WIDGET(list)->allocation.height * CLAMP (position, 0, 1);
2379 for (item = NULL, work = list->children; work; work =work->next)
2381 item = GTK_WIDGET (work->data);
2382 if (item->allocation.y <= new_value &&
2383 item->allocation.y + item->allocation.height > new_value)
2387 gtk_widget_grab_focus (item);
2395 gtk_list_horizontal_timeout (GtkWidget *list)
2397 GdkEventMotion event;
2399 memset (&event, 0, sizeof (event));
2401 GDK_THREADS_ENTER ();
2403 GTK_LIST (list)->htimer = 0;
2405 event.type = GDK_MOTION_NOTIFY;
2406 event.send_event = TRUE;
2408 gtk_list_motion_notify (list, &event);
2410 GDK_THREADS_LEAVE ();
2416 gtk_list_vertical_timeout (GtkWidget *list)
2418 GdkEventMotion event;
2420 memset (&event, 0, sizeof (event));
2422 GDK_THREADS_ENTER ();
2424 GTK_LIST (list)->vtimer = 0;
2426 event.type = GDK_MOTION_NOTIFY;
2427 event.send_event = TRUE;
2429 gtk_list_motion_notify (list, &event);
2431 GDK_THREADS_LEAVE ();
2437 /* Private GtkListItem Signal Functions :
2439 * gtk_list_signal_toggle_focus_row
2440 * gtk_list_signal_select_all
2441 * gtk_list_signal_unselect_all
2442 * gtk_list_signal_undo_selection
2443 * gtk_list_signal_start_selection
2444 * gtk_list_signal_end_selection
2445 * gtk_list_signal_extend_selection
2446 * gtk_list_signal_scroll_horizontal
2447 * gtk_list_signal_scroll_vertical
2448 * gtk_list_signal_toggle_add_mode
2449 * gtk_list_signal_item_select
2450 * gtk_list_signal_item_deselect
2451 * gtk_list_signal_item_toggle
2454 gtk_list_signal_toggle_focus_row (GtkListItem *list_item,
2457 g_return_if_fail (list_item != 0);
2458 g_return_if_fail (GTK_IS_LIST_ITEM (list_item));
2459 g_return_if_fail (list != NULL);
2460 g_return_if_fail (GTK_IS_LIST (list));
2462 gtk_list_toggle_focus_row (list);
2466 gtk_list_signal_select_all (GtkListItem *list_item,
2469 g_return_if_fail (list_item != 0);
2470 g_return_if_fail (GTK_IS_LIST_ITEM (list_item));
2471 g_return_if_fail (list != NULL);
2472 g_return_if_fail (GTK_IS_LIST (list));
2474 gtk_list_select_all (list);
2478 gtk_list_signal_unselect_all (GtkListItem *list_item,
2481 g_return_if_fail (list_item != 0);
2482 g_return_if_fail (GTK_IS_LIST_ITEM (list_item));
2483 g_return_if_fail (list != NULL);
2484 g_return_if_fail (GTK_IS_LIST (list));
2486 gtk_list_unselect_all (list);
2490 gtk_list_signal_undo_selection (GtkListItem *list_item,
2493 g_return_if_fail (list_item != 0);
2494 g_return_if_fail (GTK_IS_LIST_ITEM (list_item));
2495 g_return_if_fail (list != NULL);
2496 g_return_if_fail (GTK_IS_LIST (list));
2498 gtk_list_undo_selection (list);
2502 gtk_list_signal_start_selection (GtkListItem *list_item,
2505 g_return_if_fail (list_item != 0);
2506 g_return_if_fail (GTK_IS_LIST_ITEM (list_item));
2507 g_return_if_fail (list != NULL);
2508 g_return_if_fail (GTK_IS_LIST (list));
2510 gtk_list_start_selection (list);
2514 gtk_list_signal_end_selection (GtkListItem *list_item,
2517 g_return_if_fail (list_item != 0);
2518 g_return_if_fail (GTK_IS_LIST_ITEM (list_item));
2519 g_return_if_fail (list != NULL);
2520 g_return_if_fail (GTK_IS_LIST (list));
2522 gtk_list_end_selection (list);
2526 gtk_list_signal_extend_selection (GtkListItem *list_item,
2527 GtkScrollType scroll_type,
2529 gboolean auto_start_selection,
2532 g_return_if_fail (list_item != 0);
2533 g_return_if_fail (GTK_IS_LIST_ITEM (list_item));
2534 g_return_if_fail (list != NULL);
2535 g_return_if_fail (GTK_IS_LIST (list));
2537 gtk_list_extend_selection (list, scroll_type, position,
2538 auto_start_selection);
2542 gtk_list_signal_scroll_horizontal (GtkListItem *list_item,
2543 GtkScrollType scroll_type,
2547 g_return_if_fail (list_item != 0);
2548 g_return_if_fail (GTK_IS_LIST_ITEM (list_item));
2549 g_return_if_fail (list != NULL);
2550 g_return_if_fail (GTK_IS_LIST (list));
2552 gtk_list_scroll_horizontal (list, scroll_type, position);
2556 gtk_list_signal_scroll_vertical (GtkListItem *list_item,
2557 GtkScrollType scroll_type,
2561 g_return_if_fail (list_item != 0);
2562 g_return_if_fail (GTK_IS_LIST_ITEM (list_item));
2563 g_return_if_fail (list != NULL);
2564 g_return_if_fail (GTK_IS_LIST (list));
2566 gtk_list_scroll_vertical (list, scroll_type, position);
2570 gtk_list_signal_toggle_add_mode (GtkListItem *list_item,
2573 g_return_if_fail (list_item != 0);
2574 g_return_if_fail (GTK_IS_LIST_ITEM (list_item));
2575 g_return_if_fail (list != NULL);
2576 g_return_if_fail (GTK_IS_LIST (list));
2578 gtk_list_toggle_add_mode (list);
2582 gtk_list_signal_item_select (GtkListItem *list_item,
2589 g_return_if_fail (list_item != 0);
2590 g_return_if_fail (GTK_IS_LIST_ITEM (list_item));
2591 g_return_if_fail (list != NULL);
2592 g_return_if_fail (GTK_IS_LIST (list));
2594 if (GTK_WIDGET (list_item)->state != GTK_STATE_SELECTED)
2597 switch (list->selection_mode)
2599 case GTK_SELECTION_SINGLE:
2600 case GTK_SELECTION_BROWSE:
2602 selection = list->selection;
2606 tmp_list = selection;
2607 selection = selection->next;
2609 if (tmp_list->data == list_item)
2610 sel_list = tmp_list;
2612 gtk_list_item_deselect (GTK_LIST_ITEM (tmp_list->data));
2617 list->selection = g_list_prepend (list->selection, list_item);
2618 gtk_widget_ref (GTK_WIDGET (list_item));
2620 gtk_signal_emit (GTK_OBJECT (list), list_signals[SELECTION_CHANGED]);
2622 case GTK_SELECTION_EXTENDED:
2623 if (list->anchor >= 0)
2625 case GTK_SELECTION_MULTIPLE:
2626 if (!g_list_find (list->selection, list_item))
2628 list->selection = g_list_prepend (list->selection, list_item);
2629 gtk_widget_ref (GTK_WIDGET (list_item));
2630 gtk_signal_emit (GTK_OBJECT (list), list_signals[SELECTION_CHANGED]);
2637 gtk_list_signal_item_deselect (GtkListItem *list_item,
2642 g_return_if_fail (list_item != 0);
2643 g_return_if_fail (GTK_IS_LIST_ITEM (list_item));
2644 g_return_if_fail (list != NULL);
2645 g_return_if_fail (GTK_IS_LIST (list));
2647 if (GTK_WIDGET (list_item)->state != GTK_STATE_NORMAL)
2650 node = g_list_find (list->selection, list_item);
2654 list->selection = g_list_remove_link (list->selection, node);
2655 g_list_free_1 (node);
2656 gtk_widget_unref (GTK_WIDGET (list_item));
2657 gtk_signal_emit (GTK_OBJECT (list), list_signals[SELECTION_CHANGED]);
2662 gtk_list_signal_item_toggle (GtkListItem *list_item,
2665 g_return_if_fail (list_item != 0);
2666 g_return_if_fail (GTK_IS_LIST_ITEM (list_item));
2667 g_return_if_fail (list != NULL);
2668 g_return_if_fail (GTK_IS_LIST (list));
2670 if ((list->selection_mode == GTK_SELECTION_BROWSE ||
2671 list->selection_mode == GTK_SELECTION_EXTENDED) &&
2672 GTK_WIDGET (list_item)->state == GTK_STATE_NORMAL)
2674 gtk_widget_set_state (GTK_WIDGET (list_item), GTK_STATE_SELECTED);
2678 switch (GTK_WIDGET (list_item)->state)
2680 case GTK_STATE_SELECTED:
2681 gtk_list_signal_item_select (list_item, list);
2683 case GTK_STATE_NORMAL:
2684 gtk_list_signal_item_deselect (list_item, list);
2692 gtk_list_signal_drag_begin (GtkWidget *widget,
2693 GdkDragContext *context,
2696 g_return_if_fail (widget != NULL);
2697 g_return_if_fail (GTK_IS_LIST_ITEM (widget));
2698 g_return_if_fail (list != NULL);
2699 g_return_if_fail (GTK_IS_LIST (list));
2701 gtk_list_drag_begin (GTK_WIDGET (list), context);
2705 gtk_list_drag_begin (GtkWidget *widget,
2706 GdkDragContext *context)
2710 g_return_if_fail (widget != NULL);
2711 g_return_if_fail (GTK_IS_LIST (widget));
2712 g_return_if_fail (context != NULL);
2714 list = GTK_LIST (widget);
2716 if (list->drag_selection)
2718 gtk_list_end_drag_selection (list);
2720 switch (list->selection_mode)
2722 case GTK_SELECTION_EXTENDED:
2723 gtk_list_end_selection (list);
2725 case GTK_SELECTION_SINGLE:
2726 case GTK_SELECTION_MULTIPLE:
2727 list->undo_focus_child = NULL;