Change to the linux kernel coding style
[wmaker-crm.git] / WINGs / wfilepanel.c
dissimilarity index 95%
index e5565eb..33e3dab 100644 (file)
-
-#include "WINGsP.h"
-#include "wconfig.h"
-
-#include <sys/types.h>
-#include <sys/stat.h>
-#include <unistd.h>
-#include <dirent.h>
-#include <limits.h>
-#include <errno.h>
-#include <stdint.h>
-
-#ifndef PATH_MAX
-#define PATH_MAX 1024
-#endif
-
-
-typedef struct W_FilePanel {
-    WMWindow *win;
-
-    WMLabel *iconLabel;
-    WMLabel *titleLabel;
-
-    WMFrame *line;
-
-    WMLabel *nameLabel;
-    WMBrowser *browser;
-
-    WMButton *okButton;
-    WMButton *cancelButton;
-
-    WMButton *homeButton;
-    WMButton *trashcanButton;
-    WMButton *createDirButton;
-    WMButton *disketteButton;
-    WMButton *unmountButton;
-
-    WMView *accessoryView;
-
-    WMTextField *fileField;
-
-    char **fileTypes;
-
-    struct {
-        unsigned int canExit:1;
-        unsigned int canceled:1;       /* clicked on cancel */
-        unsigned int filtered:1;
-        unsigned int canChooseFiles:1;
-        unsigned int canChooseDirectories:1;
-        unsigned int autoCompletion:1;
-        unsigned int showAllFiles:1;
-        unsigned int canFreeFileTypes:1;
-        unsigned int fileMustExist:1;
-        unsigned int panelType:1;
-    } flags;
-} W_FilePanel;
-
-
-/* Type of panel */
-#define WP_OPEN         0
-#define WP_SAVE         1
-
-#define PWIDTH         330
-#define PHEIGHT        360
-
-static void listDirectoryOnColumn(WMFilePanel *panel, int column, char *path);
-static void browserClick();
-static void browserDClick();
-
-static void fillColumn(WMBrowserDelegate *self, WMBrowser *bPtr, int column,
-                       WMList *list);
-
-static void deleteFile();
-
-static void createDir();
-
-static void goHome();
-
-static void goFloppy();
-
-static void goUnmount();
-
-static void buttonClick();
-
-static char *getCurrentFileName(WMFilePanel *panel);
-
-static void handleEvents(XEvent *event, void *data);
-
-
-
-static WMBrowserDelegate browserDelegate = {
-    NULL, /* data */
-    fillColumn, /* createRowsForColumn */
-    NULL, /* titleOfColumn */
-    NULL, /* didScroll */
-    NULL  /* willScroll */
-};
-
-
-static int
-closestListItem(WMList *list, char *text, Bool exact)
-{
-    WMListItem *item;
-    WMArray *items = WMGetListItems(list);
-    int i, len = strlen(text);
-
-    if (len==0)
-        return -1;
-
-    for(i=0; i<WMGetArrayItemCount(items); i++) {
-        item = WMGetFromArray(items, i);
-        if (strlen(item->text) >= len &&
-            ((exact && strcmp(item->text, text)==0) ||
-             (!exact && strncmp(item->text, text, len)==0))) {
-            return i;
-        }
-    }
-
-    return -1;
-}
-
-
-static void
-textChangedObserver(void *observerData, WMNotification *notification)
-{
-    W_FilePanel *panel = (W_FilePanel*)observerData;
-    char *text;
-    WMList *list;
-    int col = WMGetBrowserNumberOfColumns(panel->browser) - 1;
-    int i, textEvent;
-
-    if (!(list = WMGetBrowserListInColumn(panel->browser, col)))
-        return;
-
-    text = WMGetTextFieldText(panel->fileField);
-    textEvent = (int)(uintptr_t)WMGetNotificationClientData(notification);
-
-    if (panel->flags.autoCompletion && textEvent!=WMDeleteTextEvent)
-        i = closestListItem(list, text, False);
-    else
-        i = closestListItem(list, text, True);
-
-    WMSelectListItem(list, i);
-    if (i>=0 && panel->flags.autoCompletion) {
-        WMListItem *item = WMGetListItem(list, i);
-        int textLen = strlen(text), itemTextLen = strlen(item->text);
-        int visibleItems = WMWidgetHeight(list)/WMGetListItemHeight(list);
-
-        WMSetListPosition(list, i - visibleItems/2);
-
-        if (textEvent!=WMDeleteTextEvent) {
-            WMRange range;
-
-            WMInsertTextFieldText(panel->fileField, &item->text[textLen],
-                                  textLen);
-            range.position = textLen;
-            range.count = itemTextLen - textLen;
-            WMSelectTextFieldRange(panel->fileField, range);
-            /*WMSetTextFieldCursorPosition(panel->fileField, itemTextLen);*/
-        }
-    }
-
-    wfree(text);
-}
-
-
-static void
-textEditedObserver(void *observerData, WMNotification *notification)
-{
-    W_FilePanel *panel = (W_FilePanel*)observerData;
-
-    if ((int)(uintptr_t)WMGetNotificationClientData(notification)==WMReturnTextMovement) {
-        WMPerformButtonClick(panel->okButton);
-    }
-}
-
-
-
-static WMFilePanel*
-makeFilePanel(WMScreen *scrPtr, char *name, char *title)
-{
-    WMFilePanel *fPtr;
-    WMFont *largeFont;
-    WMPixmap *icon;
-
-    fPtr = wmalloc(sizeof(WMFilePanel));
-    memset(fPtr, 0, sizeof(WMFilePanel));
-
-    fPtr->win = WMCreateWindowWithStyle(scrPtr, name, WMTitledWindowMask
-                                        |WMResizableWindowMask);
-    WMResizeWidget(fPtr->win, PWIDTH, PHEIGHT);
-    WMSetWindowTitle(fPtr->win, "");
-
-    WMCreateEventHandler(WMWidgetView(fPtr->win), StructureNotifyMask,
-                         handleEvents, fPtr);
-    WMSetWindowMinSize(fPtr->win, PWIDTH, PHEIGHT);
-
-
-    fPtr->iconLabel = WMCreateLabel(fPtr->win);
-    WMResizeWidget(fPtr->iconLabel, 64, 64);
-    WMMoveWidget(fPtr->iconLabel, 0, 0);
-    WMSetLabelImagePosition(fPtr->iconLabel, WIPImageOnly);
-    icon = WMCreateApplicationIconBlendedPixmap(scrPtr, (RColor*)NULL);
-    if (icon) {
-        WMSetLabelImage(fPtr->iconLabel, icon);
-        WMReleasePixmap(icon);
-    } else {
-        WMSetLabelImage(fPtr->iconLabel, scrPtr->applicationIconPixmap);
-    }
-
-    fPtr->titleLabel = WMCreateLabel(fPtr->win);
-    WMResizeWidget(fPtr->titleLabel, PWIDTH-64, 64);
-    WMMoveWidget(fPtr->titleLabel, 64, 0);
-    largeFont = WMBoldSystemFontOfSize(scrPtr, 24);
-    WMSetLabelFont(fPtr->titleLabel, largeFont);
-    WMReleaseFont(largeFont);
-    WMSetLabelText(fPtr->titleLabel, title);
-
-    fPtr->line = WMCreateFrame(fPtr->win);
-    WMMoveWidget(fPtr->line, 0, 64);
-    WMResizeWidget(fPtr->line, PWIDTH, 2);
-    WMSetFrameRelief(fPtr->line, WRGroove);
-
-    fPtr->browser = WMCreateBrowser(fPtr->win);
-    WMSetBrowserAllowEmptySelection(fPtr->browser, True);
-    WMSetBrowserDelegate(fPtr->browser, &browserDelegate);
-    WMSetBrowserAction(fPtr->browser, browserClick, fPtr);
-    WMSetBrowserDoubleAction(fPtr->browser, browserDClick, fPtr);
-    WMMoveWidget(fPtr->browser, 7, 72);
-    WMResizeWidget(fPtr->browser, PWIDTH-14,200);
-    WMHangData(fPtr->browser, fPtr);
-
-    fPtr->nameLabel = WMCreateLabel(fPtr->win);
-    WMMoveWidget(fPtr->nameLabel, 7, 282);
-    WMResizeWidget(fPtr->nameLabel, 55, 14);
-    WMSetLabelText(fPtr->nameLabel, _("Name:"));
-
-    fPtr->fileField = WMCreateTextField(fPtr->win);
-    WMMoveWidget(fPtr->fileField, 60, 278);
-    WMResizeWidget(fPtr->fileField, PWIDTH-60-10, 24);
-    WMAddNotificationObserver(textEditedObserver, fPtr,
-                              WMTextDidEndEditingNotification,
-                              fPtr->fileField);
-    WMAddNotificationObserver(textChangedObserver, fPtr,
-                              WMTextDidChangeNotification,
-                              fPtr->fileField);
-
-    fPtr->okButton = WMCreateCommandButton(fPtr->win);
-    WMMoveWidget(fPtr->okButton, 245, 325);
-    WMResizeWidget(fPtr->okButton, 75, 28);
-    WMSetButtonText(fPtr->okButton, _("OK"));
-    WMSetButtonImage(fPtr->okButton, scrPtr->buttonArrow);
-    WMSetButtonAltImage(fPtr->okButton, scrPtr->pushedButtonArrow);
-    WMSetButtonImagePosition(fPtr->okButton, WIPRight);
-    WMSetButtonAction(fPtr->okButton, buttonClick, fPtr);
-
-    fPtr->cancelButton = WMCreateCommandButton(fPtr->win);
-    WMMoveWidget(fPtr->cancelButton, 165, 325);
-    WMResizeWidget(fPtr->cancelButton, 75, 28);
-    WMSetButtonText(fPtr->cancelButton, _("Cancel"));
-    WMSetButtonAction(fPtr->cancelButton, buttonClick, fPtr);
-
-    fPtr->trashcanButton = WMCreateCommandButton(fPtr->win);
-    WMMoveWidget(fPtr->trashcanButton, 7, 325);
-    WMResizeWidget(fPtr->trashcanButton, 28, 28);
-    WMSetButtonImagePosition(fPtr->trashcanButton, WIPImageOnly);
-    WMSetButtonImage(fPtr->trashcanButton, scrPtr->trashcanIcon);
-    WMSetButtonAltImage(fPtr->trashcanButton, scrPtr->altTrashcanIcon);
-    WMSetButtonAction(fPtr->trashcanButton, deleteFile, fPtr);
-
-    fPtr->createDirButton = WMCreateCommandButton(fPtr->win);
-    WMMoveWidget(fPtr->createDirButton, 37, 325);
-    WMResizeWidget(fPtr->createDirButton, 28, 28);
-    WMSetButtonImagePosition(fPtr->createDirButton, WIPImageOnly);
-    WMSetButtonImage(fPtr->createDirButton, scrPtr->createDirIcon);
-    WMSetButtonAltImage(fPtr->createDirButton, scrPtr->altCreateDirIcon);
-    WMSetButtonAction(fPtr->createDirButton, createDir, fPtr);
-
-    fPtr->homeButton = WMCreateCommandButton(fPtr->win);
-    WMMoveWidget(fPtr->homeButton, 67, 325);
-    WMResizeWidget(fPtr->homeButton, 28, 28);
-    WMSetButtonImagePosition(fPtr->homeButton, WIPImageOnly);
-    WMSetButtonImage(fPtr->homeButton, scrPtr->homeIcon);
-    WMSetButtonAltImage(fPtr->homeButton, scrPtr->altHomeIcon);
-    WMSetButtonAction(fPtr->homeButton, goHome, fPtr);
-
-    fPtr->disketteButton = WMCreateCommandButton(fPtr->win);
-    WMMoveWidget(fPtr->disketteButton, 97, 325);
-    WMResizeWidget(fPtr->disketteButton, 28, 28);
-    WMSetButtonImagePosition(fPtr->disketteButton, WIPImageOnly);
-    WMSetButtonImage(fPtr->disketteButton, scrPtr->disketteIcon);
-    WMSetButtonAltImage(fPtr->disketteButton, scrPtr->altDisketteIcon);
-    WMSetButtonAction(fPtr->disketteButton, goFloppy, fPtr);
-
-    fPtr->unmountButton = WMCreateCommandButton(fPtr->win);
-    WMMoveWidget(fPtr->unmountButton, 127, 325);
-    WMResizeWidget(fPtr->unmountButton, 28, 28);
-    WMSetButtonImagePosition(fPtr->unmountButton, WIPImageOnly);
-    WMSetButtonImage(fPtr->unmountButton, scrPtr->unmountIcon);
-    WMSetButtonAltImage(fPtr->unmountButton, scrPtr->altUnmountIcon);
-    WMSetButtonAction(fPtr->unmountButton, goUnmount, fPtr);
-    WMSetButtonEnabled(fPtr->unmountButton, False);
-
-
-    WMRealizeWidget(fPtr->win);
-    WMMapSubwidgets(fPtr->win);
-
-    WMSetFocusToWidget(fPtr->fileField);
-    WMSetTextFieldCursorPosition(fPtr->fileField, 0);
-
-    WMLoadBrowserColumnZero(fPtr->browser);
-
-    WMSetWindowInitialPosition(fPtr->win,
-                               (scrPtr->rootView->size.width - WMWidgetWidth(fPtr->win))/2,
-                               (scrPtr->rootView->size.height - WMWidgetHeight(fPtr->win))/2);
-
-    fPtr->flags.canChooseFiles = 1;
-    fPtr->flags.canChooseDirectories = 1;
-    fPtr->flags.autoCompletion = 1;
-
-    return fPtr;
-}
-
-
-WMOpenPanel*
-WMGetOpenPanel(WMScreen *scrPtr)
-{
-    WMFilePanel *panel;
-
-    if (scrPtr->sharedOpenPanel)
-        return scrPtr->sharedOpenPanel;
-
-    panel = makeFilePanel(scrPtr, "openFilePanel", _("Open"));
-    panel->flags.fileMustExist = 1;
-    panel->flags.panelType = WP_OPEN;
-
-    scrPtr->sharedOpenPanel = panel;
-
-    return panel;
-}
-
-
-WMSavePanel*
-WMGetSavePanel(WMScreen *scrPtr)
-{
-    WMFilePanel *panel;
-
-    if (scrPtr->sharedSavePanel)
-        return scrPtr->sharedSavePanel;
-
-    panel = makeFilePanel(scrPtr, "saveFilePanel", _("Save"));
-    panel->flags.fileMustExist = 0;
-    panel->flags.panelType = WP_SAVE;
-
-    scrPtr->sharedSavePanel = panel;
-
-    return panel;
-}
-
-
-void
-WMFreeFilePanel(WMFilePanel *panel)
-{
-    if (panel == WMWidgetScreen(panel->win)->sharedSavePanel) {
-        WMWidgetScreen(panel->win)->sharedSavePanel = NULL;
-    }
-    if (panel == WMWidgetScreen(panel->win)->sharedOpenPanel) {
-        WMWidgetScreen(panel->win)->sharedOpenPanel = NULL;
-    }
-    WMRemoveNotificationObserver(panel);
-    WMUnmapWidget(panel->win);
-    WMDestroyWidget(panel->win);
-    wfree(panel);
-}
-
-
-int
-WMRunModalFilePanelForDirectory(WMFilePanel *panel, WMWindow *owner,
-                                char *path, char *name, char **fileTypes)
-{
-    WMScreen *scr = WMWidgetScreen(panel->win);
-
-    if (name && !owner) {
-        WMSetWindowTitle(panel->win, name);
-    }
-
-    WMChangePanelOwner(panel->win, owner);
-
-    WMSetFilePanelDirectory(panel, path);
-
-    switch(panel->flags.panelType) {
-    case WP_OPEN:
-        if (fileTypes)
-            panel->flags.filtered = 1;
-        panel->fileTypes = fileTypes;
-        if (name == NULL)
-            name = _("Open");
-        break;
-    case WP_SAVE:
-        panel->fileTypes = NULL;
-        panel->flags.filtered = 0;
-        if (name == NULL)
-            name = _("Save");
-        break;
-    default:
-        break;
-    }
-
-    WMSetLabelText(panel->titleLabel, name);
-
-    WMMapWidget(panel->win);
-
-    WMRunModalLoop(scr, W_VIEW(panel->win));
-
-    /* Must withdraw window because the next time we map
-     * it, it might have a different transient owner.
-     */
-    WMCloseWindow(panel->win);
-
-    return (panel->flags.canceled ? False : True);
-}
-
-
-
-
-void
-WMSetFilePanelDirectory(WMFilePanel *panel, char *path)
-{
-    WMList *list;
-    WMListItem *item;
-    int col;
-    char *rest;
-
-    rest = WMSetBrowserPath(panel->browser, path);
-    if (strcmp(path, "/")==0)
-        rest = NULL;
-
-    col = WMGetBrowserSelectedColumn(panel->browser);
-    list = WMGetBrowserListInColumn(panel->browser, col);
-    if (list && (item = WMGetListSelectedItem(list))) {
-        if (item->isBranch) {
-            WMSetTextFieldText(panel->fileField, rest);
-        } else {
-            WMSetTextFieldText(panel->fileField, item->text);
-        }
-    } else {
-        WMSetTextFieldText(panel->fileField, rest);
-    }
-}
-
-
-void
-WMSetFilePanelCanChooseDirectories(WMFilePanel *panel, Bool flag)
-{
-    panel->flags.canChooseDirectories = ((flag==0) ? 0 : 1);
-}
-
-void
-WMSetFilePanelCanChooseFiles(WMFilePanel *panel, Bool flag)
-{
-    panel->flags.canChooseFiles = ((flag==0) ? 0 : 1);
-}
-
-
-void
-WMSetFilePanelAutoCompletion(WMFilePanel *panel, Bool flag)
-{
-    panel->flags.autoCompletion = ((flag==0) ? 0 : 1);
-}
-
-
-char*
-WMGetFilePanelFileName(WMFilePanel *panel)
-{
-    return getCurrentFileName(panel);
-}
-
-
-void
-WMSetFilePanelAccessoryView(WMFilePanel *panel, WMView *view)
-{
-    WMView *v;
-
-    panel->accessoryView = view;
-
-    v = WMWidgetView(panel->win);
-
-    W_ReparentView(view, v, 0, 0);
-
-    W_MoveView(view, (v->size.width - v->size.width)/2, 300);
-}
-
-
-WMView*
-WMGetFilePanelAccessoryView(WMFilePanel *panel)
-{
-    return panel->accessoryView;
-}
-
-
-static char*
-get_name_from_path(char *path)
-{
-    int size;
-
-    assert(path!=NULL);
-
-    size = strlen(path);
-
-    /* remove trailing / */
-    while (size > 0 && path[size-1]=='/')
-        size--;
-    /* directory was root */
-    if (size == 0)
-        return wstrdup("/");
-
-    while (size > 0 && path[size-1] != '/')
-        size--;
-
-    return wstrdup(&(path[size]));
-}
-
-
-static int
-filterFileName(WMFilePanel *panel, char *file, Bool isDirectory)
-{
-    return True;
-}
-
-
-#define CAST(item) (*((WMListItem**)item))
-static int
-comparer(const void *a, const void *b)
-{
-    if (CAST(a)->isBranch == CAST(b)->isBranch)
-        return (strcmp(CAST(a)->text, CAST(b)->text));
-    if (CAST(a)->isBranch)
-        return (-1);
-    return (1);
-}
-#undef CAST
-
-
-static void
-listDirectoryOnColumn(WMFilePanel *panel, int column, char *path)
-{
-    WMBrowser *bPtr = panel->browser;
-    struct dirent *dentry;
-    DIR *dir;
-    struct stat stat_buf;
-    char pbuf[PATH_MAX+16];
-    char *name;
-
-    assert(column >= 0);
-    assert(path != NULL);
-
-    /* put directory name in the title */
-    name = get_name_from_path(path);
-    WMSetBrowserColumnTitle(bPtr, column, name);
-    wfree(name);
-
-    dir = opendir(path);
-
-    if (!dir) {
-#ifdef VERBOSE
-        printf(_("WINGs: could not open directory %s\n"), path);
-#endif
-        return;
-    }
-
-    /* list contents in the column */
-    while ((dentry = readdir(dir))) {
-        if (strcmp(dentry->d_name, ".")==0 ||
-            strcmp(dentry->d_name, "..")==0)
-            continue;
-
-        strcpy(pbuf, path);
-        if (strcmp(path, "/")!=0)
-            strcat(pbuf, "/");
-        strcat(pbuf, dentry->d_name);
-
-        if (stat(pbuf, &stat_buf)!=0) {
-#ifdef VERBOSE
-            printf(_("WINGs: could not stat %s\n"), pbuf);
-#endif
-            continue;
-        } else {
-            int isDirectory;
-
-            isDirectory = S_ISDIR(stat_buf.st_mode);
-
-            if (filterFileName(panel, dentry->d_name, isDirectory))
-                WMInsertBrowserItem(bPtr, column, -1, dentry->d_name, isDirectory);
-        }
-    }
-    WMSortBrowserColumnWithComparer(bPtr, column, comparer);
-
-    closedir(dir);
-}
-
-
-static void
-fillColumn(WMBrowserDelegate *self, WMBrowser *bPtr, int column, WMList *list)
-{
-    char *path;
-    WMFilePanel *panel;
-
-    if (column > 0) {
-        path = WMGetBrowserPathToColumn(bPtr, column-1);
-    } else {
-        path = wstrdup("/");
-    }
-
-    panel = WMGetHangedData(bPtr);
-    listDirectoryOnColumn(panel, column, path);
-    wfree(path);
-}
-
-
-static void
-browserDClick(WMBrowser *bPtr, WMFilePanel *panel)
-{
-    WMPerformButtonClick(panel->okButton);
-}
-
-static void
-browserClick(WMBrowser *bPtr, WMFilePanel *panel)
-{
-    int col = WMGetBrowserSelectedColumn(bPtr);
-    WMListItem *item = WMGetBrowserSelectedItemInColumn(bPtr, col);
-
-    if (!item || item->isBranch)
-        WMSetTextFieldText(panel->fileField, NULL);
-    else {
-        WMSetTextFieldText(panel->fileField, item->text);
-    }
-}
-
-
-static void
-showError(WMScreen *scr, WMWindow *owner, char *s, char *file)
-{
-    char *errStr;
-
-    if (file) {
-        errStr = wmalloc(strlen(file)+strlen(s));
-        sprintf(errStr, s, file);
-    } else {
-        errStr = wstrdup(s);
-    }
-    WMRunAlertPanel(scr, owner, _("Error"), errStr, _("OK"), NULL, NULL);
-    wfree(errStr);
-}
-
-
-static void
-createDir(WMButton *bPre, WMFilePanel *panel)
-{
-    char *dirName, *directory, *file, *s;
-    WMScreen *scr = WMWidgetScreen(panel->win);
-
-    dirName = WMRunInputPanel(scr, panel->win, _("Create Directory"),
-                              _("Enter directory name"), "", _("OK"), _("Cancel"));
-    if (!dirName)
-        return;
-
-    directory = getCurrentFileName(panel);
-    s = strrchr(directory,'/');
-    if (s) s[1] = 0;
-
-    if (dirName[0] == '/') {
-        directory[0] = 0;
-    } else {
-        while ((s = strstr(directory,"//"))) {
-            int i;
-            for (i = 2;s[i] == '/';i++);
-            strcpy(s, &s[i-1]);
-        }
-        if ((s = strrchr(directory, '/')) && !s[1]) s[0] = 0;
-    }
-    while ((s = strstr(dirName,"//"))) {
-        int i;
-        for (i = 2;s[i] == '/';i++);
-        strcpy(s, &s[i-1]);
-    }
-    if ((s = strrchr(dirName, '/')) && !s[1]) s[0] = 0;
-
-    file = wmalloc(strlen(dirName)+strlen(directory)+4);
-    sprintf(file, "%s/%s", directory, dirName);
-    while ((s = strstr(file,"//"))) {
-        int i;
-        for (i = 2;s[i] == '/';i++);
-        strcpy(s, &s[i-1]);
-    }
-
-    if (mkdir(file,0xfff) != 0) {
-        switch (errno) {
-        case EACCES:
-            showError(scr, panel->win, _("Permission denied."), NULL);
-            break;
-        case EEXIST:
-            showError(scr, panel->win, _("'%s' already exists."), file);
-            break;
-        case ENOENT:
-            showError(scr, panel->win, _("Path does not exist."), NULL);
-        }
-    }
-    else WMSetFilePanelDirectory(panel, file);
-
-    wfree(dirName);
-    wfree(directory);
-    wfree(file);
-}
-
-static void
-deleteFile(WMButton *bPre, WMFilePanel *panel)
-{
-    char *file;
-    char *buffer, *s;
-    struct stat filestat;
-    WMScreen *scr = WMWidgetScreen(panel->win);
-
-    file = getCurrentFileName(panel);
-
-    while ((s = strstr(file,"//"))) {
-        int i;
-        for (i = 2;s[i] == '/';i++);
-        strcpy(s, &s[i-1]);
-    }
-    if (strlen(file) > 1 && (s = strrchr(file, '/')) && !s[1]) s[0] = 0;
-
-    if (stat(file,&filestat)) {
-        switch (errno) {
-        case ENOENT:
-            showError(scr, panel->win, _("'%s' does not exist."), file);
-            break;
-        case EACCES:
-            showError(scr, panel->win, _("Permission denied."), NULL);
-            break;
-        case ENOMEM:
-            showError(scr, panel->win,
-                      _("Insufficient memory available."), NULL);
-            break;
-        case EROFS:
-            showError(scr, panel->win,
-                      _("'%s' is on a read-only filesystem."), file);
-            break;
-        default:
-            showError(scr, panel->win, _("Can not delete '%s'."), file);
-        }
-        wfree(file);
-        return;
-    } else if (S_ISDIR(filestat.st_mode)) {
-        int len = strlen(file)+20;
-        buffer = wmalloc(len);
-        snprintf(buffer,len,_("Delete directory %s ?"),file);
-    } else {
-        int len = strlen(file)+15;
-        buffer = wmalloc(len);
-        snprintf(buffer,len,_("Delete file %s ?"),file);
-    }
-
-    if (!WMRunAlertPanel(WMWidgetScreen(panel->win), panel->win,
-                         _("Warning"), buffer, _("OK"), _("Cancel"), NULL)) {
-        if (S_ISDIR(filestat.st_mode)) {
-            if (rmdir(file) != 0) {
-                switch (errno) {
-                case EACCES:
-                    showError(scr, panel->win, _("Permission denied."), NULL);
-                    break;
-                case ENOENT:
-                    showError(scr, panel->win, _("Directory '%s' does not exist."), file);
-                    break;
-                case ENOTEMPTY:
-                    showError(scr, panel->win, _("Directory '%s' is not empty."), file);
-                    break;
-                case EBUSY:
-                    showError(scr, panel->win, _("Directory '%s' is busy."), file);
-                    break;
-                default:
-                    showError(scr, panel->win, _("Can not delete '%s'."), file);
-                }
-            } else {
-                char *s = strrchr(file,'/');
-                if (s) s[0] = 0;
-                WMSetFilePanelDirectory(panel, file);
-            }
-        } else if (remove(file) != 0) {
-            switch (errno) {
-            case EISDIR:
-                showError(scr, panel->win, _("'%s' is a directory."), file);
-                break;
-            case ENOENT:
-                showError(scr, panel->win, _("'%s' does not exist."), file);
-                break;
-            case EACCES:
-                showError(scr, panel->win, _("Permission denied."), NULL);
-                break;
-            case ENOMEM:
-                showError(scr, panel->win,
-                          _("Insufficient memory available."), NULL);
-                break;
-            case EROFS:
-                showError(scr, panel->win,
-                          _("'%s' is on a read-only filesystem."), file);
-                break;
-            default:
-                showError(scr, panel->win, _("Can not delete '%s'."), file);
-            }
-        } else {
-            char *s = strrchr(file,'/');
-            if (s) s[1] = 0;
-            WMSetFilePanelDirectory(panel, file);
-        }
-    }
-    wfree(buffer);
-    wfree(file);
-}
-
-static void
-goUnmount(WMButton *bPtr, WMFilePanel *panel)
-{
-}
-
-
-static void
-goFloppy(WMButton *bPtr, WMFilePanel *panel)
-{
-    struct stat filestat;
-    WMScreen *scr = WMWidgetScreen(panel->win);
-
-    if (stat(WINGsConfiguration.floppyPath, &filestat)) {
-        showError(scr, panel->win, _("An error occured browsing '%s'."),
-                  WINGsConfiguration.floppyPath);
-        return;
-    } else if (!S_ISDIR(filestat.st_mode)) {
-        showError(scr, panel->win, _("'%s' is not a directory."),
-                  WINGsConfiguration.floppyPath);
-        return;
-    }
-
-    WMSetFilePanelDirectory(panel, WINGsConfiguration.floppyPath);
-}
-
-
-static void
-goHome(WMButton *bPtr, WMFilePanel *panel)
-{
-    char *home;
-
-    /* home is statically allocated. Don't free it! */
-    home = wgethomedir();
-    if (!home)
-        return;
-
-    WMSetFilePanelDirectory(panel, home);
-}
-
-
-static void
-handleEvents(XEvent *event, void *data)
-{
-    W_FilePanel *pPtr = (W_FilePanel*)data;
-    W_View *view = WMWidgetView(pPtr->win);
-
-    if (event->type == ConfigureNotify) {
-        if (event->xconfigure.width != view->size.width
-            || event->xconfigure.height != view->size.height) {
-            unsigned int newWidth = event->xconfigure.width;
-            unsigned int newHeight = event->xconfigure.height;
-            int newColumnCount;
-
-            W_ResizeView(view, newWidth, newHeight);
-            WMResizeWidget(pPtr->line, newWidth, 2);
-            WMResizeWidget(pPtr->browser, newWidth-14,
-                           newHeight-(PHEIGHT-200));
-            WMResizeWidget(pPtr->fileField, newWidth-60-10, 24);
-            WMMoveWidget(pPtr->nameLabel, 7, newHeight-(PHEIGHT-282));
-            WMMoveWidget(pPtr->fileField, 60, newHeight-(PHEIGHT-278));
-            WMMoveWidget(pPtr->okButton, newWidth-(PWIDTH-245),
-                         newHeight-(PHEIGHT-325));
-            WMMoveWidget(pPtr->cancelButton, newWidth-(PWIDTH-165),
-                         newHeight-(PHEIGHT-325));
-
-            WMMoveWidget(pPtr->trashcanButton, 7, newHeight-(PHEIGHT-325));
-            WMMoveWidget(pPtr->createDirButton, 37, newHeight-(PHEIGHT-325));
-            WMMoveWidget(pPtr->homeButton, 67, newHeight-(PHEIGHT-325));
-            WMMoveWidget(pPtr->disketteButton, 97, newHeight-(PHEIGHT-325));
-            WMMoveWidget(pPtr->unmountButton, 127, newHeight-(PHEIGHT-325));
-
-            newColumnCount = (newWidth - 14) / 140;
-            WMSetBrowserMaxVisibleColumns(pPtr->browser, newColumnCount);
-        }
-    }
-}
-
-
-static char*
-getCurrentFileName(WMFilePanel *panel)
-{
-    char *path;
-    char *file;
-    char *tmp;
-    int len;
-
-    path = WMGetBrowserPath(panel->browser);
-
-    len = strlen(path);
-    if (path[len-1]=='/') {
-        file = WMGetTextFieldText(panel->fileField);
-        tmp = wmalloc(strlen(path)+strlen(file)+8);
-        if (file[0]!='/') {
-            strcpy(tmp, path);
-            strcat(tmp, file);
-        } else
-            strcpy(tmp, file);
-
-        wfree(file);
-        wfree(path);
-        return tmp;
-    } else {
-        return path;
-    }
-}
-
-
-
-static Bool
-validOpenFile(WMFilePanel *panel)
-{
-    WMListItem *item;
-    int col, haveFile = 0;
-    char *file = WMGetTextFieldText(panel->fileField);
-
-    if (file[0] != '\0')
-        haveFile = 1;
-    wfree(file);
-
-    col = WMGetBrowserSelectedColumn(panel->browser);
-    item = WMGetBrowserSelectedItemInColumn(panel->browser, col);
-    if (item) {
-        if (item->isBranch && !panel->flags.canChooseDirectories && !haveFile)
-            return False;
-        else if (!item->isBranch && !panel->flags.canChooseFiles)
-            return False;
-        else
-            return True;
-    } else {
-        /* we compute for / here */
-        if (!panel->flags.canChooseDirectories && !haveFile)
-            return False;
-        else
-            return True;
-    }
-    return True;
-}
-
-
-
-static void
-buttonClick(WMButton *bPtr, WMFilePanel *panel)
-{
-    WMRange range;
-
-    if (bPtr == panel->okButton) {
-        if (!validOpenFile(panel))
-            return;
-        if (panel->flags.fileMustExist) {
-            char *file;
-
-            file = getCurrentFileName(panel);
-            if (access(file, F_OK)!=0) {
-                WMRunAlertPanel(WMWidgetScreen(panel->win), panel->win,
-                                _("Error"), _("File does not exist."),
-                                _("OK"), NULL, NULL);
-                wfree(file);
-                return;
-            }
-            wfree(file);
-        }
-        panel->flags.canceled = 0;
-    } else
-        panel->flags.canceled = 1;
-
-    range.count = range.position = 0;
-    WMSelectTextFieldRange(panel->fileField, range);
-    WMBreakModalLoop(WMWidgetScreen(bPtr));
-}
-
-
+
+#include "WINGsP.h"
+#include "wconfig.h"
+
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <unistd.h>
+#include <dirent.h>
+#include <limits.h>
+#include <errno.h>
+#include <stdint.h>
+
+#ifndef PATH_MAX
+#define PATH_MAX 1024
+#endif
+
+typedef struct W_FilePanel {
+       WMWindow *win;
+
+       WMLabel *iconLabel;
+       WMLabel *titleLabel;
+
+       WMFrame *line;
+
+       WMLabel *nameLabel;
+       WMBrowser *browser;
+
+       WMButton *okButton;
+       WMButton *cancelButton;
+
+       WMButton *homeButton;
+       WMButton *trashcanButton;
+       WMButton *createDirButton;
+       WMButton *disketteButton;
+       WMButton *unmountButton;
+
+       WMView *accessoryView;
+
+       WMTextField *fileField;
+
+       char **fileTypes;
+
+       struct {
+               unsigned int canExit:1;
+               unsigned int canceled:1;        /* clicked on cancel */
+               unsigned int filtered:1;
+               unsigned int canChooseFiles:1;
+               unsigned int canChooseDirectories:1;
+               unsigned int autoCompletion:1;
+               unsigned int showAllFiles:1;
+               unsigned int canFreeFileTypes:1;
+               unsigned int fileMustExist:1;
+               unsigned int panelType:1;
+       } flags;
+} W_FilePanel;
+
+/* Type of panel */
+#define WP_OPEN         0
+#define WP_SAVE         1
+
+#define PWIDTH         330
+#define PHEIGHT        360
+
+static void listDirectoryOnColumn(WMFilePanel * panel, int column, char *path);
+static void browserClick();
+static void browserDClick();
+
+static void fillColumn(WMBrowserDelegate * self, WMBrowser * bPtr, int column, WMList * list);
+
+static void deleteFile();
+
+static void createDir();
+
+static void goHome();
+
+static void goFloppy();
+
+static void goUnmount();
+
+static void buttonClick();
+
+static char *getCurrentFileName(WMFilePanel * panel);
+
+static void handleEvents(XEvent * event, void *data);
+
+static WMBrowserDelegate browserDelegate = {
+       NULL,                   /* data */
+       fillColumn,             /* createRowsForColumn */
+       NULL,                   /* titleOfColumn */
+       NULL,                   /* didScroll */
+       NULL                    /* willScroll */
+};
+
+static int closestListItem(WMList * list, char *text, Bool exact)
+{
+       WMListItem *item;
+       WMArray *items = WMGetListItems(list);
+       int i, len = strlen(text);
+
+       if (len == 0)
+               return -1;
+
+       for (i = 0; i < WMGetArrayItemCount(items); i++) {
+               item = WMGetFromArray(items, i);
+               if (strlen(item->text) >= len &&
+                   ((exact && strcmp(item->text, text) == 0) ||
+                    (!exact && strncmp(item->text, text, len) == 0))) {
+                       return i;
+               }
+       }
+
+       return -1;
+}
+
+static void textChangedObserver(void *observerData, WMNotification * notification)
+{
+       W_FilePanel *panel = (W_FilePanel *) observerData;
+       char *text;
+       WMList *list;
+       int col = WMGetBrowserNumberOfColumns(panel->browser) - 1;
+       int i, textEvent;
+
+       if (!(list = WMGetBrowserListInColumn(panel->browser, col)))
+               return;
+
+       text = WMGetTextFieldText(panel->fileField);
+       textEvent = (int)(uintptr_t) WMGetNotificationClientData(notification);
+
+       if (panel->flags.autoCompletion && textEvent != WMDeleteTextEvent)
+               i = closestListItem(list, text, False);
+       else
+               i = closestListItem(list, text, True);
+
+       WMSelectListItem(list, i);
+       if (i >= 0 && panel->flags.autoCompletion) {
+               WMListItem *item = WMGetListItem(list, i);
+               int textLen = strlen(text), itemTextLen = strlen(item->text);
+               int visibleItems = WMWidgetHeight(list) / WMGetListItemHeight(list);
+
+               WMSetListPosition(list, i - visibleItems / 2);
+
+               if (textEvent != WMDeleteTextEvent) {
+                       WMRange range;
+
+                       WMInsertTextFieldText(panel->fileField, &item->text[textLen], textLen);
+                       range.position = textLen;
+                       range.count = itemTextLen - textLen;
+                       WMSelectTextFieldRange(panel->fileField, range);
+                       /*WMSetTextFieldCursorPosition(panel->fileField, itemTextLen); */
+               }
+       }
+
+       wfree(text);
+}
+
+static void textEditedObserver(void *observerData, WMNotification * notification)
+{
+       W_FilePanel *panel = (W_FilePanel *) observerData;
+
+       if ((int)(uintptr_t) WMGetNotificationClientData(notification) == WMReturnTextMovement) {
+               WMPerformButtonClick(panel->okButton);
+       }
+}
+
+static WMFilePanel *makeFilePanel(WMScreen * scrPtr, char *name, char *title)
+{
+       WMFilePanel *fPtr;
+       WMFont *largeFont;
+       WMPixmap *icon;
+
+       fPtr = wmalloc(sizeof(WMFilePanel));
+       memset(fPtr, 0, sizeof(WMFilePanel));
+
+       fPtr->win = WMCreateWindowWithStyle(scrPtr, name, WMTitledWindowMask | WMResizableWindowMask);
+       WMResizeWidget(fPtr->win, PWIDTH, PHEIGHT);
+       WMSetWindowTitle(fPtr->win, "");
+
+       WMCreateEventHandler(WMWidgetView(fPtr->win), StructureNotifyMask, handleEvents, fPtr);
+       WMSetWindowMinSize(fPtr->win, PWIDTH, PHEIGHT);
+
+       fPtr->iconLabel = WMCreateLabel(fPtr->win);
+       WMResizeWidget(fPtr->iconLabel, 64, 64);
+       WMMoveWidget(fPtr->iconLabel, 0, 0);
+       WMSetLabelImagePosition(fPtr->iconLabel, WIPImageOnly);
+       icon = WMCreateApplicationIconBlendedPixmap(scrPtr, (RColor *) NULL);
+       if (icon) {
+               WMSetLabelImage(fPtr->iconLabel, icon);
+               WMReleasePixmap(icon);
+       } else {
+               WMSetLabelImage(fPtr->iconLabel, scrPtr->applicationIconPixmap);
+       }
+
+       fPtr->titleLabel = WMCreateLabel(fPtr->win);
+       WMResizeWidget(fPtr->titleLabel, PWIDTH - 64, 64);
+       WMMoveWidget(fPtr->titleLabel, 64, 0);
+       largeFont = WMBoldSystemFontOfSize(scrPtr, 24);
+       WMSetLabelFont(fPtr->titleLabel, largeFont);
+       WMReleaseFont(largeFont);
+       WMSetLabelText(fPtr->titleLabel, title);
+
+       fPtr->line = WMCreateFrame(fPtr->win);
+       WMMoveWidget(fPtr->line, 0, 64);
+       WMResizeWidget(fPtr->line, PWIDTH, 2);
+       WMSetFrameRelief(fPtr->line, WRGroove);
+
+       fPtr->browser = WMCreateBrowser(fPtr->win);
+       WMSetBrowserAllowEmptySelection(fPtr->browser, True);
+       WMSetBrowserDelegate(fPtr->browser, &browserDelegate);
+       WMSetBrowserAction(fPtr->browser, browserClick, fPtr);
+       WMSetBrowserDoubleAction(fPtr->browser, browserDClick, fPtr);
+       WMMoveWidget(fPtr->browser, 7, 72);
+       WMResizeWidget(fPtr->browser, PWIDTH - 14, 200);
+       WMHangData(fPtr->browser, fPtr);
+
+       fPtr->nameLabel = WMCreateLabel(fPtr->win);
+       WMMoveWidget(fPtr->nameLabel, 7, 282);
+       WMResizeWidget(fPtr->nameLabel, 55, 14);
+       WMSetLabelText(fPtr->nameLabel, _("Name:"));
+
+       fPtr->fileField = WMCreateTextField(fPtr->win);
+       WMMoveWidget(fPtr->fileField, 60, 278);
+       WMResizeWidget(fPtr->fileField, PWIDTH - 60 - 10, 24);
+       WMAddNotificationObserver(textEditedObserver, fPtr, WMTextDidEndEditingNotification, fPtr->fileField);
+       WMAddNotificationObserver(textChangedObserver, fPtr, WMTextDidChangeNotification, fPtr->fileField);
+
+       fPtr->okButton = WMCreateCommandButton(fPtr->win);
+       WMMoveWidget(fPtr->okButton, 245, 325);
+       WMResizeWidget(fPtr->okButton, 75, 28);
+       WMSetButtonText(fPtr->okButton, _("OK"));
+       WMSetButtonImage(fPtr->okButton, scrPtr->buttonArrow);
+       WMSetButtonAltImage(fPtr->okButton, scrPtr->pushedButtonArrow);
+       WMSetButtonImagePosition(fPtr->okButton, WIPRight);
+       WMSetButtonAction(fPtr->okButton, buttonClick, fPtr);
+
+       fPtr->cancelButton = WMCreateCommandButton(fPtr->win);
+       WMMoveWidget(fPtr->cancelButton, 165, 325);
+       WMResizeWidget(fPtr->cancelButton, 75, 28);
+       WMSetButtonText(fPtr->cancelButton, _("Cancel"));
+       WMSetButtonAction(fPtr->cancelButton, buttonClick, fPtr);
+
+       fPtr->trashcanButton = WMCreateCommandButton(fPtr->win);
+       WMMoveWidget(fPtr->trashcanButton, 7, 325);
+       WMResizeWidget(fPtr->trashcanButton, 28, 28);
+       WMSetButtonImagePosition(fPtr->trashcanButton, WIPImageOnly);
+       WMSetButtonImage(fPtr->trashcanButton, scrPtr->trashcanIcon);
+       WMSetButtonAltImage(fPtr->trashcanButton, scrPtr->altTrashcanIcon);
+       WMSetButtonAction(fPtr->trashcanButton, deleteFile, fPtr);
+
+       fPtr->createDirButton = WMCreateCommandButton(fPtr->win);
+       WMMoveWidget(fPtr->createDirButton, 37, 325);
+       WMResizeWidget(fPtr->createDirButton, 28, 28);
+       WMSetButtonImagePosition(fPtr->createDirButton, WIPImageOnly);
+       WMSetButtonImage(fPtr->createDirButton, scrPtr->createDirIcon);
+       WMSetButtonAltImage(fPtr->createDirButton, scrPtr->altCreateDirIcon);
+       WMSetButtonAction(fPtr->createDirButton, createDir, fPtr);
+
+       fPtr->homeButton = WMCreateCommandButton(fPtr->win);
+       WMMoveWidget(fPtr->homeButton, 67, 325);
+       WMResizeWidget(fPtr->homeButton, 28, 28);
+       WMSetButtonImagePosition(fPtr->homeButton, WIPImageOnly);
+       WMSetButtonImage(fPtr->homeButton, scrPtr->homeIcon);
+       WMSetButtonAltImage(fPtr->homeButton, scrPtr->altHomeIcon);
+       WMSetButtonAction(fPtr->homeButton, goHome, fPtr);
+
+       fPtr->disketteButton = WMCreateCommandButton(fPtr->win);
+       WMMoveWidget(fPtr->disketteButton, 97, 325);
+       WMResizeWidget(fPtr->disketteButton, 28, 28);
+       WMSetButtonImagePosition(fPtr->disketteButton, WIPImageOnly);
+       WMSetButtonImage(fPtr->disketteButton, scrPtr->disketteIcon);
+       WMSetButtonAltImage(fPtr->disketteButton, scrPtr->altDisketteIcon);
+       WMSetButtonAction(fPtr->disketteButton, goFloppy, fPtr);
+
+       fPtr->unmountButton = WMCreateCommandButton(fPtr->win);
+       WMMoveWidget(fPtr->unmountButton, 127, 325);
+       WMResizeWidget(fPtr->unmountButton, 28, 28);
+       WMSetButtonImagePosition(fPtr->unmountButton, WIPImageOnly);
+       WMSetButtonImage(fPtr->unmountButton, scrPtr->unmountIcon);
+       WMSetButtonAltImage(fPtr->unmountButton, scrPtr->altUnmountIcon);
+       WMSetButtonAction(fPtr->unmountButton, goUnmount, fPtr);
+       WMSetButtonEnabled(fPtr->unmountButton, False);
+
+       WMRealizeWidget(fPtr->win);
+       WMMapSubwidgets(fPtr->win);
+
+       WMSetFocusToWidget(fPtr->fileField);
+       WMSetTextFieldCursorPosition(fPtr->fileField, 0);
+
+       WMLoadBrowserColumnZero(fPtr->browser);
+
+       WMSetWindowInitialPosition(fPtr->win,
+                                  (scrPtr->rootView->size.width - WMWidgetWidth(fPtr->win)) / 2,
+                                  (scrPtr->rootView->size.height - WMWidgetHeight(fPtr->win)) / 2);
+
+       fPtr->flags.canChooseFiles = 1;
+       fPtr->flags.canChooseDirectories = 1;
+       fPtr->flags.autoCompletion = 1;
+
+       return fPtr;
+}
+
+WMOpenPanel *WMGetOpenPanel(WMScreen * scrPtr)
+{
+       WMFilePanel *panel;
+
+       if (scrPtr->sharedOpenPanel)
+               return scrPtr->sharedOpenPanel;
+
+       panel = makeFilePanel(scrPtr, "openFilePanel", _("Open"));
+       panel->flags.fileMustExist = 1;
+       panel->flags.panelType = WP_OPEN;
+
+       scrPtr->sharedOpenPanel = panel;
+
+       return panel;
+}
+
+WMSavePanel *WMGetSavePanel(WMScreen * scrPtr)
+{
+       WMFilePanel *panel;
+
+       if (scrPtr->sharedSavePanel)
+               return scrPtr->sharedSavePanel;
+
+       panel = makeFilePanel(scrPtr, "saveFilePanel", _("Save"));
+       panel->flags.fileMustExist = 0;
+       panel->flags.panelType = WP_SAVE;
+
+       scrPtr->sharedSavePanel = panel;
+
+       return panel;
+}
+
+void WMFreeFilePanel(WMFilePanel * panel)
+{
+       if (panel == WMWidgetScreen(panel->win)->sharedSavePanel) {
+               WMWidgetScreen(panel->win)->sharedSavePanel = NULL;
+       }
+       if (panel == WMWidgetScreen(panel->win)->sharedOpenPanel) {
+               WMWidgetScreen(panel->win)->sharedOpenPanel = NULL;
+       }
+       WMRemoveNotificationObserver(panel);
+       WMUnmapWidget(panel->win);
+       WMDestroyWidget(panel->win);
+       wfree(panel);
+}
+
+int
+WMRunModalFilePanelForDirectory(WMFilePanel * panel, WMWindow * owner, char *path, char *name, char **fileTypes)
+{
+       WMScreen *scr = WMWidgetScreen(panel->win);
+
+       if (name && !owner) {
+               WMSetWindowTitle(panel->win, name);
+       }
+
+       WMChangePanelOwner(panel->win, owner);
+
+       WMSetFilePanelDirectory(panel, path);
+
+       switch (panel->flags.panelType) {
+       case WP_OPEN:
+               if (fileTypes)
+                       panel->flags.filtered = 1;
+               panel->fileTypes = fileTypes;
+               if (name == NULL)
+                       name = _("Open");
+               break;
+       case WP_SAVE:
+               panel->fileTypes = NULL;
+               panel->flags.filtered = 0;
+               if (name == NULL)
+                       name = _("Save");
+               break;
+       default:
+               break;
+       }
+
+       WMSetLabelText(panel->titleLabel, name);
+
+       WMMapWidget(panel->win);
+
+       WMRunModalLoop(scr, W_VIEW(panel->win));
+
+       /* Must withdraw window because the next time we map
+        * it, it might have a different transient owner.
+        */
+       WMCloseWindow(panel->win);
+
+       return (panel->flags.canceled ? False : True);
+}
+
+void WMSetFilePanelDirectory(WMFilePanel * panel, char *path)
+{
+       WMList *list;
+       WMListItem *item;
+       int col;
+       char *rest;
+
+       rest = WMSetBrowserPath(panel->browser, path);
+       if (strcmp(path, "/") == 0)
+               rest = NULL;
+
+       col = WMGetBrowserSelectedColumn(panel->browser);
+       list = WMGetBrowserListInColumn(panel->browser, col);
+       if (list && (item = WMGetListSelectedItem(list))) {
+               if (item->isBranch) {
+                       WMSetTextFieldText(panel->fileField, rest);
+               } else {
+                       WMSetTextFieldText(panel->fileField, item->text);
+               }
+       } else {
+               WMSetTextFieldText(panel->fileField, rest);
+       }
+}
+
+void WMSetFilePanelCanChooseDirectories(WMFilePanel * panel, Bool flag)
+{
+       panel->flags.canChooseDirectories = ((flag == 0) ? 0 : 1);
+}
+
+void WMSetFilePanelCanChooseFiles(WMFilePanel * panel, Bool flag)
+{
+       panel->flags.canChooseFiles = ((flag == 0) ? 0 : 1);
+}
+
+void WMSetFilePanelAutoCompletion(WMFilePanel * panel, Bool flag)
+{
+       panel->flags.autoCompletion = ((flag == 0) ? 0 : 1);
+}
+
+char *WMGetFilePanelFileName(WMFilePanel * panel)
+{
+       return getCurrentFileName(panel);
+}
+
+void WMSetFilePanelAccessoryView(WMFilePanel * panel, WMView * view)
+{
+       WMView *v;
+
+       panel->accessoryView = view;
+
+       v = WMWidgetView(panel->win);
+
+       W_ReparentView(view, v, 0, 0);
+
+       W_MoveView(view, (v->size.width - v->size.width) / 2, 300);
+}
+
+WMView *WMGetFilePanelAccessoryView(WMFilePanel * panel)
+{
+       return panel->accessoryView;
+}
+
+static char *get_name_from_path(char *path)
+{
+       int size;
+
+       assert(path != NULL);
+
+       size = strlen(path);
+
+       /* remove trailing / */
+       while (size > 0 && path[size - 1] == '/')
+               size--;
+       /* directory was root */
+       if (size == 0)
+               return wstrdup("/");
+
+       while (size > 0 && path[size - 1] != '/')
+               size--;
+
+       return wstrdup(&(path[size]));
+}
+
+static int filterFileName(WMFilePanel * panel, char *file, Bool isDirectory)
+{
+       return True;
+}
+
+#define CAST(item) (*((WMListItem**)item))
+static int comparer(const void *a, const void *b)
+{
+       if (CAST(a)->isBranch == CAST(b)->isBranch)
+               return (strcmp(CAST(a)->text, CAST(b)->text));
+       if (CAST(a)->isBranch)
+               return (-1);
+       return (1);
+}
+
+#undef CAST
+
+static void listDirectoryOnColumn(WMFilePanel * panel, int column, char *path)
+{
+       WMBrowser *bPtr = panel->browser;
+       struct dirent *dentry;
+       DIR *dir;
+       struct stat stat_buf;
+       char pbuf[PATH_MAX + 16];
+       char *name;
+
+       assert(column >= 0);
+       assert(path != NULL);
+
+       /* put directory name in the title */
+       name = get_name_from_path(path);
+       WMSetBrowserColumnTitle(bPtr, column, name);
+       wfree(name);
+
+       dir = opendir(path);
+
+       if (!dir) {
+#ifdef VERBOSE
+               printf(_("WINGs: could not open directory %s\n"), path);
+#endif
+               return;
+       }
+
+       /* list contents in the column */
+       while ((dentry = readdir(dir))) {
+               if (strcmp(dentry->d_name, ".") == 0 || strcmp(dentry->d_name, "..") == 0)
+                       continue;
+
+               strcpy(pbuf, path);
+               if (strcmp(path, "/") != 0)
+                       strcat(pbuf, "/");
+               strcat(pbuf, dentry->d_name);
+
+               if (stat(pbuf, &stat_buf) != 0) {
+#ifdef VERBOSE
+                       printf(_("WINGs: could not stat %s\n"), pbuf);
+#endif
+                       continue;
+               } else {
+                       int isDirectory;
+
+                       isDirectory = S_ISDIR(stat_buf.st_mode);
+
+                       if (filterFileName(panel, dentry->d_name, isDirectory))
+                               WMInsertBrowserItem(bPtr, column, -1, dentry->d_name, isDirectory);
+               }
+       }
+       WMSortBrowserColumnWithComparer(bPtr, column, comparer);
+
+       closedir(dir);
+}
+
+static void fillColumn(WMBrowserDelegate * self, WMBrowser * bPtr, int column, WMList * list)
+{
+       char *path;
+       WMFilePanel *panel;
+
+       if (column > 0) {
+               path = WMGetBrowserPathToColumn(bPtr, column - 1);
+       } else {
+               path = wstrdup("/");
+       }
+
+       panel = WMGetHangedData(bPtr);
+       listDirectoryOnColumn(panel, column, path);
+       wfree(path);
+}
+
+static void browserDClick(WMBrowser * bPtr, WMFilePanel * panel)
+{
+       WMPerformButtonClick(panel->okButton);
+}
+
+static void browserClick(WMBrowser * bPtr, WMFilePanel * panel)
+{
+       int col = WMGetBrowserSelectedColumn(bPtr);
+       WMListItem *item = WMGetBrowserSelectedItemInColumn(bPtr, col);
+
+       if (!item || item->isBranch)
+               WMSetTextFieldText(panel->fileField, NULL);
+       else {
+               WMSetTextFieldText(panel->fileField, item->text);
+       }
+}
+
+static void showError(WMScreen * scr, WMWindow * owner, char *s, char *file)
+{
+       char *errStr;
+
+       if (file) {
+               errStr = wmalloc(strlen(file) + strlen(s));
+               sprintf(errStr, s, file);
+       } else {
+               errStr = wstrdup(s);
+       }
+       WMRunAlertPanel(scr, owner, _("Error"), errStr, _("OK"), NULL, NULL);
+       wfree(errStr);
+}
+
+static void createDir(WMButton * bPre, WMFilePanel * panel)
+{
+       char *dirName, *directory, *file, *s;
+       WMScreen *scr = WMWidgetScreen(panel->win);
+
+       dirName = WMRunInputPanel(scr, panel->win, _("Create Directory"),
+                                 _("Enter directory name"), "", _("OK"), _("Cancel"));
+       if (!dirName)
+               return;
+
+       directory = getCurrentFileName(panel);
+       s = strrchr(directory, '/');
+       if (s)
+               s[1] = 0;
+
+       if (dirName[0] == '/') {
+               directory[0] = 0;
+       } else {
+               while ((s = strstr(directory, "//"))) {
+                       int i;
+                       for (i = 2; s[i] == '/'; i++) ;
+                       strcpy(s, &s[i - 1]);
+               }
+               if ((s = strrchr(directory, '/')) && !s[1])
+                       s[0] = 0;
+       }
+       while ((s = strstr(dirName, "//"))) {
+               int i;
+               for (i = 2; s[i] == '/'; i++) ;
+               strcpy(s, &s[i - 1]);
+       }
+       if ((s = strrchr(dirName, '/')) && !s[1])
+               s[0] = 0;
+
+       file = wmalloc(strlen(dirName) + strlen(directory) + 4);
+       sprintf(file, "%s/%s", directory, dirName);
+       while ((s = strstr(file, "//"))) {
+               int i;
+               for (i = 2; s[i] == '/'; i++) ;
+               strcpy(s, &s[i - 1]);
+       }
+
+       if (mkdir(file, 0xfff) != 0) {
+               switch (errno) {
+               case EACCES:
+                       showError(scr, panel->win, _("Permission denied."), NULL);
+                       break;
+               case EEXIST:
+                       showError(scr, panel->win, _("'%s' already exists."), file);
+                       break;
+               case ENOENT:
+                       showError(scr, panel->win, _("Path does not exist."), NULL);
+               }
+       } else
+               WMSetFilePanelDirectory(panel, file);
+
+       wfree(dirName);
+       wfree(directory);
+       wfree(file);
+}
+
+static void deleteFile(WMButton * bPre, WMFilePanel * panel)
+{
+       char *file;
+       char *buffer, *s;
+       struct stat filestat;
+       WMScreen *scr = WMWidgetScreen(panel->win);
+
+       file = getCurrentFileName(panel);
+
+       while ((s = strstr(file, "//"))) {
+               int i;
+               for (i = 2; s[i] == '/'; i++) ;
+               strcpy(s, &s[i - 1]);
+       }
+       if (strlen(file) > 1 && (s = strrchr(file, '/')) && !s[1])
+               s[0] = 0;
+
+       if (stat(file, &filestat)) {
+               switch (errno) {
+               case ENOENT:
+                       showError(scr, panel->win, _("'%s' does not exist."), file);
+                       break;
+               case EACCES:
+                       showError(scr, panel->win, _("Permission denied."), NULL);
+                       break;
+               case ENOMEM:
+                       showError(scr, panel->win, _("Insufficient memory available."), NULL);
+                       break;
+               case EROFS:
+                       showError(scr, panel->win, _("'%s' is on a read-only filesystem."), file);
+                       break;
+               default:
+                       showError(scr, panel->win, _("Can not delete '%s'."), file);
+               }
+               wfree(file);
+               return;
+       } else if (S_ISDIR(filestat.st_mode)) {
+               int len = strlen(file) + 20;
+               buffer = wmalloc(len);
+               snprintf(buffer, len, _("Delete directory %s ?"), file);
+       } else {
+               int len = strlen(file) + 15;
+               buffer = wmalloc(len);
+               snprintf(buffer, len, _("Delete file %s ?"), file);
+       }
+
+       if (!WMRunAlertPanel(WMWidgetScreen(panel->win), panel->win,
+                            _("Warning"), buffer, _("OK"), _("Cancel"), NULL)) {
+               if (S_ISDIR(filestat.st_mode)) {
+                       if (rmdir(file) != 0) {
+                               switch (errno) {
+                               case EACCES:
+                                       showError(scr, panel->win, _("Permission denied."), NULL);
+                                       break;
+                               case ENOENT:
+                                       showError(scr, panel->win, _("Directory '%s' does not exist."), file);
+                                       break;
+                               case ENOTEMPTY:
+                                       showError(scr, panel->win, _("Directory '%s' is not empty."), file);
+                                       break;
+                               case EBUSY:
+                                       showError(scr, panel->win, _("Directory '%s' is busy."), file);
+                                       break;
+                               default:
+                                       showError(scr, panel->win, _("Can not delete '%s'."), file);
+                               }
+                       } else {
+                               char *s = strrchr(file, '/');
+                               if (s)
+                                       s[0] = 0;
+                               WMSetFilePanelDirectory(panel, file);
+                       }
+               } else if (remove(file) != 0) {
+                       switch (errno) {
+                       case EISDIR:
+                               showError(scr, panel->win, _("'%s' is a directory."), file);
+                               break;
+                       case ENOENT:
+                               showError(scr, panel->win, _("'%s' does not exist."), file);
+                               break;
+                       case EACCES:
+                               showError(scr, panel->win, _("Permission denied."), NULL);
+                               break;
+                       case ENOMEM:
+                               showError(scr, panel->win, _("Insufficient memory available."), NULL);
+                               break;
+                       case EROFS:
+                               showError(scr, panel->win, _("'%s' is on a read-only filesystem."), file);
+                               break;
+                       default:
+                               showError(scr, panel->win, _("Can not delete '%s'."), file);
+                       }
+               } else {
+                       char *s = strrchr(file, '/');
+                       if (s)
+                               s[1] = 0;
+                       WMSetFilePanelDirectory(panel, file);
+               }
+       }
+       wfree(buffer);
+       wfree(file);
+}
+
+static void goUnmount(WMButton * bPtr, WMFilePanel * panel)
+{
+}
+
+static void goFloppy(WMButton * bPtr, WMFilePanel * panel)
+{
+       struct stat filestat;
+       WMScreen *scr = WMWidgetScreen(panel->win);
+
+       if (stat(WINGsConfiguration.floppyPath, &filestat)) {
+               showError(scr, panel->win, _("An error occured browsing '%s'."), WINGsConfiguration.floppyPath);
+               return;
+       } else if (!S_ISDIR(filestat.st_mode)) {
+               showError(scr, panel->win, _("'%s' is not a directory."), WINGsConfiguration.floppyPath);
+               return;
+       }
+
+       WMSetFilePanelDirectory(panel, WINGsConfiguration.floppyPath);
+}
+
+static void goHome(WMButton * bPtr, WMFilePanel * panel)
+{
+       char *home;
+
+       /* home is statically allocated. Don't free it! */
+       home = wgethomedir();
+       if (!home)
+               return;
+
+       WMSetFilePanelDirectory(panel, home);
+}
+
+static void handleEvents(XEvent * event, void *data)
+{
+       W_FilePanel *pPtr = (W_FilePanel *) data;
+       W_View *view = WMWidgetView(pPtr->win);
+
+       if (event->type == ConfigureNotify) {
+               if (event->xconfigure.width != view->size.width || event->xconfigure.height != view->size.height) {
+                       unsigned int newWidth = event->xconfigure.width;
+                       unsigned int newHeight = event->xconfigure.height;
+                       int newColumnCount;
+
+                       W_ResizeView(view, newWidth, newHeight);
+                       WMResizeWidget(pPtr->line, newWidth, 2);
+                       WMResizeWidget(pPtr->browser, newWidth - 14, newHeight - (PHEIGHT - 200));
+                       WMResizeWidget(pPtr->fileField, newWidth - 60 - 10, 24);
+                       WMMoveWidget(pPtr->nameLabel, 7, newHeight - (PHEIGHT - 282));
+                       WMMoveWidget(pPtr->fileField, 60, newHeight - (PHEIGHT - 278));
+                       WMMoveWidget(pPtr->okButton, newWidth - (PWIDTH - 245), newHeight - (PHEIGHT - 325));
+                       WMMoveWidget(pPtr->cancelButton, newWidth - (PWIDTH - 165), newHeight - (PHEIGHT - 325));
+
+                       WMMoveWidget(pPtr->trashcanButton, 7, newHeight - (PHEIGHT - 325));
+                       WMMoveWidget(pPtr->createDirButton, 37, newHeight - (PHEIGHT - 325));
+                       WMMoveWidget(pPtr->homeButton, 67, newHeight - (PHEIGHT - 325));
+                       WMMoveWidget(pPtr->disketteButton, 97, newHeight - (PHEIGHT - 325));
+                       WMMoveWidget(pPtr->unmountButton, 127, newHeight - (PHEIGHT - 325));
+
+                       newColumnCount = (newWidth - 14) / 140;
+                       WMSetBrowserMaxVisibleColumns(pPtr->browser, newColumnCount);
+               }
+       }
+}
+
+static char *getCurrentFileName(WMFilePanel * panel)
+{
+       char *path;
+       char *file;
+       char *tmp;
+       int len;
+
+       path = WMGetBrowserPath(panel->browser);
+
+       len = strlen(path);
+       if (path[len - 1] == '/') {
+               file = WMGetTextFieldText(panel->fileField);
+               tmp = wmalloc(strlen(path) + strlen(file) + 8);
+               if (file[0] != '/') {
+                       strcpy(tmp, path);
+                       strcat(tmp, file);
+               } else
+                       strcpy(tmp, file);
+
+               wfree(file);
+               wfree(path);
+               return tmp;
+       } else {
+               return path;
+       }
+}
+
+static Bool validOpenFile(WMFilePanel * panel)
+{
+       WMListItem *item;
+       int col, haveFile = 0;
+       char *file = WMGetTextFieldText(panel->fileField);
+
+       if (file[0] != '\0')
+               haveFile = 1;
+       wfree(file);
+
+       col = WMGetBrowserSelectedColumn(panel->browser);
+       item = WMGetBrowserSelectedItemInColumn(panel->browser, col);
+       if (item) {
+               if (item->isBranch && !panel->flags.canChooseDirectories && !haveFile)
+                       return False;
+               else if (!item->isBranch && !panel->flags.canChooseFiles)
+                       return False;
+               else
+                       return True;
+       } else {
+               /* we compute for / here */
+               if (!panel->flags.canChooseDirectories && !haveFile)
+                       return False;
+               else
+                       return True;
+       }
+       return True;
+}
+
+static void buttonClick(WMButton * bPtr, WMFilePanel * panel)
+{
+       WMRange range;
+
+       if (bPtr == panel->okButton) {
+               if (!validOpenFile(panel))
+                       return;
+               if (panel->flags.fileMustExist) {
+                       char *file;
+
+                       file = getCurrentFileName(panel);
+                       if (access(file, F_OK) != 0) {
+                               WMRunAlertPanel(WMWidgetScreen(panel->win), panel->win,
+                                               _("Error"), _("File does not exist."), _("OK"), NULL, NULL);
+                               wfree(file);
+                               return;
+                       }
+                       wfree(file);
+               }
+               panel->flags.canceled = 0;
+       } else
+               panel->flags.canceled = 1;
+
+       range.count = range.position = 0;
+       WMSelectTextFieldRange(panel->fileField, range);
+       WMBreakModalLoop(WMWidgetScreen(bPtr));
+}