Change to the linux kernel coding style
[wmaker-crm.git] / WINGs / wlist.c
dissimilarity index 95%
index 911b434..759fe62 100644 (file)
-
-
-
-
-#include "WINGsP.h"
-
-char *WMListDidScrollNotification = "WMListDidScrollNotification";
-char *WMListSelectionDidChangeNotification = "WMListSelectionDidChangeNotification";
-
-typedef struct W_List {
-    W_Class widgetClass;
-    W_View *view;
-
-    WMArray *items;        /* list of WMListItem */
-    WMArray *selectedItems; /* list of selected WMListItems */
-
-    short itemHeight;
-
-    int topItem;           /* index of first visible item */
-
-    short fullFitLines;            /* no of lines that fit entirely */
-
-    void *clientData;
-    WMAction *action;
-    void *doubleClientData;
-    WMAction *doubleAction;
-
-    WMListDrawProc *draw;
-
-    WMHandlerID        *idleID;    /* for updating the scroller after adding elements */
-
-    WMHandlerID        *selectID;  /* for selecting items in list while scrolling */
-
-    WMScroller *vScroller;
-
-    Pixmap doubleBuffer;
-
-    struct {
-        unsigned int allowMultipleSelection:1;
-        unsigned int allowEmptySelection:1;
-        unsigned int userDrawn:1;
-        unsigned int userItemHeight:1;
-        unsigned int dontFitAll:1;     /* 1 = last item won't be fully visible */
-        unsigned int redrawPending:1;
-        unsigned int buttonPressed:1;
-        unsigned int buttonWasPressed:1;
-    } flags;
-} List;
-
-
-
-#define DEFAULT_WIDTH  150
-#define DEFAULT_HEIGHT 150
-
-#define SCROLL_DELAY    100
-
-
-static void destroyList(List *lPtr);
-static void paintList(List *lPtr);
-
-
-static void handleEvents(XEvent *event, void *data);
-static void handleActionEvents(XEvent *event, void *data);
-
-static void updateScroller(void *data);
-static void scrollForwardSelecting(void *data);
-static void scrollBackwardSelecting(void *data);
-
-static void vScrollCallBack(WMWidget *scroller, void *self);
-
-static void toggleItemSelection(WMList *lPtr, int index);
-
-static void updateGeometry(WMList *lPtr);
-static void didResizeList();
-
-static void unselectAllListItems(WMList *lPtr, WMListItem *exceptThis);
-
-
-W_ViewDelegate _ListViewDelegate = {
-    NULL,
-    NULL,
-    didResizeList,
-    NULL,
-    NULL
-};
-
-
-static void
-updateDoubleBufferPixmap(WMList *lPtr)
-{
-    WMView *view = lPtr->view;
-    WMScreen *scr = view->screen;
-
-    if (!view->flags.realized)
-        return;
-
-    if (lPtr->doubleBuffer)
-        XFreePixmap(scr->display, lPtr->doubleBuffer);
-    lPtr->doubleBuffer =
-        XCreatePixmap(scr->display, view->window, view->size.width,
-                      lPtr->itemHeight, scr->depth);
-}
-
-
-static void
-realizeObserver(void *self, WMNotification *not)
-{
-    updateDoubleBufferPixmap(self);
-}
-
-
-static void
-releaseItem(void *data)
-{
-    WMListItem *item = (WMListItem*)data;
-
-    if (item->text)
-        wfree(item->text);
-    wfree(item);
-}
-
-
-WMList*
-WMCreateList(WMWidget *parent)
-{
-    List *lPtr;
-    W_Screen *scrPtr = W_VIEW(parent)->screen;
-
-    lPtr = wmalloc(sizeof(List));
-    memset(lPtr, 0, sizeof(List));
-
-    lPtr->widgetClass = WC_List;
-
-    lPtr->view = W_CreateView(W_VIEW(parent));
-    if (!lPtr->view) {
-        wfree(lPtr);
-        return NULL;
-    }
-    lPtr->view->self = lPtr;
-
-    lPtr->view->delegate = &_ListViewDelegate;
-
-    WMCreateEventHandler(lPtr->view, ExposureMask|StructureNotifyMask
-                         |ClientMessageMask, handleEvents, lPtr);
-
-    WMCreateEventHandler(lPtr->view, ButtonPressMask|ButtonReleaseMask
-                         |EnterWindowMask|LeaveWindowMask|ButtonMotionMask,
-                         handleActionEvents, lPtr);
-
-    lPtr->itemHeight = WMFontHeight(scrPtr->normalFont) + 1;
-
-    lPtr->items = WMCreateArrayWithDestructor(4, releaseItem);
-    lPtr->selectedItems = WMCreateArray(4);
-
-    /* create the vertical scroller */
-    lPtr->vScroller = WMCreateScroller(lPtr);
-    WMMoveWidget(lPtr->vScroller, 1, 1);
-    WMSetScrollerArrowsPosition(lPtr->vScroller, WSAMaxEnd);
-
-    WMSetScrollerAction(lPtr->vScroller, vScrollCallBack, lPtr);
-
-    /* make the scroller map itself when it's realized */
-    WMMapWidget(lPtr->vScroller);
-
-    W_ResizeView(lPtr->view, DEFAULT_WIDTH, DEFAULT_HEIGHT);
-
-    WMAddNotificationObserver(realizeObserver, lPtr,
-                              WMViewRealizedNotification, lPtr->view);
-
-    return lPtr;
-}
-
-
-void
-WMSetListAllowMultipleSelection(WMList *lPtr, Bool flag)
-{
-    lPtr->flags.allowMultipleSelection = ((flag==0) ? 0 : 1);
-}
-
-
-void
-WMSetListAllowEmptySelection(WMList *lPtr, Bool flag)
-{
-    lPtr->flags.allowEmptySelection = ((flag==0) ? 0 : 1);
-}
-
-
-static int
-comparator(const void *a, const void *b)
-{
-    return (strcmp((*(WMListItem**)a)->text, (*(WMListItem**)b)->text));
-}
-
-
-void
-WMSortListItems(WMList *lPtr)
-{
-    WMSortArray(lPtr->items, comparator);
-
-    paintList(lPtr);
-}
-
-
-
-void
-WMSortListItemsWithComparer(WMList *lPtr, WMCompareDataProc *func)
-{
-    WMSortArray(lPtr->items, func);
-
-    paintList(lPtr);
-}
-
-
-
-WMListItem*
-WMInsertListItem(WMList *lPtr, int row, char *text)
-{
-    WMListItem *item;
-
-    CHECK_CLASS(lPtr, WC_List);
-
-    item = wmalloc(sizeof(WMListItem));
-    memset(item, 0, sizeof(WMListItem));
-    item->text = wstrdup(text);
-
-    row = WMIN(row, WMGetArrayItemCount(lPtr->items));
-
-    if (row < 0)
-        WMAddToArray(lPtr->items, item);
-    else
-        WMInsertInArray(lPtr->items, row, item);
-
-    /* update the scroller when idle, so that we don't waste time
-     * updating it when another item is going to be added later */
-    if (!lPtr->idleID) {
-        lPtr->idleID = WMAddIdleHandler((WMCallback*)updateScroller, lPtr);
-    }
-
-    return item;
-}
-
-
-void
-WMRemoveListItem(WMList *lPtr, int row)
-{
-    WMListItem *item;
-    int topItem = lPtr->topItem;
-    int selNotify = 0;
-
-    CHECK_CLASS(lPtr, WC_List);
-
-    /*wassertr(row>=0 && row<WMGetArrayItemCount(lPtr->items));*/
-    if (row<0 || row>=WMGetArrayItemCount(lPtr->items))
-        return;
-
-    item = WMGetFromArray(lPtr->items, row);
-    if (item->selected) {
-        WMRemoveFromArray(lPtr->selectedItems, item);
-        selNotify = 1;
-    }
-
-    if (row <= lPtr->topItem+lPtr->fullFitLines+lPtr->flags.dontFitAll)
-        lPtr->topItem--;
-    if (lPtr->topItem < 0)
-        lPtr->topItem = 0;
-
-    WMDeleteFromArray(lPtr->items, row);
-
-    if (!lPtr->idleID) {
-        lPtr->idleID = WMAddIdleHandler((WMCallback*)updateScroller, lPtr);
-    }
-    if (lPtr->topItem != topItem) {
-        WMPostNotificationName(WMListDidScrollNotification, lPtr, NULL);
-    }
-    if (selNotify) {
-        WMPostNotificationName(WMListSelectionDidChangeNotification, lPtr, NULL);
-    }
-}
-
-
-WMListItem*
-WMGetListItem(WMList *lPtr, int row)
-{
-    return WMGetFromArray(lPtr->items, row);
-}
-
-
-WMArray*
-WMGetListItems(WMList *lPtr)
-{
-    return lPtr->items;
-}
-
-
-void
-WMSetListUserDrawProc(WMList *lPtr, WMListDrawProc *proc)
-{
-    lPtr->flags.userDrawn = 1;
-    lPtr->draw = proc;
-}
-
-
-void
-WMSetListUserDrawItemHeight(WMList *lPtr, unsigned short height)
-{
-    assert(height > 0);
-
-    lPtr->flags.userItemHeight = 1;
-    lPtr->itemHeight = height;
-
-    updateDoubleBufferPixmap(lPtr);
-
-    updateGeometry(lPtr);
-}
-
-
-void
-WMClearList(WMList *lPtr)
-{
-    int selNo = WMGetArrayItemCount(lPtr->selectedItems);
-
-    WMEmptyArray(lPtr->selectedItems);
-    WMEmptyArray(lPtr->items);
-
-    lPtr->topItem = 0;
-
-    if (!lPtr->idleID) {
-        WMDeleteIdleHandler(lPtr->idleID);
-        lPtr->idleID = NULL;
-    }
-    if (lPtr->selectID) {
-        WMDeleteTimerHandler(lPtr->selectID);
-        lPtr->selectID = NULL;
-    }
-    if (lPtr->view->flags.realized) {
-        updateScroller(lPtr);
-    }
-    if (selNo > 0) {
-        WMPostNotificationName(WMListSelectionDidChangeNotification, lPtr, NULL);
-    }
-}
-
-
-void
-WMSetListAction(WMList *lPtr, WMAction *action, void *clientData)
-{
-    lPtr->action = action;
-    lPtr->clientData = clientData;
-}
-
-
-void
-WMSetListDoubleAction(WMList *lPtr, WMAction *action, void *clientData)
-{
-    lPtr->doubleAction = action;
-    lPtr->doubleClientData = clientData;
-}
-
-
-WMArray*
-WMGetListSelectedItems(WMList *lPtr)
-{
-    return lPtr->selectedItems;
-}
-
-
-WMListItem*
-WMGetListSelectedItem(WMList *lPtr)
-{
-    return WMGetFromArray(lPtr->selectedItems, 0);
-}
-
-
-int
-WMGetListSelectedItemRow(WMList *lPtr)
-{
-    WMListItem *item = WMGetFromArray(lPtr->selectedItems, 0);
-
-    return (item!=NULL ? WMGetFirstInArray(lPtr->items, item) : WLNotFound);
-}
-
-
-int
-WMGetListItemHeight(WMList *lPtr)
-{
-    return lPtr->itemHeight;
-}
-
-
-void
-WMSetListPosition(WMList *lPtr, int row)
-{
-    lPtr->topItem = row;
-    if (lPtr->topItem + lPtr->fullFitLines > WMGetArrayItemCount(lPtr->items))
-        lPtr->topItem = WMGetArrayItemCount(lPtr->items) - lPtr->fullFitLines;
-
-    if (lPtr->topItem < 0)
-        lPtr->topItem = 0;
-
-    if (lPtr->view->flags.realized)
-        updateScroller(lPtr);
-}
-
-
-void
-WMSetListBottomPosition(WMList *lPtr, int row)
-{
-    if (WMGetArrayItemCount(lPtr->items) > lPtr->fullFitLines) {
-        lPtr->topItem = row - lPtr->fullFitLines;
-        if (lPtr->topItem < 0)
-            lPtr->topItem = 0;
-        if (lPtr->view->flags.realized)
-            updateScroller(lPtr);
-    }
-}
-
-
-int
-WMGetListNumberOfRows(WMList *lPtr)
-{
-    return WMGetArrayItemCount(lPtr->items);
-}
-
-
-int
-WMGetListPosition(WMList *lPtr)
-{
-    return lPtr->topItem;
-}
-
-
-Bool
-WMListAllowsMultipleSelection(WMList *lPtr)
-{
-    return lPtr->flags.allowMultipleSelection;
-}
-
-
-Bool
-WMListAllowsEmptySelection(WMList *lPtr)
-{
-    return lPtr->flags.allowEmptySelection;
-}
-
-
-static void
-scrollByAmount(WMList *lPtr, int amount)
-{
-    int itemCount = WMGetArrayItemCount(lPtr->items);
-
-    if ((amount < 0 && lPtr->topItem > 0) ||
-        (amount > 0 && (lPtr->topItem + lPtr->fullFitLines < itemCount))) {
-
-        lPtr->topItem += amount;
-        if (lPtr->topItem < 0)
-            lPtr->topItem = 0;
-        if (lPtr->topItem + lPtr->fullFitLines > itemCount)
-            lPtr->topItem = itemCount - lPtr->fullFitLines;
-
-        updateScroller(lPtr);
-    }
-}
-
-
-static void
-vScrollCallBack(WMWidget *scroller, void *self)
-{
-    WMList *lPtr = (WMList*)self;
-    int height;
-    int oldTopItem = lPtr->topItem;
-    int itemCount = WMGetArrayItemCount(lPtr->items);
-
-    height = lPtr->view->size.height - 4;
-
-    switch (WMGetScrollerHitPart((WMScroller*)scroller)) {
-    case WSDecrementLine:
-        scrollByAmount(lPtr, -1);
-        break;
-
-    case WSIncrementLine:
-        scrollByAmount(lPtr, 1);
-        break;
-
-    case WSDecrementPage:
-        scrollByAmount(lPtr, -lPtr->fullFitLines+(1-lPtr->flags.dontFitAll)+1);
-        break;
-
-    case WSIncrementPage:
-        scrollByAmount(lPtr, lPtr->fullFitLines-(1-lPtr->flags.dontFitAll)-1);
-        break;
-
-    case WSDecrementWheel:
-        scrollByAmount(lPtr, -lPtr->fullFitLines / 3);
-        break;
-
-    case WSIncrementWheel:
-        scrollByAmount(lPtr, lPtr->fullFitLines / 3);
-        break;
-
-    case WSKnob:
-        lPtr->topItem = WMGetScrollerValue(lPtr->vScroller) *
-            (float)(itemCount - lPtr->fullFitLines);
-
-        if (oldTopItem != lPtr->topItem)
-            paintList(lPtr); /* use updateScroller(lPtr) here? -Dan */
-        break;
-
-    case WSKnobSlot:
-    case WSNoPart:
-    default:
-        /* do nothing */
-        break;
-    }
-
-    if (lPtr->topItem != oldTopItem)
-        WMPostNotificationName(WMListDidScrollNotification, lPtr, NULL);
-}
-
-
-static void
-paintItem(List *lPtr, int index)
-{
-    WMView *view = lPtr->view;
-    W_Screen *scr = view->screen;
-    Display *display = scr->display;
-    int width, height, x, y, tlen;
-    WMListItem *itemPtr;
-    Drawable d = lPtr->doubleBuffer;
-
-    itemPtr = WMGetFromArray(lPtr->items, index);
-
-    width = lPtr->view->size.width - 2 - 19;
-    height = lPtr->itemHeight;
-    x = 19;
-    y = 2 + (index-lPtr->topItem) * lPtr->itemHeight + 1;
-    tlen = strlen(itemPtr->text);
-
-    if (lPtr->flags.userDrawn) {
-        WMRect rect;
-        int flags;
-
-
-        rect.size.width = width;
-        rect.size.height = height;
-        rect.pos.x = 0;
-        rect.pos.y = 0;
-
-        flags = itemPtr->uflags;
-        if (itemPtr->disabled)
-            flags |= WLDSDisabled;
-        if (itemPtr->selected)
-            flags |= WLDSSelected;
-        if (itemPtr->isBranch)
-            flags |= WLDSIsBranch;
-
-        if (lPtr->draw)
-            (*lPtr->draw)(lPtr, index, d, itemPtr->text, flags, &rect);
-
-        XCopyArea(display, d, view->window, scr->copyGC, 0, 0, width, height, x, y);
-    } else {
-        WMColor *back = (itemPtr->selected ? scr->white : view->backColor);
-
-        XFillRectangle(display, d, WMColorGC(back), 0, 0, width, height);
-
-        W_PaintText(view, d, scr->normalFont,  4, 0, width, WALeft, scr->black,
-                    False, itemPtr->text, tlen);
-        XCopyArea(display, d, view->window, scr->copyGC, 0, 0, width, height, x, y);
-    }
-
-    if ((index-lPtr->topItem+lPtr->fullFitLines)*lPtr->itemHeight >
-        lPtr->view->size.height-2) {
-        W_DrawRelief(lPtr->view->screen, lPtr->view->window, 0, 0,
-                     lPtr->view->size.width, lPtr->view->size.height,
-                     WRSunken);
-    }
-}
-
-
-
-static void
-paintList(List *lPtr)
-{
-    W_Screen *scrPtr = lPtr->view->screen;
-    int i, lim;
-
-    if (!lPtr->view->flags.mapped)
-        return;
-
-    if (WMGetArrayItemCount(lPtr->items) > 0) {
-        if (lPtr->topItem+lPtr->fullFitLines+lPtr->flags.dontFitAll
-            > WMGetArrayItemCount(lPtr->items)) {
-
-            lim = WMGetArrayItemCount(lPtr->items) - lPtr->topItem;
-            XClearArea(scrPtr->display, lPtr->view->window, 19,
-                       2+lim*lPtr->itemHeight, lPtr->view->size.width-21,
-                       lPtr->view->size.height-lim*lPtr->itemHeight-3, False);
-        } else {
-            lim = lPtr->fullFitLines + lPtr->flags.dontFitAll;
-        }
-        for (i = lPtr->topItem; i < lPtr->topItem + lim; i++) {
-            paintItem(lPtr, i);
-        }
-    } else {
-        XClearWindow(scrPtr->display, lPtr->view->window);
-    }
-    W_DrawRelief(scrPtr, lPtr->view->window, 0, 0, lPtr->view->size.width,
-                 lPtr->view->size.height, WRSunken);
-}
-
-#if 0
-static void
-scrollTo(List *lPtr, int newTop)
-{
-
-}
-#endif
-
-static void
-updateScroller(void *data)
-{
-    List *lPtr = (List*)data;
-
-    float knobProportion, floatValue, tmp;
-    int count = WMGetArrayItemCount(lPtr->items);
-
-    if (lPtr->idleID)
-        WMDeleteIdleHandler(lPtr->idleID);
-    lPtr->idleID = NULL;
-
-    paintList(lPtr);
-
-    if (count == 0 || count <= lPtr->fullFitLines)
-        WMSetScrollerParameters(lPtr->vScroller, 0, 1);
-    else {
-        tmp = lPtr->fullFitLines;
-        knobProportion = tmp/(float)count;
-
-        floatValue = (float)lPtr->topItem/(float)(count - lPtr->fullFitLines);
-
-        WMSetScrollerParameters(lPtr->vScroller, floatValue, knobProportion);
-    }
-}
-
-
-static void
-scrollForwardSelecting(void *data)
-{
-    List *lPtr = (List*)data;
-    int lastSelected;
-
-    lastSelected = lPtr->topItem+lPtr->fullFitLines+lPtr->flags.dontFitAll-1;
-
-    if (lastSelected >= WMGetArrayItemCount(lPtr->items)-1) {
-        lPtr->selectID = NULL;
-        if (lPtr->flags.dontFitAll)
-            scrollByAmount(lPtr, 1);
-        return;
-    }
-
-    /* selecting NEEDS to be done before scrolling to avoid flickering */
-    if (lPtr->flags.allowMultipleSelection) {
-        WMListItem *item;
-        WMRange range;
-
-        item = WMGetFromArray(lPtr->selectedItems, 0);
-        range.position = WMGetFirstInArray(lPtr->items, item);
-        if (lastSelected+1 >= range.position) {
-            range.count = lastSelected - range.position + 2;
-        } else {
-            range.count = lastSelected - range.position;
-        }
-        WMSetListSelectionToRange(lPtr, range);
-    } else {
-        WMSelectListItem(lPtr, lastSelected+1);
-    }
-    scrollByAmount(lPtr, 1);
-
-    lPtr->selectID = WMAddTimerHandler(SCROLL_DELAY, scrollForwardSelecting,
-                                       lPtr);
-}
-
-
-static void
-scrollBackwardSelecting(void *data)
-{
-    List *lPtr = (List*)data;
-
-    if (lPtr->topItem < 1) {
-        lPtr->selectID = NULL;
-        return;
-    }
-
-    /* selecting NEEDS to be done before scrolling to avoid flickering */
-    if (lPtr->flags.allowMultipleSelection) {
-        WMListItem *item;
-        WMRange range;
-
-        item = WMGetFromArray(lPtr->selectedItems, 0);
-        range.position = WMGetFirstInArray(lPtr->items, item);
-        if (lPtr->topItem-1 >= range.position) {
-            range.count = lPtr->topItem - range.position;
-        } else {
-            range.count = lPtr->topItem - range.position - 2;
-        }
-        WMSetListSelectionToRange(lPtr, range);
-    } else {
-        WMSelectListItem(lPtr, lPtr->topItem-1);
-    }
-    scrollByAmount(lPtr, -1);
-
-    lPtr->selectID = WMAddTimerHandler(SCROLL_DELAY, scrollBackwardSelecting,
-                                       lPtr);
-}
-
-
-static void
-handleEvents(XEvent *event, void *data)
-{
-    List *lPtr = (List*)data;
-
-    CHECK_CLASS(data, WC_List);
-
-
-    switch (event->type) {
-    case Expose:
-        if (event->xexpose.count!=0)
-            break;
-        paintList(lPtr);
-        break;
-
-    case DestroyNotify:
-        destroyList(lPtr);
-        break;
-
-    }
-}
-
-
-static int
-matchTitle(void *item, void *title)
-{
-    return (strcmp(((WMListItem*)item)->text, (char*)title)==0 ? 1 : 0);
-}
-
-
-int
-WMFindRowOfListItemWithTitle(WMList *lPtr, char *title)
-{
-    return WMFindInArray(lPtr->items, matchTitle, title);
-}
-
-
-void
-WMSelectListItem(WMList *lPtr, int row)
-{
-    WMListItem *item;
-
-    if (row >= WMGetArrayItemCount(lPtr->items))
-        return;
-
-    if (row < 0) {
-        /* row = -1 will deselects all for backward compatibility.
-         * will be removed later. -Dan */
-        WMUnselectAllListItems(lPtr);
-        return;
-    }
-
-    item = WMGetFromArray(lPtr->items, row);
-    if (item->selected)
-        return;           /* Return if already selected */
-
-    if (!lPtr->flags.allowMultipleSelection) {
-        /* unselect previous selected items */
-        unselectAllListItems(lPtr, NULL);
-    }
-
-    /* select item */
-    item->selected = 1;
-    WMAddToArray(lPtr->selectedItems, item);
-
-    if (lPtr->view->flags.mapped && row>=lPtr->topItem
-        && row<=lPtr->topItem+lPtr->fullFitLines) {
-        paintItem(lPtr, row);
-    }
-
-    WMPostNotificationName(WMListSelectionDidChangeNotification, lPtr, NULL);
-}
-
-
-void
-WMUnselectListItem(WMList *lPtr, int row)
-{
-    WMListItem *item = WMGetFromArray(lPtr->items, row);
-
-    if (!item || !item->selected)
-        return;
-
-    if (!lPtr->flags.allowEmptySelection &&
-        WMGetArrayItemCount(lPtr->selectedItems) <= 1) {
-        return;
-    }
-
-    item->selected = 0;
-    WMRemoveFromArray(lPtr->selectedItems, item);
-
-    if (lPtr->view->flags.mapped && row>=lPtr->topItem
-        && row<=lPtr->topItem+lPtr->fullFitLines) {
-        paintItem(lPtr, row);
-    }
-
-    WMPostNotificationName(WMListSelectionDidChangeNotification, lPtr, NULL);
-}
-
-
-void
-WMSelectListItemsInRange(WMList *lPtr, WMRange range)
-{
-    WMListItem *item;
-    int position = range.position, k = 1, notify = 0;
-    int total = WMGetArrayItemCount(lPtr->items);
-
-    if (!lPtr->flags.allowMultipleSelection)
-        return;
-    if (range.count==0)
-        return; /* Nothing to select */
-
-    if (range.count < 0) {
-        range.count = -range.count;
-        k = -1;
-    }
-
-    for (; range.count>0 && position>=0 && position<total; range.count--) {
-        item = WMGetFromArray(lPtr->items, position);
-        if (!item->selected) {
-            item->selected = 1;
-            WMAddToArray(lPtr->selectedItems, item);
-            if (lPtr->view->flags.mapped && position>=lPtr->topItem
-                && position<=lPtr->topItem+lPtr->fullFitLines) {
-                paintItem(lPtr, position);
-            }
-            notify = 1;
-        }
-        position += k;
-    }
-
-    if (notify) {
-        WMPostNotificationName(WMListSelectionDidChangeNotification, lPtr, NULL);
-    }
-}
-
-
-void
-WMSetListSelectionToRange(WMList *lPtr, WMRange range)
-{
-    WMListItem *item;
-    int mark1, mark2, i, k;
-    int position = range.position, notify = 0;
-    int total = WMGetArrayItemCount(lPtr->items);
-
-    if (!lPtr->flags.allowMultipleSelection)
-        return;
-
-    if (range.count==0) {
-        WMUnselectAllListItems(lPtr);
-        return;
-    }
-
-    if (range.count < 0) {
-        mark1 = range.position + range.count + 1;
-        mark2 = range.position + 1;
-        range.count = -range.count;
-        k = -1;
-    } else {
-        mark1 = range.position;
-        mark2 = range.position + range.count;
-        k = 1;
-    }
-    if (mark1 > total)
-        mark1 = total;
-    if (mark2 < 0)
-        mark2 = 0;
-
-    WMEmptyArray(lPtr->selectedItems);
-
-    for (i=0; i<mark1; i++) {
-        item = WMGetFromArray(lPtr->items, i);
-        if (item->selected) {
-            item->selected = 0;
-            if (lPtr->view->flags.mapped && i>=lPtr->topItem
-                && i<=lPtr->topItem+lPtr->fullFitLines) {
-                paintItem(lPtr, i);
-            }
-            notify = 1;
-        }
-    }
-    for (; range.count>0 && position>=0 && position<total; range.count--) {
-        item = WMGetFromArray(lPtr->items, position);
-        if (!item->selected) {
-            item->selected = 1;
-            if (lPtr->view->flags.mapped && position>=lPtr->topItem
-                && position<=lPtr->topItem+lPtr->fullFitLines) {
-                paintItem(lPtr, position);
-            }
-            notify = 1;
-        }
-        WMAddToArray(lPtr->selectedItems, item);
-        position += k;
-    }
-    for (i=mark2; i<total; i++) {
-        item = WMGetFromArray(lPtr->items, i);
-        if (item->selected) {
-            item->selected = 0;
-            if (lPtr->view->flags.mapped && i>=lPtr->topItem
-                && i<=lPtr->topItem+lPtr->fullFitLines) {
-                paintItem(lPtr, i);
-            }
-            notify = 1;
-        }
-    }
-
-    if (notify) {
-        WMPostNotificationName(WMListSelectionDidChangeNotification, lPtr, NULL);
-    }
-}
-
-
-void
-WMSelectAllListItems(WMList *lPtr)
-{
-    int i;
-    WMListItem *item;
-
-    if (!lPtr->flags.allowMultipleSelection)
-        return;
-
-    if (WMGetArrayItemCount(lPtr->items) ==
-        WMGetArrayItemCount(lPtr->selectedItems)) {
-        return; /* All items are selected already */
-    }
-
-    WMFreeArray(lPtr->selectedItems);
-    lPtr->selectedItems = WMCreateArrayWithArray(lPtr->items);
-
-    for (i=0; i<WMGetArrayItemCount(lPtr->items); i++) {
-        item = WMGetFromArray(lPtr->items, i);
-        if (!item->selected) {
-            item->selected = 1;
-            if (lPtr->view->flags.mapped && i>=lPtr->topItem
-                && i<=lPtr->topItem+lPtr->fullFitLines) {
-                paintItem(lPtr, i);
-            }
-        }
-    }
-
-    WMPostNotificationName(WMListSelectionDidChangeNotification, lPtr, NULL);
-}
-
-/*
- * Be careful from where you call this function! It doesn't honor the
- * allowEmptySelection flag and doesn't send a notification about selection
- * change! You need to manage these in the functions from where you call it.
- *
- * This will unselect all items if exceptThis is NULL, else will keep
- * exceptThis selected.
- * Make sure that exceptThis is one of the already selected items if not NULL!
- *
- */
-static void
-unselectAllListItems(WMList *lPtr, WMListItem *exceptThis)
-{
-    int i;
-    WMListItem *item;
-
-    for (i=0; i<WMGetArrayItemCount(lPtr->items); i++) {
-        item = WMGetFromArray(lPtr->items, i);
-        if (item!=exceptThis && item->selected) {
-            item->selected = 0;
-            if (lPtr->view->flags.mapped && i>=lPtr->topItem
-                && i<=lPtr->topItem+lPtr->fullFitLines) {
-                paintItem(lPtr, i);
-            }
-        }
-    }
-
-    WMEmptyArray(lPtr->selectedItems);
-    if (exceptThis!=NULL) {
-        exceptThis->selected = 1;
-        WMAddToArray(lPtr->selectedItems, exceptThis);
-    }
-}
-
-
-void
-WMUnselectAllListItems(WMList *lPtr)
-{
-    int keep;
-    WMListItem *keepItem;
-
-    keep = lPtr->flags.allowEmptySelection ? 0 : 1;
-
-    if (WMGetArrayItemCount(lPtr->selectedItems) == keep)
-        return;
-
-    keepItem = (keep==1 ? WMGetFromArray(lPtr->selectedItems, 0) : NULL);
-
-    unselectAllListItems(lPtr, keepItem);
-
-    WMPostNotificationName(WMListSelectionDidChangeNotification, lPtr, NULL);
-}
-
-
-static int
-getItemIndexAt(List *lPtr, int clickY)
-{
-    int index;
-
-    index = (clickY - 2) / lPtr->itemHeight + lPtr->topItem;
-
-    if (index < 0 || index >= WMGetArrayItemCount(lPtr->items))
-        return -1;
-
-    return index;
-}
-
-
-static void
-toggleItemSelection(WMList *lPtr, int index)
-{
-    WMListItem *item = WMGetFromArray(lPtr->items, index);
-
-    if (item && item->selected) {
-        WMUnselectListItem(lPtr, index);
-    } else {
-        WMSelectListItem(lPtr, index);
-    }
-}
-
-
-static void
-handleActionEvents(XEvent *event, void *data)
-{
-    List *lPtr = (List*)data;
-    int tmp, height;
-    int topItem = lPtr->topItem;
-    static int lastClicked = -1, prevItem = -1;
-
-    CHECK_CLASS(data, WC_List);
-
-    switch (event->type) {
-    case ButtonRelease:
-        /* Ignore mouse wheel events, they're not "real" button events */
-        if (event->xbutton.button == WINGsConfiguration.mouseWheelUp ||
-            event->xbutton.button == WINGsConfiguration.mouseWheelDown) {
-            break;
-        }
-
-        lPtr->flags.buttonPressed = 0;
-        if (lPtr->selectID) {
-            WMDeleteTimerHandler(lPtr->selectID);
-            lPtr->selectID = NULL;
-        }
-        tmp = getItemIndexAt(lPtr, event->xbutton.y);
-
-        if (tmp >= 0) {
-            if (lPtr->action)
-                (*lPtr->action)(lPtr, lPtr->clientData);
-        }
-
-        if (!(event->xbutton.state & ShiftMask))
-            lastClicked = prevItem = tmp;
-
-        break;
-
-    case EnterNotify:
-        if (lPtr->selectID) {
-            WMDeleteTimerHandler(lPtr->selectID);
-            lPtr->selectID = NULL;
-        }
-        break;
-
-    case LeaveNotify:
-        height = WMWidgetHeight(lPtr);
-        if (lPtr->flags.buttonPressed && !lPtr->selectID) {
-            if (event->xcrossing.y >= height) {
-                lPtr->selectID = WMAddTimerHandler(SCROLL_DELAY,
-                                                   scrollForwardSelecting,
-                                                   lPtr);
-            } else if (event->xcrossing.y <= 0) {
-                lPtr->selectID = WMAddTimerHandler(SCROLL_DELAY,
-                                                   scrollBackwardSelecting,
-                                                   lPtr);
-            }
-        }
-        break;
-
-    case ButtonPress:
-        if (event->xbutton.x <= WMWidgetWidth(lPtr->vScroller))
-            break;
-        if (event->xbutton.button == WINGsConfiguration.mouseWheelDown ||
-            event->xbutton.button == WINGsConfiguration.mouseWheelUp) {
-            int amount = 0;
-
-            if (event->xbutton.state & ControlMask) {
-                amount = lPtr->fullFitLines-(1-lPtr->flags.dontFitAll)-1;
-            } else if (event->xbutton.state & ShiftMask) {
-                amount = 1;
-            } else {
-                amount = lPtr->fullFitLines / 3;
-                if (amount == 0)
-                    amount++;
-            }
-            if (event->xbutton.button == WINGsConfiguration.mouseWheelUp)
-                amount = -amount;
-
-            scrollByAmount(lPtr, amount);
-            break;
-        }
-
-        tmp = getItemIndexAt(lPtr, event->xbutton.y);
-        lPtr->flags.buttonPressed = 1;
-
-        if (tmp >= 0) {
-            if (tmp == lastClicked && WMIsDoubleClick(event)) {
-                WMSelectListItem(lPtr, tmp);
-                if (lPtr->doubleAction)
-                    (*lPtr->doubleAction)(lPtr, lPtr->doubleClientData);
-            } else {
-                if (!lPtr->flags.allowMultipleSelection) {
-                    if (event->xbutton.state & ControlMask) {
-                        toggleItemSelection(lPtr, tmp);
-                    } else {
-                        WMSelectListItem(lPtr, tmp);
-                    }
-                } else {
-                    WMRange range;
-                    WMListItem *lastSel;
-
-                    if (event->xbutton.state & ControlMask) {
-                        toggleItemSelection(lPtr, tmp);
-                    } else if (event->xbutton.state & ShiftMask) {
-                        if (WMGetArrayItemCount(lPtr->selectedItems) == 0) {
-                            WMSelectListItem(lPtr, tmp);
-                        } else {
-                            lastSel = WMGetFromArray(lPtr->items, lastClicked);
-                            range.position = WMGetFirstInArray(lPtr->items,
-                                                               lastSel);
-                            if (tmp >= range.position)
-                                range.count = tmp - range.position + 1;
-                            else
-                                range.count = tmp - range.position - 1;
-
-                            WMSetListSelectionToRange(lPtr, range);
-                        }
-                    } else {
-                        range.position = tmp;
-                        range.count = 1;
-                        WMSetListSelectionToRange(lPtr, range);
-                    }
-                }
-            }
-        }
-
-        if (!(event->xbutton.state & ShiftMask))
-            lastClicked = prevItem = tmp;
-
-        break;
-
-    case MotionNotify:
-        height = WMWidgetHeight(lPtr);
-        if (lPtr->selectID && event->xmotion.y>0 && event->xmotion.y<height) {
-            WMDeleteTimerHandler(lPtr->selectID);
-            lPtr->selectID = NULL;
-        }
-        if (lPtr->flags.buttonPressed && !lPtr->selectID) {
-            if (event->xmotion.y <= 0) {
-                lPtr->selectID = WMAddTimerHandler(SCROLL_DELAY,
-                                                   scrollBackwardSelecting,
-                                                   lPtr);
-                break;
-            } else if (event->xmotion.y >= height) {
-                lPtr->selectID = WMAddTimerHandler(SCROLL_DELAY,
-                                                   scrollForwardSelecting,
-                                                   lPtr);
-                break;
-            }
-
-            tmp = getItemIndexAt(lPtr, event->xmotion.y);
-            if (tmp>=0 && tmp!=prevItem) {
-                if (lPtr->flags.allowMultipleSelection) {
-                    WMRange range;
-
-                    range.position = lastClicked;
-                    if (tmp >= lastClicked)
-                        range.count = tmp - lastClicked + 1;
-                    else
-                        range.count = tmp - lastClicked - 1;
-                    WMSetListSelectionToRange(lPtr, range);
-                } else {
-                    WMSelectListItem(lPtr, tmp);
-                }
-            }
-            prevItem = tmp;
-        }
-        break;
-    }
-    if (lPtr->topItem != topItem)
-        WMPostNotificationName(WMListDidScrollNotification, lPtr, NULL);
-}
-
-
-static void
-updateGeometry(WMList *lPtr)
-{
-    lPtr->fullFitLines = (lPtr->view->size.height - 4) / lPtr->itemHeight;
-    if (lPtr->fullFitLines * lPtr->itemHeight < lPtr->view->size.height - 4) {
-        lPtr->flags.dontFitAll = 1;
-    } else {
-        lPtr->flags.dontFitAll = 0;
-    }
-
-    if (WMGetArrayItemCount(lPtr->items) - lPtr->topItem <= lPtr->fullFitLines) {
-        lPtr->topItem = WMGetArrayItemCount(lPtr->items) - lPtr->fullFitLines;
-        if (lPtr->topItem < 0)
-            lPtr->topItem = 0;
-    }
-
-    updateScroller(lPtr);
-}
-
-
-static void
-didResizeList(W_ViewDelegate *self, WMView *view)
-{
-    WMList *lPtr = (WMList*)view->self;
-
-    WMResizeWidget(lPtr->vScroller, 1, view->size.height-2);
-
-    updateDoubleBufferPixmap(lPtr);
-
-    updateGeometry(lPtr);
-}
-
-
-static void
-destroyList(List *lPtr)
-{
-    if (lPtr->idleID)
-        WMDeleteIdleHandler(lPtr->idleID);
-    lPtr->idleID = NULL;
-
-    if (lPtr->selectID)
-        WMDeleteTimerHandler(lPtr->selectID);
-    lPtr->selectID = NULL;
-
-    if (lPtr->selectedItems)
-        WMFreeArray(lPtr->selectedItems);
-
-    if (lPtr->items)
-        WMFreeArray(lPtr->items);
-
-    if (lPtr->doubleBuffer)
-        XFreePixmap(lPtr->view->screen->display, lPtr->doubleBuffer);
-
-    WMRemoveNotificationObserver(lPtr);
-
-    wfree(lPtr);
-}
-
-
+
+#include "WINGsP.h"
+
+char *WMListDidScrollNotification = "WMListDidScrollNotification";
+char *WMListSelectionDidChangeNotification = "WMListSelectionDidChangeNotification";
+
+typedef struct W_List {
+       W_Class widgetClass;
+       W_View *view;
+
+       WMArray *items;         /* list of WMListItem */
+       WMArray *selectedItems; /* list of selected WMListItems */
+
+       short itemHeight;
+
+       int topItem;            /* index of first visible item */
+
+       short fullFitLines;     /* no of lines that fit entirely */
+
+       void *clientData;
+       WMAction *action;
+       void *doubleClientData;
+       WMAction *doubleAction;
+
+       WMListDrawProc *draw;
+
+       WMHandlerID *idleID;    /* for updating the scroller after adding elements */
+
+       WMHandlerID *selectID;  /* for selecting items in list while scrolling */
+
+       WMScroller *vScroller;
+
+       Pixmap doubleBuffer;
+
+       struct {
+               unsigned int allowMultipleSelection:1;
+               unsigned int allowEmptySelection:1;
+               unsigned int userDrawn:1;
+               unsigned int userItemHeight:1;
+               unsigned int dontFitAll:1;      /* 1 = last item won't be fully visible */
+               unsigned int redrawPending:1;
+               unsigned int buttonPressed:1;
+               unsigned int buttonWasPressed:1;
+       } flags;
+} List;
+
+#define DEFAULT_WIDTH  150
+#define DEFAULT_HEIGHT 150
+
+#define SCROLL_DELAY    100
+
+static void destroyList(List * lPtr);
+static void paintList(List * lPtr);
+
+static void handleEvents(XEvent * event, void *data);
+static void handleActionEvents(XEvent * event, void *data);
+
+static void updateScroller(void *data);
+static void scrollForwardSelecting(void *data);
+static void scrollBackwardSelecting(void *data);
+
+static void vScrollCallBack(WMWidget * scroller, void *self);
+
+static void toggleItemSelection(WMList * lPtr, int index);
+
+static void updateGeometry(WMList * lPtr);
+static void didResizeList();
+
+static void unselectAllListItems(WMList * lPtr, WMListItem * exceptThis);
+
+W_ViewDelegate _ListViewDelegate = {
+       NULL,
+       NULL,
+       didResizeList,
+       NULL,
+       NULL
+};
+
+static void updateDoubleBufferPixmap(WMList * lPtr)
+{
+       WMView *view = lPtr->view;
+       WMScreen *scr = view->screen;
+
+       if (!view->flags.realized)
+               return;
+
+       if (lPtr->doubleBuffer)
+               XFreePixmap(scr->display, lPtr->doubleBuffer);
+       lPtr->doubleBuffer =
+           XCreatePixmap(scr->display, view->window, view->size.width, lPtr->itemHeight, scr->depth);
+}
+
+static void realizeObserver(void *self, WMNotification * not)
+{
+       updateDoubleBufferPixmap(self);
+}
+
+static void releaseItem(void *data)
+{
+       WMListItem *item = (WMListItem *) data;
+
+       if (item->text)
+               wfree(item->text);
+       wfree(item);
+}
+
+WMList *WMCreateList(WMWidget * parent)
+{
+       List *lPtr;
+       W_Screen *scrPtr = W_VIEW(parent)->screen;
+
+       lPtr = wmalloc(sizeof(List));
+       memset(lPtr, 0, sizeof(List));
+
+       lPtr->widgetClass = WC_List;
+
+       lPtr->view = W_CreateView(W_VIEW(parent));
+       if (!lPtr->view) {
+               wfree(lPtr);
+               return NULL;
+       }
+       lPtr->view->self = lPtr;
+
+       lPtr->view->delegate = &_ListViewDelegate;
+
+       WMCreateEventHandler(lPtr->view, ExposureMask | StructureNotifyMask
+                            | ClientMessageMask, handleEvents, lPtr);
+
+       WMCreateEventHandler(lPtr->view, ButtonPressMask | ButtonReleaseMask
+                            | EnterWindowMask | LeaveWindowMask | ButtonMotionMask, handleActionEvents, lPtr);
+
+       lPtr->itemHeight = WMFontHeight(scrPtr->normalFont) + 1;
+
+       lPtr->items = WMCreateArrayWithDestructor(4, releaseItem);
+       lPtr->selectedItems = WMCreateArray(4);
+
+       /* create the vertical scroller */
+       lPtr->vScroller = WMCreateScroller(lPtr);
+       WMMoveWidget(lPtr->vScroller, 1, 1);
+       WMSetScrollerArrowsPosition(lPtr->vScroller, WSAMaxEnd);
+
+       WMSetScrollerAction(lPtr->vScroller, vScrollCallBack, lPtr);
+
+       /* make the scroller map itself when it's realized */
+       WMMapWidget(lPtr->vScroller);
+
+       W_ResizeView(lPtr->view, DEFAULT_WIDTH, DEFAULT_HEIGHT);
+
+       WMAddNotificationObserver(realizeObserver, lPtr, WMViewRealizedNotification, lPtr->view);
+
+       return lPtr;
+}
+
+void WMSetListAllowMultipleSelection(WMList * lPtr, Bool flag)
+{
+       lPtr->flags.allowMultipleSelection = ((flag == 0) ? 0 : 1);
+}
+
+void WMSetListAllowEmptySelection(WMList * lPtr, Bool flag)
+{
+       lPtr->flags.allowEmptySelection = ((flag == 0) ? 0 : 1);
+}
+
+static int comparator(const void *a, const void *b)
+{
+       return (strcmp((*(WMListItem **) a)->text, (*(WMListItem **) b)->text));
+}
+
+void WMSortListItems(WMList * lPtr)
+{
+       WMSortArray(lPtr->items, comparator);
+
+       paintList(lPtr);
+}
+
+void WMSortListItemsWithComparer(WMList * lPtr, WMCompareDataProc * func)
+{
+       WMSortArray(lPtr->items, func);
+
+       paintList(lPtr);
+}
+
+WMListItem *WMInsertListItem(WMList * lPtr, int row, char *text)
+{
+       WMListItem *item;
+
+       CHECK_CLASS(lPtr, WC_List);
+
+       item = wmalloc(sizeof(WMListItem));
+       memset(item, 0, sizeof(WMListItem));
+       item->text = wstrdup(text);
+
+       row = WMIN(row, WMGetArrayItemCount(lPtr->items));
+
+       if (row < 0)
+               WMAddToArray(lPtr->items, item);
+       else
+               WMInsertInArray(lPtr->items, row, item);
+
+       /* update the scroller when idle, so that we don't waste time
+        * updating it when another item is going to be added later */
+       if (!lPtr->idleID) {
+               lPtr->idleID = WMAddIdleHandler((WMCallback *) updateScroller, lPtr);
+       }
+
+       return item;
+}
+
+void WMRemoveListItem(WMList * lPtr, int row)
+{
+       WMListItem *item;
+       int topItem = lPtr->topItem;
+       int selNotify = 0;
+
+       CHECK_CLASS(lPtr, WC_List);
+
+       /*wassertr(row>=0 && row<WMGetArrayItemCount(lPtr->items)); */
+       if (row < 0 || row >= WMGetArrayItemCount(lPtr->items))
+               return;
+
+       item = WMGetFromArray(lPtr->items, row);
+       if (item->selected) {
+               WMRemoveFromArray(lPtr->selectedItems, item);
+               selNotify = 1;
+       }
+
+       if (row <= lPtr->topItem + lPtr->fullFitLines + lPtr->flags.dontFitAll)
+               lPtr->topItem--;
+       if (lPtr->topItem < 0)
+               lPtr->topItem = 0;
+
+       WMDeleteFromArray(lPtr->items, row);
+
+       if (!lPtr->idleID) {
+               lPtr->idleID = WMAddIdleHandler((WMCallback *) updateScroller, lPtr);
+       }
+       if (lPtr->topItem != topItem) {
+               WMPostNotificationName(WMListDidScrollNotification, lPtr, NULL);
+       }
+       if (selNotify) {
+               WMPostNotificationName(WMListSelectionDidChangeNotification, lPtr, NULL);
+       }
+}
+
+WMListItem *WMGetListItem(WMList * lPtr, int row)
+{
+       return WMGetFromArray(lPtr->items, row);
+}
+
+WMArray *WMGetListItems(WMList * lPtr)
+{
+       return lPtr->items;
+}
+
+void WMSetListUserDrawProc(WMList * lPtr, WMListDrawProc * proc)
+{
+       lPtr->flags.userDrawn = 1;
+       lPtr->draw = proc;
+}
+
+void WMSetListUserDrawItemHeight(WMList * lPtr, unsigned short height)
+{
+       assert(height > 0);
+
+       lPtr->flags.userItemHeight = 1;
+       lPtr->itemHeight = height;
+
+       updateDoubleBufferPixmap(lPtr);
+
+       updateGeometry(lPtr);
+}
+
+void WMClearList(WMList * lPtr)
+{
+       int selNo = WMGetArrayItemCount(lPtr->selectedItems);
+
+       WMEmptyArray(lPtr->selectedItems);
+       WMEmptyArray(lPtr->items);
+
+       lPtr->topItem = 0;
+
+       if (!lPtr->idleID) {
+               WMDeleteIdleHandler(lPtr->idleID);
+               lPtr->idleID = NULL;
+       }
+       if (lPtr->selectID) {
+               WMDeleteTimerHandler(lPtr->selectID);
+               lPtr->selectID = NULL;
+       }
+       if (lPtr->view->flags.realized) {
+               updateScroller(lPtr);
+       }
+       if (selNo > 0) {
+               WMPostNotificationName(WMListSelectionDidChangeNotification, lPtr, NULL);
+       }
+}
+
+void WMSetListAction(WMList * lPtr, WMAction * action, void *clientData)
+{
+       lPtr->action = action;
+       lPtr->clientData = clientData;
+}
+
+void WMSetListDoubleAction(WMList * lPtr, WMAction * action, void *clientData)
+{
+       lPtr->doubleAction = action;
+       lPtr->doubleClientData = clientData;
+}
+
+WMArray *WMGetListSelectedItems(WMList * lPtr)
+{
+       return lPtr->selectedItems;
+}
+
+WMListItem *WMGetListSelectedItem(WMList * lPtr)
+{
+       return WMGetFromArray(lPtr->selectedItems, 0);
+}
+
+int WMGetListSelectedItemRow(WMList * lPtr)
+{
+       WMListItem *item = WMGetFromArray(lPtr->selectedItems, 0);
+
+       return (item != NULL ? WMGetFirstInArray(lPtr->items, item) : WLNotFound);
+}
+
+int WMGetListItemHeight(WMList * lPtr)
+{
+       return lPtr->itemHeight;
+}
+
+void WMSetListPosition(WMList * lPtr, int row)
+{
+       lPtr->topItem = row;
+       if (lPtr->topItem + lPtr->fullFitLines > WMGetArrayItemCount(lPtr->items))
+               lPtr->topItem = WMGetArrayItemCount(lPtr->items) - lPtr->fullFitLines;
+
+       if (lPtr->topItem < 0)
+               lPtr->topItem = 0;
+
+       if (lPtr->view->flags.realized)
+               updateScroller(lPtr);
+}
+
+void WMSetListBottomPosition(WMList * lPtr, int row)
+{
+       if (WMGetArrayItemCount(lPtr->items) > lPtr->fullFitLines) {
+               lPtr->topItem = row - lPtr->fullFitLines;
+               if (lPtr->topItem < 0)
+                       lPtr->topItem = 0;
+               if (lPtr->view->flags.realized)
+                       updateScroller(lPtr);
+       }
+}
+
+int WMGetListNumberOfRows(WMList * lPtr)
+{
+       return WMGetArrayItemCount(lPtr->items);
+}
+
+int WMGetListPosition(WMList * lPtr)
+{
+       return lPtr->topItem;
+}
+
+Bool WMListAllowsMultipleSelection(WMList * lPtr)
+{
+       return lPtr->flags.allowMultipleSelection;
+}
+
+Bool WMListAllowsEmptySelection(WMList * lPtr)
+{
+       return lPtr->flags.allowEmptySelection;
+}
+
+static void scrollByAmount(WMList * lPtr, int amount)
+{
+       int itemCount = WMGetArrayItemCount(lPtr->items);
+
+       if ((amount < 0 && lPtr->topItem > 0) || (amount > 0 && (lPtr->topItem + lPtr->fullFitLines < itemCount))) {
+
+               lPtr->topItem += amount;
+               if (lPtr->topItem < 0)
+                       lPtr->topItem = 0;
+               if (lPtr->topItem + lPtr->fullFitLines > itemCount)
+                       lPtr->topItem = itemCount - lPtr->fullFitLines;
+
+               updateScroller(lPtr);
+       }
+}
+
+static void vScrollCallBack(WMWidget * scroller, void *self)
+{
+       WMList *lPtr = (WMList *) self;
+       int height;
+       int oldTopItem = lPtr->topItem;
+       int itemCount = WMGetArrayItemCount(lPtr->items);
+
+       height = lPtr->view->size.height - 4;
+
+       switch (WMGetScrollerHitPart((WMScroller *) scroller)) {
+       case WSDecrementLine:
+               scrollByAmount(lPtr, -1);
+               break;
+
+       case WSIncrementLine:
+               scrollByAmount(lPtr, 1);
+               break;
+
+       case WSDecrementPage:
+               scrollByAmount(lPtr, -lPtr->fullFitLines + (1 - lPtr->flags.dontFitAll) + 1);
+               break;
+
+       case WSIncrementPage:
+               scrollByAmount(lPtr, lPtr->fullFitLines - (1 - lPtr->flags.dontFitAll) - 1);
+               break;
+
+       case WSDecrementWheel:
+               scrollByAmount(lPtr, -lPtr->fullFitLines / 3);
+               break;
+
+       case WSIncrementWheel:
+               scrollByAmount(lPtr, lPtr->fullFitLines / 3);
+               break;
+
+       case WSKnob:
+               lPtr->topItem = WMGetScrollerValue(lPtr->vScroller) * (float)(itemCount - lPtr->fullFitLines);
+
+               if (oldTopItem != lPtr->topItem)
+                       paintList(lPtr);        /* use updateScroller(lPtr) here? -Dan */
+               break;
+
+       case WSKnobSlot:
+       case WSNoPart:
+       default:
+               /* do nothing */
+               break;
+       }
+
+       if (lPtr->topItem != oldTopItem)
+               WMPostNotificationName(WMListDidScrollNotification, lPtr, NULL);
+}
+
+static void paintItem(List * lPtr, int index)
+{
+       WMView *view = lPtr->view;
+       W_Screen *scr = view->screen;
+       Display *display = scr->display;
+       int width, height, x, y, tlen;
+       WMListItem *itemPtr;
+       Drawable d = lPtr->doubleBuffer;
+
+       itemPtr = WMGetFromArray(lPtr->items, index);
+
+       width = lPtr->view->size.width - 2 - 19;
+       height = lPtr->itemHeight;
+       x = 19;
+       y = 2 + (index - lPtr->topItem) * lPtr->itemHeight + 1;
+       tlen = strlen(itemPtr->text);
+
+       if (lPtr->flags.userDrawn) {
+               WMRect rect;
+               int flags;
+
+               rect.size.width = width;
+               rect.size.height = height;
+               rect.pos.x = 0;
+               rect.pos.y = 0;
+
+               flags = itemPtr->uflags;
+               if (itemPtr->disabled)
+                       flags |= WLDSDisabled;
+               if (itemPtr->selected)
+                       flags |= WLDSSelected;
+               if (itemPtr->isBranch)
+                       flags |= WLDSIsBranch;
+
+               if (lPtr->draw)
+                       (*lPtr->draw) (lPtr, index, d, itemPtr->text, flags, &rect);
+
+               XCopyArea(display, d, view->window, scr->copyGC, 0, 0, width, height, x, y);
+       } else {
+               WMColor *back = (itemPtr->selected ? scr->white : view->backColor);
+
+               XFillRectangle(display, d, WMColorGC(back), 0, 0, width, height);
+
+               W_PaintText(view, d, scr->normalFont, 4, 0, width, WALeft, scr->black, False, itemPtr->text, tlen);
+               XCopyArea(display, d, view->window, scr->copyGC, 0, 0, width, height, x, y);
+       }
+
+       if ((index - lPtr->topItem + lPtr->fullFitLines) * lPtr->itemHeight > lPtr->view->size.height - 2) {
+               W_DrawRelief(lPtr->view->screen, lPtr->view->window, 0, 0,
+                            lPtr->view->size.width, lPtr->view->size.height, WRSunken);
+       }
+}
+
+static void paintList(List * lPtr)
+{
+       W_Screen *scrPtr = lPtr->view->screen;
+       int i, lim;
+
+       if (!lPtr->view->flags.mapped)
+               return;
+
+       if (WMGetArrayItemCount(lPtr->items) > 0) {
+               if (lPtr->topItem + lPtr->fullFitLines + lPtr->flags.dontFitAll > WMGetArrayItemCount(lPtr->items)) {
+
+                       lim = WMGetArrayItemCount(lPtr->items) - lPtr->topItem;
+                       XClearArea(scrPtr->display, lPtr->view->window, 19,
+                                  2 + lim * lPtr->itemHeight, lPtr->view->size.width - 21,
+                                  lPtr->view->size.height - lim * lPtr->itemHeight - 3, False);
+               } else {
+                       lim = lPtr->fullFitLines + lPtr->flags.dontFitAll;
+               }
+               for (i = lPtr->topItem; i < lPtr->topItem + lim; i++) {
+                       paintItem(lPtr, i);
+               }
+       } else {
+               XClearWindow(scrPtr->display, lPtr->view->window);
+       }
+       W_DrawRelief(scrPtr, lPtr->view->window, 0, 0, lPtr->view->size.width, lPtr->view->size.height, WRSunken);
+}
+
+#if 0
+static void scrollTo(List * lPtr, int newTop)
+{
+
+}
+#endif
+
+static void updateScroller(void *data)
+{
+       List *lPtr = (List *) data;
+
+       float knobProportion, floatValue, tmp;
+       int count = WMGetArrayItemCount(lPtr->items);
+
+       if (lPtr->idleID)
+               WMDeleteIdleHandler(lPtr->idleID);
+       lPtr->idleID = NULL;
+
+       paintList(lPtr);
+
+       if (count == 0 || count <= lPtr->fullFitLines)
+               WMSetScrollerParameters(lPtr->vScroller, 0, 1);
+       else {
+               tmp = lPtr->fullFitLines;
+               knobProportion = tmp / (float)count;
+
+               floatValue = (float)lPtr->topItem / (float)(count - lPtr->fullFitLines);
+
+               WMSetScrollerParameters(lPtr->vScroller, floatValue, knobProportion);
+       }
+}
+
+static void scrollForwardSelecting(void *data)
+{
+       List *lPtr = (List *) data;
+       int lastSelected;
+
+       lastSelected = lPtr->topItem + lPtr->fullFitLines + lPtr->flags.dontFitAll - 1;
+
+       if (lastSelected >= WMGetArrayItemCount(lPtr->items) - 1) {
+               lPtr->selectID = NULL;
+               if (lPtr->flags.dontFitAll)
+                       scrollByAmount(lPtr, 1);
+               return;
+       }
+
+       /* selecting NEEDS to be done before scrolling to avoid flickering */
+       if (lPtr->flags.allowMultipleSelection) {
+               WMListItem *item;
+               WMRange range;
+
+               item = WMGetFromArray(lPtr->selectedItems, 0);
+               range.position = WMGetFirstInArray(lPtr->items, item);
+               if (lastSelected + 1 >= range.position) {
+                       range.count = lastSelected - range.position + 2;
+               } else {
+                       range.count = lastSelected - range.position;
+               }
+               WMSetListSelectionToRange(lPtr, range);
+       } else {
+               WMSelectListItem(lPtr, lastSelected + 1);
+       }
+       scrollByAmount(lPtr, 1);
+
+       lPtr->selectID = WMAddTimerHandler(SCROLL_DELAY, scrollForwardSelecting, lPtr);
+}
+
+static void scrollBackwardSelecting(void *data)
+{
+       List *lPtr = (List *) data;
+
+       if (lPtr->topItem < 1) {
+               lPtr->selectID = NULL;
+               return;
+       }
+
+       /* selecting NEEDS to be done before scrolling to avoid flickering */
+       if (lPtr->flags.allowMultipleSelection) {
+               WMListItem *item;
+               WMRange range;
+
+               item = WMGetFromArray(lPtr->selectedItems, 0);
+               range.position = WMGetFirstInArray(lPtr->items, item);
+               if (lPtr->topItem - 1 >= range.position) {
+                       range.count = lPtr->topItem - range.position;
+               } else {
+                       range.count = lPtr->topItem - range.position - 2;
+               }
+               WMSetListSelectionToRange(lPtr, range);
+       } else {
+               WMSelectListItem(lPtr, lPtr->topItem - 1);
+       }
+       scrollByAmount(lPtr, -1);
+
+       lPtr->selectID = WMAddTimerHandler(SCROLL_DELAY, scrollBackwardSelecting, lPtr);
+}
+
+static void handleEvents(XEvent * event, void *data)
+{
+       List *lPtr = (List *) data;
+
+       CHECK_CLASS(data, WC_List);
+
+       switch (event->type) {
+       case Expose:
+               if (event->xexpose.count != 0)
+                       break;
+               paintList(lPtr);
+               break;
+
+       case DestroyNotify:
+               destroyList(lPtr);
+               break;
+
+       }
+}
+
+static int matchTitle(void *item, void *title)
+{
+       return (strcmp(((WMListItem *) item)->text, (char *)title) == 0 ? 1 : 0);
+}
+
+int WMFindRowOfListItemWithTitle(WMList * lPtr, char *title)
+{
+       return WMFindInArray(lPtr->items, matchTitle, title);
+}
+
+void WMSelectListItem(WMList * lPtr, int row)
+{
+       WMListItem *item;
+
+       if (row >= WMGetArrayItemCount(lPtr->items))
+               return;
+
+       if (row < 0) {
+               /* row = -1 will deselects all for backward compatibility.
+                * will be removed later. -Dan */
+               WMUnselectAllListItems(lPtr);
+               return;
+       }
+
+       item = WMGetFromArray(lPtr->items, row);
+       if (item->selected)
+               return;         /* Return if already selected */
+
+       if (!lPtr->flags.allowMultipleSelection) {
+               /* unselect previous selected items */
+               unselectAllListItems(lPtr, NULL);
+       }
+
+       /* select item */
+       item->selected = 1;
+       WMAddToArray(lPtr->selectedItems, item);
+
+       if (lPtr->view->flags.mapped && row >= lPtr->topItem && row <= lPtr->topItem + lPtr->fullFitLines) {
+               paintItem(lPtr, row);
+       }
+
+       WMPostNotificationName(WMListSelectionDidChangeNotification, lPtr, NULL);
+}
+
+void WMUnselectListItem(WMList * lPtr, int row)
+{
+       WMListItem *item = WMGetFromArray(lPtr->items, row);
+
+       if (!item || !item->selected)
+               return;
+
+       if (!lPtr->flags.allowEmptySelection && WMGetArrayItemCount(lPtr->selectedItems) <= 1) {
+               return;
+       }
+
+       item->selected = 0;
+       WMRemoveFromArray(lPtr->selectedItems, item);
+
+       if (lPtr->view->flags.mapped && row >= lPtr->topItem && row <= lPtr->topItem + lPtr->fullFitLines) {
+               paintItem(lPtr, row);
+       }
+
+       WMPostNotificationName(WMListSelectionDidChangeNotification, lPtr, NULL);
+}
+
+void WMSelectListItemsInRange(WMList * lPtr, WMRange range)
+{
+       WMListItem *item;
+       int position = range.position, k = 1, notify = 0;
+       int total = WMGetArrayItemCount(lPtr->items);
+
+       if (!lPtr->flags.allowMultipleSelection)
+               return;
+       if (range.count == 0)
+               return;         /* Nothing to select */
+
+       if (range.count < 0) {
+               range.count = -range.count;
+               k = -1;
+       }
+
+       for (; range.count > 0 && position >= 0 && position < total; range.count--) {
+               item = WMGetFromArray(lPtr->items, position);
+               if (!item->selected) {
+                       item->selected = 1;
+                       WMAddToArray(lPtr->selectedItems, item);
+                       if (lPtr->view->flags.mapped && position >= lPtr->topItem
+                           && position <= lPtr->topItem + lPtr->fullFitLines) {
+                               paintItem(lPtr, position);
+                       }
+                       notify = 1;
+               }
+               position += k;
+       }
+
+       if (notify) {
+               WMPostNotificationName(WMListSelectionDidChangeNotification, lPtr, NULL);
+       }
+}
+
+void WMSetListSelectionToRange(WMList * lPtr, WMRange range)
+{
+       WMListItem *item;
+       int mark1, mark2, i, k;
+       int position = range.position, notify = 0;
+       int total = WMGetArrayItemCount(lPtr->items);
+
+       if (!lPtr->flags.allowMultipleSelection)
+               return;
+
+       if (range.count == 0) {
+               WMUnselectAllListItems(lPtr);
+               return;
+       }
+
+       if (range.count < 0) {
+               mark1 = range.position + range.count + 1;
+               mark2 = range.position + 1;
+               range.count = -range.count;
+               k = -1;
+       } else {
+               mark1 = range.position;
+               mark2 = range.position + range.count;
+               k = 1;
+       }
+       if (mark1 > total)
+               mark1 = total;
+       if (mark2 < 0)
+               mark2 = 0;
+
+       WMEmptyArray(lPtr->selectedItems);
+
+       for (i = 0; i < mark1; i++) {
+               item = WMGetFromArray(lPtr->items, i);
+               if (item->selected) {
+                       item->selected = 0;
+                       if (lPtr->view->flags.mapped && i >= lPtr->topItem
+                           && i <= lPtr->topItem + lPtr->fullFitLines) {
+                               paintItem(lPtr, i);
+                       }
+                       notify = 1;
+               }
+       }
+       for (; range.count > 0 && position >= 0 && position < total; range.count--) {
+               item = WMGetFromArray(lPtr->items, position);
+               if (!item->selected) {
+                       item->selected = 1;
+                       if (lPtr->view->flags.mapped && position >= lPtr->topItem
+                           && position <= lPtr->topItem + lPtr->fullFitLines) {
+                               paintItem(lPtr, position);
+                       }
+                       notify = 1;
+               }
+               WMAddToArray(lPtr->selectedItems, item);
+               position += k;
+       }
+       for (i = mark2; i < total; i++) {
+               item = WMGetFromArray(lPtr->items, i);
+               if (item->selected) {
+                       item->selected = 0;
+                       if (lPtr->view->flags.mapped && i >= lPtr->topItem
+                           && i <= lPtr->topItem + lPtr->fullFitLines) {
+                               paintItem(lPtr, i);
+                       }
+                       notify = 1;
+               }
+       }
+
+       if (notify) {
+               WMPostNotificationName(WMListSelectionDidChangeNotification, lPtr, NULL);
+       }
+}
+
+void WMSelectAllListItems(WMList * lPtr)
+{
+       int i;
+       WMListItem *item;
+
+       if (!lPtr->flags.allowMultipleSelection)
+               return;
+
+       if (WMGetArrayItemCount(lPtr->items) == WMGetArrayItemCount(lPtr->selectedItems)) {
+               return;         /* All items are selected already */
+       }
+
+       WMFreeArray(lPtr->selectedItems);
+       lPtr->selectedItems = WMCreateArrayWithArray(lPtr->items);
+
+       for (i = 0; i < WMGetArrayItemCount(lPtr->items); i++) {
+               item = WMGetFromArray(lPtr->items, i);
+               if (!item->selected) {
+                       item->selected = 1;
+                       if (lPtr->view->flags.mapped && i >= lPtr->topItem
+                           && i <= lPtr->topItem + lPtr->fullFitLines) {
+                               paintItem(lPtr, i);
+                       }
+               }
+       }
+
+       WMPostNotificationName(WMListSelectionDidChangeNotification, lPtr, NULL);
+}
+
+/*
+ * Be careful from where you call this function! It doesn't honor the
+ * allowEmptySelection flag and doesn't send a notification about selection
+ * change! You need to manage these in the functions from where you call it.
+ *
+ * This will unselect all items if exceptThis is NULL, else will keep
+ * exceptThis selected.
+ * Make sure that exceptThis is one of the already selected items if not NULL!
+ *
+ */
+static void unselectAllListItems(WMList * lPtr, WMListItem * exceptThis)
+{
+       int i;
+       WMListItem *item;
+
+       for (i = 0; i < WMGetArrayItemCount(lPtr->items); i++) {
+               item = WMGetFromArray(lPtr->items, i);
+               if (item != exceptThis && item->selected) {
+                       item->selected = 0;
+                       if (lPtr->view->flags.mapped && i >= lPtr->topItem
+                           && i <= lPtr->topItem + lPtr->fullFitLines) {
+                               paintItem(lPtr, i);
+                       }
+               }
+       }
+
+       WMEmptyArray(lPtr->selectedItems);
+       if (exceptThis != NULL) {
+               exceptThis->selected = 1;
+               WMAddToArray(lPtr->selectedItems, exceptThis);
+       }
+}
+
+void WMUnselectAllListItems(WMList * lPtr)
+{
+       int keep;
+       WMListItem *keepItem;
+
+       keep = lPtr->flags.allowEmptySelection ? 0 : 1;
+
+       if (WMGetArrayItemCount(lPtr->selectedItems) == keep)
+               return;
+
+       keepItem = (keep == 1 ? WMGetFromArray(lPtr->selectedItems, 0) : NULL);
+
+       unselectAllListItems(lPtr, keepItem);
+
+       WMPostNotificationName(WMListSelectionDidChangeNotification, lPtr, NULL);
+}
+
+static int getItemIndexAt(List * lPtr, int clickY)
+{
+       int index;
+
+       index = (clickY - 2) / lPtr->itemHeight + lPtr->topItem;
+
+       if (index < 0 || index >= WMGetArrayItemCount(lPtr->items))
+               return -1;
+
+       return index;
+}
+
+static void toggleItemSelection(WMList * lPtr, int index)
+{
+       WMListItem *item = WMGetFromArray(lPtr->items, index);
+
+       if (item && item->selected) {
+               WMUnselectListItem(lPtr, index);
+       } else {
+               WMSelectListItem(lPtr, index);
+       }
+}
+
+static void handleActionEvents(XEvent * event, void *data)
+{
+       List *lPtr = (List *) data;
+       int tmp, height;
+       int topItem = lPtr->topItem;
+       static int lastClicked = -1, prevItem = -1;
+
+       CHECK_CLASS(data, WC_List);
+
+       switch (event->type) {
+       case ButtonRelease:
+               /* Ignore mouse wheel events, they're not "real" button events */
+               if (event->xbutton.button == WINGsConfiguration.mouseWheelUp ||
+                   event->xbutton.button == WINGsConfiguration.mouseWheelDown) {
+                       break;
+               }
+
+               lPtr->flags.buttonPressed = 0;
+               if (lPtr->selectID) {
+                       WMDeleteTimerHandler(lPtr->selectID);
+                       lPtr->selectID = NULL;
+               }
+               tmp = getItemIndexAt(lPtr, event->xbutton.y);
+
+               if (tmp >= 0) {
+                       if (lPtr->action)
+                               (*lPtr->action) (lPtr, lPtr->clientData);
+               }
+
+               if (!(event->xbutton.state & ShiftMask))
+                       lastClicked = prevItem = tmp;
+
+               break;
+
+       case EnterNotify:
+               if (lPtr->selectID) {
+                       WMDeleteTimerHandler(lPtr->selectID);
+                       lPtr->selectID = NULL;
+               }
+               break;
+
+       case LeaveNotify:
+               height = WMWidgetHeight(lPtr);
+               if (lPtr->flags.buttonPressed && !lPtr->selectID) {
+                       if (event->xcrossing.y >= height) {
+                               lPtr->selectID = WMAddTimerHandler(SCROLL_DELAY, scrollForwardSelecting, lPtr);
+                       } else if (event->xcrossing.y <= 0) {
+                               lPtr->selectID = WMAddTimerHandler(SCROLL_DELAY, scrollBackwardSelecting, lPtr);
+                       }
+               }
+               break;
+
+       case ButtonPress:
+               if (event->xbutton.x <= WMWidgetWidth(lPtr->vScroller))
+                       break;
+               if (event->xbutton.button == WINGsConfiguration.mouseWheelDown ||
+                   event->xbutton.button == WINGsConfiguration.mouseWheelUp) {
+                       int amount = 0;
+
+                       if (event->xbutton.state & ControlMask) {
+                               amount = lPtr->fullFitLines - (1 - lPtr->flags.dontFitAll) - 1;
+                       } else if (event->xbutton.state & ShiftMask) {
+                               amount = 1;
+                       } else {
+                               amount = lPtr->fullFitLines / 3;
+                               if (amount == 0)
+                                       amount++;
+                       }
+                       if (event->xbutton.button == WINGsConfiguration.mouseWheelUp)
+                               amount = -amount;
+
+                       scrollByAmount(lPtr, amount);
+                       break;
+               }
+
+               tmp = getItemIndexAt(lPtr, event->xbutton.y);
+               lPtr->flags.buttonPressed = 1;
+
+               if (tmp >= 0) {
+                       if (tmp == lastClicked && WMIsDoubleClick(event)) {
+                               WMSelectListItem(lPtr, tmp);
+                               if (lPtr->doubleAction)
+                                       (*lPtr->doubleAction) (lPtr, lPtr->doubleClientData);
+                       } else {
+                               if (!lPtr->flags.allowMultipleSelection) {
+                                       if (event->xbutton.state & ControlMask) {
+                                               toggleItemSelection(lPtr, tmp);
+                                       } else {
+                                               WMSelectListItem(lPtr, tmp);
+                                       }
+                               } else {
+                                       WMRange range;
+                                       WMListItem *lastSel;
+
+                                       if (event->xbutton.state & ControlMask) {
+                                               toggleItemSelection(lPtr, tmp);
+                                       } else if (event->xbutton.state & ShiftMask) {
+                                               if (WMGetArrayItemCount(lPtr->selectedItems) == 0) {
+                                                       WMSelectListItem(lPtr, tmp);
+                                               } else {
+                                                       lastSel = WMGetFromArray(lPtr->items, lastClicked);
+                                                       range.position = WMGetFirstInArray(lPtr->items, lastSel);
+                                                       if (tmp >= range.position)
+                                                               range.count = tmp - range.position + 1;
+                                                       else
+                                                               range.count = tmp - range.position - 1;
+
+                                                       WMSetListSelectionToRange(lPtr, range);
+                                               }
+                                       } else {
+                                               range.position = tmp;
+                                               range.count = 1;
+                                               WMSetListSelectionToRange(lPtr, range);
+                                       }
+                               }
+                       }
+               }
+
+               if (!(event->xbutton.state & ShiftMask))
+                       lastClicked = prevItem = tmp;
+
+               break;
+
+       case MotionNotify:
+               height = WMWidgetHeight(lPtr);
+               if (lPtr->selectID && event->xmotion.y > 0 && event->xmotion.y < height) {
+                       WMDeleteTimerHandler(lPtr->selectID);
+                       lPtr->selectID = NULL;
+               }
+               if (lPtr->flags.buttonPressed && !lPtr->selectID) {
+                       if (event->xmotion.y <= 0) {
+                               lPtr->selectID = WMAddTimerHandler(SCROLL_DELAY, scrollBackwardSelecting, lPtr);
+                               break;
+                       } else if (event->xmotion.y >= height) {
+                               lPtr->selectID = WMAddTimerHandler(SCROLL_DELAY, scrollForwardSelecting, lPtr);
+                               break;
+                       }
+
+                       tmp = getItemIndexAt(lPtr, event->xmotion.y);
+                       if (tmp >= 0 && tmp != prevItem) {
+                               if (lPtr->flags.allowMultipleSelection) {
+                                       WMRange range;
+
+                                       range.position = lastClicked;
+                                       if (tmp >= lastClicked)
+                                               range.count = tmp - lastClicked + 1;
+                                       else
+                                               range.count = tmp - lastClicked - 1;
+                                       WMSetListSelectionToRange(lPtr, range);
+                               } else {
+                                       WMSelectListItem(lPtr, tmp);
+                               }
+                       }
+                       prevItem = tmp;
+               }
+               break;
+       }
+       if (lPtr->topItem != topItem)
+               WMPostNotificationName(WMListDidScrollNotification, lPtr, NULL);
+}
+
+static void updateGeometry(WMList * lPtr)
+{
+       lPtr->fullFitLines = (lPtr->view->size.height - 4) / lPtr->itemHeight;
+       if (lPtr->fullFitLines * lPtr->itemHeight < lPtr->view->size.height - 4) {
+               lPtr->flags.dontFitAll = 1;
+       } else {
+               lPtr->flags.dontFitAll = 0;
+       }
+
+       if (WMGetArrayItemCount(lPtr->items) - lPtr->topItem <= lPtr->fullFitLines) {
+               lPtr->topItem = WMGetArrayItemCount(lPtr->items) - lPtr->fullFitLines;
+               if (lPtr->topItem < 0)
+                       lPtr->topItem = 0;
+       }
+
+       updateScroller(lPtr);
+}
+
+static void didResizeList(W_ViewDelegate * self, WMView * view)
+{
+       WMList *lPtr = (WMList *) view->self;
+
+       WMResizeWidget(lPtr->vScroller, 1, view->size.height - 2);
+
+       updateDoubleBufferPixmap(lPtr);
+
+       updateGeometry(lPtr);
+}
+
+static void destroyList(List * lPtr)
+{
+       if (lPtr->idleID)
+               WMDeleteIdleHandler(lPtr->idleID);
+       lPtr->idleID = NULL;
+
+       if (lPtr->selectID)
+               WMDeleteTimerHandler(lPtr->selectID);
+       lPtr->selectID = NULL;
+
+       if (lPtr->selectedItems)
+               WMFreeArray(lPtr->selectedItems);
+
+       if (lPtr->items)
+               WMFreeArray(lPtr->items);
+
+       if (lPtr->doubleBuffer)
+               XFreePixmap(lPtr->view->screen->display, lPtr->doubleBuffer);
+
+       WMRemoveNotificationObserver(lPtr);
+
+       wfree(lPtr);
+}