+static int listitem_key(GtkWidget *item, GdkEventKey *event, gpointer data,
+ int multiple)
+{
+ GtkAdjustment *adj = GTK_ADJUSTMENT(data);
+
+ if (event->keyval == GDK_Up || event->keyval == GDK_KP_Up ||
+ event->keyval == GDK_Down || event->keyval == GDK_KP_Down ||
+ event->keyval == GDK_Page_Up || event->keyval == GDK_KP_Page_Up ||
+ event->keyval == GDK_Page_Down || event->keyval == GDK_KP_Page_Down) {
+ /*
+ * Up, Down, PgUp or PgDn have been pressed on a ListItem
+ * in a list box. So, if the list box is single-selection:
+ *
+ * - if the list item in question isn't already selected,
+ * we simply select it.
+ * - otherwise, we find the next one (or next
+ * however-far-away) in whichever direction we're going,
+ * and select that.
+ * + in this case, we must also fiddle with the
+ * scrollbar to ensure the newly selected item is
+ * actually visible.
+ *
+ * If it's multiple-selection, we do all of the above
+ * except actually selecting anything, so we move the focus
+ * and fiddle the scrollbar to follow it.
+ */
+ GtkWidget *list = item->parent;
+
+ gtk_signal_emit_stop_by_name(GTK_OBJECT(item), "key_press_event");
+
+ if (!multiple &&
+ GTK_WIDGET_STATE(item) != GTK_STATE_SELECTED) {
+ gtk_list_select_child(GTK_LIST(list), item);
+ } else {
+ int direction =
+ (event->keyval==GDK_Up || event->keyval==GDK_KP_Up ||
+ event->keyval==GDK_Page_Up || event->keyval==GDK_KP_Page_Up)
+ ? -1 : +1;
+ int step =
+ (event->keyval==GDK_Page_Down ||
+ event->keyval==GDK_KP_Page_Down ||
+ event->keyval==GDK_Page_Up || event->keyval==GDK_KP_Page_Up)
+ ? 2 : 1;
+ int i, n;
+ GtkWidget *thisitem;
+ GList *children, *chead;
+
+ chead = children = gtk_container_children(GTK_CONTAINER(list));
+
+ n = g_list_length(children);
+
+ if (step == 2) {
+ /*
+ * Figure out how many list items to a screenful,
+ * and adjust the step appropriately.
+ */
+ step = 0.5 + adj->page_size * n / (adj->upper - adj->lower);
+ step--; /* go by one less than that */
+ }
+
+ i = 0;
+ while (children != NULL) {
+ if (item == children->data)
+ break;
+ children = children->next;
+ i++;
+ }
+
+ while (step > 0) {
+ if (direction < 0 && i > 0)
+ children = children->prev, i--;
+ else if (direction > 0 && i < n-1)
+ children = children->next, i++;
+ step--;
+ }
+
+ if (children && children->data) {
+ if (!multiple)
+ gtk_list_select_child(GTK_LIST(list),
+ GTK_WIDGET(children->data));
+ gtk_widget_grab_focus(GTK_WIDGET(children->data));
+ gtk_adjustment_clamp_page
+ (adj,
+ adj->lower + (adj->upper-adj->lower) * i / n,
+ adj->lower + (adj->upper-adj->lower) * (i+1) / n);
+ }
+
+ g_list_free(chead);
+ }
+ return TRUE;
+ }
+
+ return FALSE;
+}
+
+static int listitem_single_key(GtkWidget *item, GdkEventKey *event,
+ gpointer data)
+{
+ listitem_key(item, event, data, FALSE);
+}
+
+static int listitem_multi_key(GtkWidget *item, GdkEventKey *event,
+ gpointer data)
+{
+ listitem_key(item, event, data, TRUE);
+}
+
+static int listitem_button(GtkWidget *item, GdkEventButton *event,