Change to the linux kernel coding style
[wmaker-crm.git] / WPrefs.app / Menu.c
dissimilarity index 94%
index 0f7f59f..f27159f 100644 (file)
-/* Menu.c- menu definition
- *
- *  WPrefs - Window Maker Preferences Program
- *
- *  Copyright (c) 2000-2003 Alfredo K. Kojima
- *
- *  This program is free software; you can redistribute it and/or modify
- *  it under the terms of the GNU General Public License as published by
- *  the Free Software Foundation; either version 2 of the License, or
- *  (at your option) any later version.
- *
- *  This program is distributed in the hope that it will be useful,
- *  but WITHOUT ANY WARRANTY; without even the implied warranty of
- *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- *  GNU General Public License for more details.
- *
- *  You should have received a copy of the GNU General Public License
- *  along with this program; if not, write to the Free Software
- *  Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307,
- *  USA.
- */
-
-
-#include "WPrefs.h"
-#include <assert.h>
-#include <ctype.h>
-
-#include <X11/keysym.h>
-#include <X11/cursorfont.h>
-
-
-#include "editmenu.h"
-
-
-typedef enum {
-    NoInfo,
-    ExecInfo,
-    CommandInfo,
-    ExternalInfo,
-    PipeInfo,
-    DirectoryInfo,
-    WSMenuInfo,
-    WWindowListInfo,
-    LastInfo
-} InfoType;
-
-#define MAX_SECTION_SIZE 4
-
-typedef struct _Panel {
-    WMBox *box;
-    char *sectionName;
-
-    char *description;
-
-    CallbackRec callbacks;
-    WMWidget *parent;
-
-
-    WMFont *boldFont;
-    WMFont *normalFont;
-    WMColor *white;
-    WMColor *gray;
-    WMColor *black;
-
-    WMPixmap *markerPix[LastInfo];
-
-    WMPopUpButton *typeP;
-
-    WMWidget *itemPad[3];
-    int currentPad;
-
-    WEditMenu *menu;
-    char *menuPath;
-
-    WMFrame *optionsF;
-
-    WMFrame *commandF;
-    WMTextField *commandT;            /* command to run */
-    WMButton *browseB;
-    WMButton *xtermC;                 /* inside xterm? */
-
-    WMFrame *pathF;
-    WMTextField *pathT;
-
-    WMFrame *pipeF;
-    WMTextField *pipeT;
-    WMButton *pipeCacheB;
-
-    WMFrame *dpathF;
-    WMTextField *dpathT;
-
-    WMFrame *dcommandF;
-    WMTextField *dcommandT;
-
-    WMButton *dstripB;
-
-    WMFrame *shortF;
-    WMTextField *shortT;
-    WMButton *sgrabB;
-    WMButton *sclearB;
-
-    WMList *icommandL;
-
-    WMFrame *paramF;
-    WMTextField *paramT;
-
-    WMButton *quickB;
-
-    Bool dontAsk;                     /* whether to comfirm submenu remove */
-    Bool dontSave;
-
-    Bool capturing;
-
-
-    /* about the currently selected item */
-    WEditMenuItem *currentItem;
-    InfoType currentType;
-    WMWidget *sections[LastInfo][MAX_SECTION_SIZE];
-} _Panel;
-
-
-typedef struct {
-    InfoType type;
-    union {
-        struct {
-            int command;
-            char *parameter;
-            char *shortcut;
-        } command;
-        struct {
-            char *command;
-            char *shortcut;
-        } exec;
-        struct {
-            char *path;
-        } external;
-        struct {
-            char *command;
-            unsigned cached:1;
-        } pipe;
-        struct {
-            char *directory;
-            char *command;
-            unsigned stripExt:1;
-        } directory;
-    } param;
-} ItemData;
-
-
-
-static char *commandNames[] = {
-    "ARRANGE_ICONS",
-    "HIDE_OTHERS",
-    "SHOW_ALL",
-    "EXIT",
-    "SHUTDOWN",
-    "RESTART",
-    "RESTART",
-    "SAVE_SESSION",
-    "CLEAR_SESSION",
-    "REFRESH",
-    "INFO_PANEL",
-    "LEGAL_PANEL"
-};
-
-
-
-#define NEW(type) memset(wmalloc(sizeof(type)), 0, sizeof(type))
-
-
-#define ICON_FILE      "menus"
-
-
-
-static void showData(_Panel *panel);
-
-
-static void updateMenuItem(_Panel *panel, WEditMenuItem *item,
-                           WMWidget *changedWidget);
-
-static void menuItemSelected(struct WEditMenuDelegate *delegate,
-                             WEditMenu *menu, WEditMenuItem *item);
-
-static void menuItemDeselected(struct WEditMenuDelegate *delegate,
-                               WEditMenu *menu, WEditMenuItem *item);
-
-static void menuItemCloned(struct WEditMenuDelegate *delegate, WEditMenu *menu,
-                           WEditMenuItem *origItem, WEditMenuItem *newItem);
-
-static void menuItemEdited(struct WEditMenuDelegate *delegate, WEditMenu *menu,
-                           WEditMenuItem *item);
-
-static Bool shouldRemoveItem(struct WEditMenuDelegate *delegate,
-                             WEditMenu *menu, WEditMenuItem *item);
-
-
-static void freeItemData(ItemData *data);
-
-
-
-static WEditMenuDelegate menuDelegate = {
-    NULL,
-    menuItemCloned,
-    menuItemEdited,
-    menuItemSelected,
-    menuItemDeselected,
-    shouldRemoveItem
-};
-
-
-static void
-dataChanged(void *self, WMNotification *notif)
-{
-    _Panel *panel = (_Panel*)self;
-    WEditMenuItem *item = panel->currentItem;
-    WMWidget *w = (WMWidget*)WMGetNotificationObject(notif);
-
-    updateMenuItem(panel, item, w);
-}
-
-
-static void
-buttonClicked(WMWidget *w, void *data)
-{
-    _Panel *panel = (_Panel*)data;
-    WEditMenuItem *item = panel->currentItem;
-
-    updateMenuItem(panel, item, w);
-}
-
-
-static void
-icommandLClicked(WMWidget *w, void *data)
-{
-    _Panel *panel = (_Panel*)data;
-    int cmd;
-
-    cmd = WMGetListSelectedItemRow(w);
-    if (cmd == 3 || cmd == 4) {
-        WMMapWidget(panel->quickB);
-    } else {
-        WMUnmapWidget(panel->quickB);
-    }
-    if (cmd == 6) {
-        WMMapWidget(panel->paramF);
-    } else {
-        WMUnmapWidget(panel->paramF);
-    }
-}
-
-
-static void
-browseForFile(WMWidget *self, void *clientData)
-{
-    _Panel *panel = (_Panel*)clientData;
-    WMFilePanel *filePanel;
-    char *text, *oldprog, *newprog;
-
-    filePanel = WMGetOpenPanel(WMWidgetScreen(self));
-    text = WMGetTextFieldText(panel->commandT);
-
-    oldprog = wtrimspace(text);
-    wfree(text);
-
-    if (oldprog[0]==0 || oldprog[0]!='/') {
-        wfree(oldprog);
-        oldprog = wstrdup("/");
-    } else {
-        char *ptr = oldprog;
-        while (*ptr && !isspace(*ptr))
-            ptr++;
-        *ptr = 0;
-    }
-
-    WMSetFilePanelCanChooseDirectories(filePanel, False);
-
-    if (WMRunModalFilePanelForDirectory(filePanel, panel->parent, oldprog,
-                                        _("Select Program"), NULL)==True) {
-        newprog = WMGetFilePanelFileName(filePanel);
-        WMSetTextFieldText(panel->commandT, newprog);
-        updateMenuItem(panel, panel->currentItem, panel->commandT);
-        wfree(newprog);
-    }
-
-    wfree(oldprog);
-}
-
-
-static char*
-captureShortcut(Display *dpy, _Panel *panel)
-{
-    XEvent ev;
-    KeySym ksym;
-    char buffer[64];
-    char *key = NULL;
-
-    while (panel->capturing) {
-        XAllowEvents(dpy, AsyncKeyboard, CurrentTime);
-        WMNextEvent(dpy, &ev);
-        if (ev.type==KeyPress && ev.xkey.keycode!=0) {
-            ksym = XKeycodeToKeysym(dpy, ev.xkey.keycode, 0);
-            if (!IsModifierKey(ksym)) {
-                key=XKeysymToString(ksym);
-                panel->capturing = 0;
-                break;
-            }
-        }
-        WMHandleEvent(&ev);
-    }
-
-    if (!key)
-        return NULL;
-
-    buffer[0] = 0;
-
-    if (ev.xkey.state & ControlMask) {
-        strcat(buffer, "Control+");
-    }
-    if (ev.xkey.state & ShiftMask) {
-        strcat(buffer, "Shift+");
-    }
-    if (ev.xkey.state & Mod1Mask) {
-        strcat(buffer, "Mod1+");
-    }
-    if (ev.xkey.state & Mod2Mask) {
-        strcat(buffer, "Mod2+");
-    }
-    if (ev.xkey.state & Mod3Mask) {
-        strcat(buffer, "Mod3+");
-    }
-    if (ev.xkey.state & Mod4Mask) {
-        strcat(buffer, "Mod4+");
-    }
-    if (ev.xkey.state & Mod5Mask) {
-        strcat(buffer, "Mod5+");
-    }
-    strcat(buffer, key);
-
-    return wstrdup(buffer);
-}
-
-
-
-static void
-sgrabClicked(WMWidget *w, void *data)
-{
-    _Panel *panel = (_Panel*)data;
-    Display *dpy = WMScreenDisplay(WMWidgetScreen(panel->parent));
-    char *shortcut;
-
-
-    if (w == panel->sclearB) {
-        WMSetTextFieldText(panel->shortT, "");
-        updateMenuItem(panel, panel->currentItem, panel->shortT);
-        return;
-    }
-
-    if (!panel->capturing) {
-        panel->capturing = 1;
-        WMSetButtonText(w, _("Cancel"));
-        XGrabKeyboard(dpy, WMWidgetXID(panel->parent), True, GrabModeAsync,
-                      GrabModeAsync, CurrentTime);
-        shortcut = captureShortcut(dpy, panel);
-        if (shortcut) {
-            WMSetTextFieldText(panel->shortT, shortcut);
-            updateMenuItem(panel, panel->currentItem, panel->shortT);
-            wfree(shortcut);
-        }
-    }
-    panel->capturing = 0;
-    WMSetButtonText(w, _("Capture"));
-    XUngrabKeyboard(dpy, CurrentTime);
-}
-
-
-static void
-changedItemPad(WMWidget *w, void *data)
-{
-    _Panel *panel = (_Panel*)data;
-    int padn = WMGetPopUpButtonSelectedItem(w);
-
-    WMUnmapWidget(panel->itemPad[panel->currentPad]);
-    WMMapWidget(panel->itemPad[padn]);
-
-    panel->currentPad = padn;
-}
-
-
-static WEditMenu*
-putNewSubmenu(WEditMenu *menu, char *title)
-{
-    WEditMenu *tmp;
-    WEditMenuItem *item;
-
-    item = WAddMenuItemWithTitle(menu, title);
-
-    tmp = WCreateEditMenu(WMWidgetScreen(menu), title);
-    WSetEditMenuAcceptsDrop(tmp, True);
-    WSetEditMenuDelegate(tmp, &menuDelegate);
-    WSetEditMenuSubmenu(menu, item, tmp);
-
-    return tmp;
-}
-
-
-static ItemData*
-putNewItem(_Panel *panel, WEditMenu *menu, int type, char *title)
-{
-    WEditMenuItem *item;
-    ItemData *data;
-
-    item = WAddMenuItemWithTitle(menu, title);
-
-    data = NEW(ItemData);
-    data->type = type;
-    WSetEditMenuItemData(item, data, (WMCallback*)freeItemData);
-    WSetEditMenuItemImage(item, panel->markerPix[type]);
-
-    return data;
-}
-
-
-static WEditMenu*
-makeFactoryMenu(WMWidget *parent, int width)
-{
-    WEditMenu *pad;
-
-    pad = WCreateEditMenuPad(parent);
-    WMResizeWidget(pad, width, 10);
-    WSetEditMenuMinSize(pad, wmksize(width, 0));
-    WSetEditMenuMaxSize(pad, wmksize(width, 0));
-    WSetEditMenuSelectable(pad, False);
-    WSetEditMenuEditable(pad, False);
-    WSetEditMenuIsFactory(pad, True);
-    WSetEditMenuDelegate(pad, &menuDelegate);
-
-    return pad;
-}
-
-
-static void
-createPanel(_Panel *p)
-{
-    _Panel *panel = (_Panel*)p;
-    WMScreen *scr = WMWidgetScreen(panel->parent);
-    WMColor *black = WMBlackColor(scr);
-    WMColor *white = WMWhiteColor(scr);
-    WMColor *gray = WMGrayColor(scr);
-    WMFont *bold = WMBoldSystemFontOfSize(scr, 12);
-    WMFont *font = WMSystemFontOfSize(scr, 12);
-    WMLabel *label;
-    int width;
-
-
-    menuDelegate.data = panel;
-
-
-    panel->boldFont = bold;
-    panel->normalFont = font;
-
-    panel->black = black;
-    panel->white = white;
-    panel->gray = gray;
-
-    {
-        Pixmap pix;
-        Display *dpy = WMScreenDisplay(scr);
-        GC gc;
-        WMPixmap *pixm;
-
-        pixm = WMCreatePixmap(scr, 7, 7, WMScreenDepth(scr), True);
-
-        pix = WMGetPixmapXID(pixm);
-
-        XDrawLine(dpy, pix, WMColorGC(black), 0, 3, 6, 3);
-        XDrawLine(dpy, pix, WMColorGC(black), 3, 0, 3, 6);
-        /*
-         XDrawLine(dpy, pix, WMColorGC(black), 1, 0, 3, 3);
-         XDrawLine(dpy, pix, WMColorGC(black), 1, 6, 3, 3);
-         XDrawLine(dpy, pix, WMColorGC(black), 0, 0, 0, 6);
-         */
-
-        pix = WMGetPixmapMaskXID(pixm);
-
-        gc = XCreateGC(dpy, pix, 0, NULL);
-
-        XSetForeground(dpy, gc, 0);
-        XFillRectangle(dpy, pix, gc, 0, 0, 7, 7);
-
-        XSetForeground(dpy, gc, 1);
-        XDrawLine(dpy, pix, gc, 0, 3, 6, 3);
-        XDrawLine(dpy, pix, gc, 3, 0, 3, 6);
-
-        panel->markerPix[ExternalInfo] = pixm;
-        panel->markerPix[PipeInfo] = pixm;
-        panel->markerPix[DirectoryInfo] = pixm;
-        panel->markerPix[WSMenuInfo] = pixm;
-        panel->markerPix[WWindowListInfo] = pixm;
-
-        XFreeGC(dpy, gc);
-    }
-
-    panel->box = WMCreateBox(panel->parent);
-    WMSetViewExpandsToParent(WMWidgetView(panel->box), 2, 2, 2, 2);
-
-    panel->typeP = WMCreatePopUpButton(panel->box);
-    WMResizeWidget(panel->typeP, 150, 20);
-    WMMoveWidget(panel->typeP, 10, 10);
-
-    WMAddPopUpButtonItem(panel->typeP, _("New Items"));
-    WMAddPopUpButtonItem(panel->typeP, _("Sample Commands"));
-    WMAddPopUpButtonItem(panel->typeP, _("Sample Submenus"));
-
-    WMSetPopUpButtonAction(panel->typeP, changedItemPad, panel);
-
-    WMSetPopUpButtonSelectedItem(panel->typeP, 0);
-
-    {
-        WEditMenu *pad;
-        WEditMenu *smenu;
-        ItemData *data;
-
-        pad = makeFactoryMenu(panel->box, 150);
-        WMMoveWidget(pad, 10, 40);
-
-        data = putNewItem(panel, pad, ExecInfo, _("Run Program"));
-        data = putNewItem(panel, pad, CommandInfo, _("Internal Command"));
-        smenu = putNewSubmenu(pad, _("Submenu"));
-        data = putNewItem(panel, pad, ExternalInfo, _("External Submenu"));
-        data = putNewItem(panel, pad, PipeInfo, _("Generated Submenu"));
-        data = putNewItem(panel, pad, DirectoryInfo, _("Directory Contents"));
-        data = putNewItem(panel, pad, WSMenuInfo, _("Workspace Menu"));
-        data = putNewItem(panel, pad, WWindowListInfo, _("Window List Menu"));
-
-        panel->itemPad[0] = pad;
-    }
-
-    {
-        WEditMenu *pad;
-        ItemData *data;
-        WMScrollView *sview;
-
-        sview = WMCreateScrollView(panel->box);
-        WMResizeWidget(sview, 150, 180);
-        WMMoveWidget(sview, 10, 40);
-        WMSetScrollViewHasVerticalScroller(sview, True);
-
-        pad = makeFactoryMenu(panel->box, 130);
-
-        WMSetScrollViewContentView(sview, WMWidgetView(pad));
-
-        data = putNewItem(panel, pad, ExecInfo, _("XTerm"));
-        data->param.exec.command = "xterm -sb -sl 2000 -bg black -fg white";
-
-        data = putNewItem(panel, pad, ExecInfo, _("rxvt"));
-        data->param.exec.command = "rxvt";
-
-        data = putNewItem(panel, pad, ExecInfo, _("ETerm"));
-        data->param.exec.command = "eterm";
-
-        data = putNewItem(panel, pad, ExecInfo, _("Run..."));
-        data->param.exec.command = _("%a(Run,Type command to run)");
-
-        data = putNewItem(panel, pad, ExecInfo, _("Netscape"));
-        data->param.exec.command = "netscape";
-
-        data = putNewItem(panel, pad, ExecInfo, _("gimp"));
-        data->param.exec.command = "gimp";
-
-        data = putNewItem(panel, pad, ExecInfo, _("epic"));
-        data->param.exec.command = "xterm -e epic";
-
-        data = putNewItem(panel, pad, ExecInfo, _("ee"));
-        data->param.exec.command = "ee";
-
-        data = putNewItem(panel, pad, ExecInfo, _("xv"));
-        data->param.exec.command = "xv";
-
-        data = putNewItem(panel, pad, ExecInfo, _("Acrobat Reader"));
-        data->param.exec.command = "acroread || /usr/local/Acrobat4/bin/acroread";
-
-        data = putNewItem(panel, pad, ExecInfo, _("ghostview"));
-        data->param.exec.command = "gv";
-
-        data = putNewItem(panel, pad, CommandInfo, _("Exit Window Maker"));
-        data->param.command.command = 3;
-
-        WMMapWidget(pad);
-
-        panel->itemPad[1] = sview;
-    }
-
-
-    {
-        WEditMenu *pad, *smenu;
-        ItemData *data;
-        WMScrollView *sview;
-
-        sview = WMCreateScrollView(panel->box);
-        WMResizeWidget(sview, 150, 180);
-        WMMoveWidget(sview, 10, 40);
-        WMSetScrollViewHasVerticalScroller(sview, True);
-
-        pad = makeFactoryMenu(panel->box, 130);
-
-        WMSetScrollViewContentView(sview, WMWidgetView(pad));
-
-        data = putNewItem(panel, pad, ExternalInfo, _("Debian Menu"));
-        data->param.pipe.command = "/etc/X11/WindowMaker/menu.hook";
-
-        data = putNewItem(panel, pad, PipeInfo, _("RedHat Menu"));
-        data->param.pipe.command = "wmconfig --output wmaker";
-
-        data = putNewItem(panel, pad, PipeInfo, _("Menu Conectiva"));
-        data->param.pipe.command = "wmconfig --output wmaker";
-
-        data = putNewItem(panel, pad, DirectoryInfo, _("Themes"));
-        data->param.directory.command = "setstyle";
-        data->param.directory.directory = "/usr/share/WindowMaker/Themes /usr/local/share/WindowMaker/Themes $HOME/GNUstep/Library/WindowMaker/Themes";
-        data->param.directory.stripExt = 1;
-
-        data = putNewItem(panel, pad, DirectoryInfo, _("Bg Images (scale)"));
-        data->param.directory.command = "wmsetbg -u -s";
-        data->param.directory.directory = "/opt/kde2/share/wallpapers /usr/share/WindowMaker/Backgrounds $HOME/GNUstep/Library/WindowMaker/Backgrounds";
-        data->param.directory.stripExt = 1;
-
-        data = putNewItem(panel, pad, DirectoryInfo, _("Bg Images (tile)"));
-        data->param.directory.command = "wmsetbg -u -t";
-        data->param.directory.directory = "/opt/kde2/share/wallpapers /usr/share/WindowMaker/Backgrounds $HOME/GNUstep/Library/WindowMaker/Backgrounds";
-        data->param.directory.stripExt = 1;
-
-        smenu = putNewSubmenu(pad, _("Assorted XTerms"));
-
-        data = putNewItem(panel, smenu, ExecInfo, _("XTerm Yellow on Blue"));
-        data->param.exec.command = "xterm -sb -sl 2000 -bg midnightblue -fg yellow";
-
-        data = putNewItem(panel, smenu, ExecInfo, _("XTerm White on Black"));
-        data->param.exec.command = "xterm -sb -sl 2000 -bg black -fg white";
-
-        data = putNewItem(panel, smenu, ExecInfo, _("XTerm Black on White"));
-        data->param.exec.command = "xterm -sb -sl 2000 -bg white -fg black";
-
-        data = putNewItem(panel, smenu, ExecInfo, _("XTerm Black on Beige"));
-        data->param.exec.command = "xterm -sb -sl 2000 -bg '#bbbb99' -fg black";
-
-        data = putNewItem(panel, smenu, ExecInfo, _("XTerm White on Green"));
-        data->param.exec.command = "xterm -sb -sl 2000 -bg '#228822' -fg white";
-
-        data = putNewItem(panel, smenu, ExecInfo, _("XTerm White on Olive"));
-        data->param.exec.command = "xterm -sb -sl 2000 -bg '#335533' -fg white";
-
-        data = putNewItem(panel, smenu, ExecInfo, _("XTerm Blue on Blue"));
-        data->param.exec.command = "xterm -sb -sl 2000 -bg '#112244' -fg '#88aabb'";
-
-        data = putNewItem(panel, smenu, ExecInfo, _("XTerm BIG FONTS"));
-        data->param.exec.command = "xterm -sb -sl 2000 -bg black -fg white -fn 10x20";
-
-        WMMapWidget(pad);
-
-        panel->itemPad[2] = sview;
-    }
-
-
-    width = FRAME_WIDTH - 20 - 150 - 10 - 2;
-
-    panel->optionsF = WMCreateFrame(panel->box);
-    WMResizeWidget(panel->optionsF, width, FRAME_HEIGHT - 15);
-    WMMoveWidget(panel->optionsF, 10 + 150 + 10, 5);
-
-    width -= 20;
-
-    /* command */
-
-    panel->commandF = WMCreateFrame(panel->optionsF);
-    WMResizeWidget(panel->commandF, width, 50);
-    WMMoveWidget(panel->commandF, 10, 20);
-    WMSetFrameTitle(panel->commandF, _("Program to Run"));
-    WMSetFrameTitlePosition(panel->commandF, WTPAtTop);
-
-    panel->commandT = WMCreateTextField(panel->commandF);
-    WMResizeWidget(panel->commandT, width - 95, 20);
-    WMMoveWidget(panel->commandT, 10, 20);
-
-    panel->browseB = WMCreateCommandButton(panel->commandF);
-    WMResizeWidget(panel->browseB, 70, 24);
-    WMMoveWidget(panel->browseB, width - 80, 18);
-    WMSetButtonText(panel->browseB, _("Browse"));
-    WMSetButtonAction(panel->browseB, browseForFile, panel);
-
-    WMAddNotificationObserver(dataChanged, panel,
-                              WMTextDidChangeNotification,
-                              panel->commandT);
-
-#if 0
-    panel->xtermC = WMCreateSwitchButton(panel->commandF);
-    WMResizeWidget(panel->xtermC, width - 20, 20);
-    WMMoveWidget(panel->xtermC, 10, 50);
-    WMSetButtonText(panel->xtermC, _("Run the program inside a Xterm"));
-#endif
-    WMMapSubwidgets(panel->commandF);
-
-
-    /* path */
-
-    panel->pathF = WMCreateFrame(panel->optionsF);
-    WMResizeWidget(panel->pathF, width, 150);
-    WMMoveWidget(panel->pathF, 10, 40);
-    WMSetFrameTitle(panel->pathF, _("Path for Menu"));
-
-    panel->pathT = WMCreateTextField(panel->pathF);
-    WMResizeWidget(panel->pathT, width - 20, 20);
-    WMMoveWidget(panel->pathT, 10, 20);
-
-    WMAddNotificationObserver(dataChanged, panel,
-                              WMTextDidChangeNotification,
-                              panel->pathT);
-
-    label = WMCreateLabel(panel->pathF);
-    WMResizeWidget(label, width - 20, 80);
-    WMMoveWidget(label, 10, 50);
-    WMSetLabelText(label, _("Enter the path for a file containing a menu\n"
-                            "or a list of directories with the programs you\n"
-                            "want to have listed in the menu. Ex:\n"
-                            "~/GNUstep/Library/WindowMaker/menu\n"
-                            "or\n"
-                            "/usr/X11R6/bin ~/xbin"));
-
-    WMMapSubwidgets(panel->pathF);
-
-
-    /* pipe */
-
-    panel->pipeF = WMCreateFrame(panel->optionsF);
-    WMResizeWidget(panel->pipeF, width, 155);
-    WMMoveWidget(panel->pipeF, 10, 30);
-    WMSetFrameTitle(panel->pipeF, _("Command"));
-
-    panel->pipeT = WMCreateTextField(panel->pipeF);
-    WMResizeWidget(panel->pipeT, width - 20, 20);
-    WMMoveWidget(panel->pipeT, 10, 20);
-
-    WMAddNotificationObserver(dataChanged, panel,
-                              WMTextDidChangeNotification,
-                              panel->pipeT);
-
-
-    label = WMCreateLabel(panel->pipeF);
-    WMResizeWidget(label, width - 20, 40);
-    WMMoveWidget(label, 10, 50);
-    WMSetLabelText(label, _("Enter a command that outputs a menu\n"
-                            "definition to stdout when invoked."));
-
-
-    panel->pipeCacheB = WMCreateSwitchButton(panel->pipeF);
-    WMResizeWidget(panel->pipeCacheB, width - 20, 40);
-    WMMoveWidget(panel->pipeCacheB, 10, 110);
-    WMSetButtonText(panel->pipeCacheB,
-                    _("Cache menu contents after opening for\n"
-                      "the first time"));
-
-    WMMapSubwidgets(panel->pipeF);
-
-
-    /* directory menu */
-
-    panel->dcommandF = WMCreateFrame(panel->optionsF);
-    WMResizeWidget(panel->dcommandF, width, 90);
-    WMMoveWidget(panel->dcommandF, 10, 25);
-    WMSetFrameTitle(panel->dcommandF, _("Command to Open Files"));
-
-    panel->dcommandT = WMCreateTextField(panel->dcommandF);
-    WMResizeWidget(panel->dcommandT, width - 20, 20);
-    WMMoveWidget(panel->dcommandT, 10, 20);
-
-    WMAddNotificationObserver(dataChanged, panel,
-                              WMTextDidChangeNotification,
-                              panel->dcommandT);
-
-
-    label = WMCreateLabel(panel->dcommandF);
-    WMResizeWidget(label, width - 20, 45);
-    WMMoveWidget(label, 10, 40);
-    WMSetLabelText(label, _("Enter the command you want to use to open the\n"
-                            "files in the directories listed below."));
-
-    WMMapSubwidgets(panel->dcommandF);
-
-
-    panel->dpathF = WMCreateFrame(panel->optionsF);
-    WMResizeWidget(panel->dpathF, width, 80);
-    WMMoveWidget(panel->dpathF, 10, 125);
-    WMSetFrameTitle(panel->dpathF, _("Directories with Files"));
-
-    panel->dpathT = WMCreateTextField(panel->dpathF);
-    WMResizeWidget(panel->dpathT, width - 20, 20);
-    WMMoveWidget(panel->dpathT, 10, 20);
-
-    WMAddNotificationObserver(dataChanged, panel,
-                              WMTextDidChangeNotification,
-                              panel->dpathT);
-
-    panel->dstripB = WMCreateSwitchButton(panel->dpathF);
-    WMResizeWidget(panel->dstripB, width - 20, 20);
-    WMMoveWidget(panel->dstripB, 10, 50);
-    WMSetButtonText(panel->dstripB, _("Strip extensions from file names"));
-
-    WMSetButtonAction(panel->dstripB, buttonClicked, panel);
-
-    WMMapSubwidgets(panel->dpathF);
-
-
-    /* shortcut */
-
-    panel->shortF = WMCreateFrame(panel->optionsF);
-    WMResizeWidget(panel->shortF, width, 50);
-    WMMoveWidget(panel->shortF, 10, 160);
-    WMSetFrameTitle(panel->shortF, _("Keyboard Shortcut"));
-
-    panel->shortT = WMCreateTextField(panel->shortF);
-    WMResizeWidget(panel->shortT, width - 20 - 150, 20);
-    WMMoveWidget(panel->shortT, 10, 20);
-
-    WMAddNotificationObserver(dataChanged, panel,
-                              WMTextDidChangeNotification,
-                              panel->shortT);
-
-    panel->sgrabB = WMCreateCommandButton(panel->shortF);
-    WMResizeWidget(panel->sgrabB, 70, 24);
-    WMMoveWidget(panel->sgrabB, width - 80, 18);
-    WMSetButtonText(panel->sgrabB, _("Capture"));
-    WMSetButtonAction(panel->sgrabB, sgrabClicked, panel);
-
-    panel->sclearB = WMCreateCommandButton(panel->shortF);
-    WMResizeWidget(panel->sclearB, 70, 24);
-    WMMoveWidget(panel->sclearB, width - 155, 18);
-    WMSetButtonText(panel->sclearB, _("Clear"));
-    WMSetButtonAction(panel->sclearB, sgrabClicked, panel);
-
-    WMMapSubwidgets(panel->shortF);
-
-    /* internal command */
-
-    panel->icommandL = WMCreateList(panel->optionsF);
-    WMResizeWidget(panel->icommandL, width, 80);
-    WMMoveWidget(panel->icommandL, 10, 20);
-
-    WMSetListAction(panel->icommandL, icommandLClicked, panel);
-
-    WMAddNotificationObserver(dataChanged, panel,
-                              WMListSelectionDidChangeNotification,
-                              panel->icommandL);
-
-    WMInsertListItem(panel->icommandL, 0, _("Arrange Icons"));
-    WMInsertListItem(panel->icommandL, 1, _("Hide All Windows Except For The Focused One"));
-    WMInsertListItem(panel->icommandL, 2, _("Show All Windows"));
-
-    WMInsertListItem(panel->icommandL, 3, _("Exit Window Maker"));
-    WMInsertListItem(panel->icommandL, 4, _("Exit X Session"));
-    WMInsertListItem(panel->icommandL, 5, _("Restart Window Maker"));
-    WMInsertListItem(panel->icommandL, 6, _("Start Another Window Manager   : ("));
-
-    WMInsertListItem(panel->icommandL, 7, _("Save Current Session"));
-    WMInsertListItem(panel->icommandL, 8, _("Clear Saved Session"));
-    WMInsertListItem(panel->icommandL, 9, _("Refresh Screen"));
-    WMInsertListItem(panel->icommandL, 10, _("Open Info Panel"));
-    WMInsertListItem(panel->icommandL, 11, _("Open Copyright Panel"));
-
-
-    panel->paramF = WMCreateFrame(panel->optionsF);
-    WMResizeWidget(panel->paramF, width, 50);
-    WMMoveWidget(panel->paramF, 10, 105);
-    WMSetFrameTitle(panel->paramF, _("Window Manager to Start"));
-
-    panel->paramT = WMCreateTextField(panel->paramF);
-    WMResizeWidget(panel->paramT, width - 20, 20);
-    WMMoveWidget(panel->paramT, 10, 20);
-
-    WMAddNotificationObserver(dataChanged, panel,
-                              WMTextDidChangeNotification,
-                              panel->paramT);
-
-    WMMapSubwidgets(panel->paramF);
-
-
-    panel->quickB = WMCreateSwitchButton(panel->optionsF);
-    WMResizeWidget(panel->quickB, width, 20);
-    WMMoveWidget(panel->quickB, 10, 120);
-    WMSetButtonText(panel->quickB, _("Do not confirm action."));
-    WMSetButtonAction(panel->quickB, buttonClicked, panel);
-
-
-    label = WMCreateLabel(panel->optionsF);
-    WMResizeWidget(label, width+5, FRAME_HEIGHT - 50);
-    WMMoveWidget(label, 7, 20);
-    WMSetLabelText(label,
-                   _("Instructions:\n\n"
-                     " - drag items from the left to the menu to add new items\n"
-                     " - drag items out of the menu to remove items\n"
-                     " - drag items in menu to change their position\n"
-                     " - drag items with Control pressed to copy them\n"
-                     " - double click in a menu item to change the label\n"
-                     " - click on a menu item to change related information"));
-    WMMapWidget(label);
-
-    WMRealizeWidget(panel->box);
-    WMMapSubwidgets(panel->box);
-    WMMapWidget(panel->box);
-
-
-    {
-        int i;
-        for (i = 0; i < 3; i++)
-            WMUnmapWidget(panel->itemPad[i]);
-    }
-    changedItemPad(panel->typeP, panel);
-
-    panel->sections[NoInfo][0] = label;
-
-    panel->sections[ExecInfo][0] = panel->commandF;
-    panel->sections[ExecInfo][1] = panel->shortF;
-
-    panel->sections[CommandInfo][0] = panel->icommandL;
-    panel->sections[CommandInfo][1] = panel->shortF;
-
-    panel->sections[ExternalInfo][0] = panel->pathF;
-
-    panel->sections[PipeInfo][0] = panel->pipeF;
-
-    panel->sections[DirectoryInfo][0] = panel->dpathF;
-    panel->sections[DirectoryInfo][1] = panel->dcommandF;
-
-    panel->currentType = NoInfo;
-
-    showData(panel);
-
-    {
-        WMPoint pos;
-
-        pos = WMGetViewScreenPosition(WMWidgetView(panel->box));
-
-        if (pos.x < 200) {
-            pos.x += FRAME_WIDTH + 20;
-        } else {
-            pos.x = 10;
-        }
-
-        pos.y = WMAX(pos.y - 100, 0);
-
-        if (panel->menu)
-            WEditMenuShowAt(panel->menu, pos.x, pos.y);
-    }
-}
-
-
-
-
-static void
-freeItemData(ItemData *data)
-{
-#define CFREE(d) if (d) wfree(d)
-
-    /* TODO */
-    switch (data->type) {
-    case CommandInfo:
-        CFREE(data->param.command.parameter);
-        CFREE(data->param.command.shortcut);
-        break;
-
-    case ExecInfo:
-        CFREE(data->param.exec.command);
-        CFREE(data->param.exec.shortcut);
-        break;
-
-    case PipeInfo:
-        CFREE(data->param.pipe.command);
-        break;
-
-    case ExternalInfo:
-        CFREE(data->param.external.path);
-        break;
-
-    case DirectoryInfo:
-        CFREE(data->param.directory.command);
-        CFREE(data->param.directory.directory);
-        break;
-
-    default:
-        break;
-    }
-
-    wfree(data);
-#undef CFREE
-}
-
-
-static ItemData*
-parseCommand(WMPropList *item)
-{
-    ItemData *data = NEW(ItemData);
-    WMPropList *p;
-    char *command = NULL;
-    char *parameter = NULL;
-    char *shortcut = NULL;
-    int i = 1;
-
-
-    p = WMGetFromPLArray(item, i++);
-    command = WMGetFromPLString(p);
-    if (strcmp(command, "SHORTCUT") == 0) {
-        p = WMGetFromPLArray(item, i++);
-        shortcut = WMGetFromPLString(p);
-        p = WMGetFromPLArray(item, i++);
-        command = WMGetFromPLString(p);
-    }
-    p = WMGetFromPLArray(item, i++);
-    if (p)
-        parameter = WMGetFromPLString(p);
-
-    if (strcmp(command, "EXEC") == 0 || strcmp(command, "SHEXEC") == 0) {
-
-        data->type = ExecInfo;
-
-        data->param.exec.command = wstrdup(parameter);
-        if (shortcut)
-            data->param.exec.shortcut = wstrdup(shortcut);
-
-    } else if (strcmp(command, "OPEN_MENU") == 0) {
-        char *p;
-        /*
-         * dir menu, menu file
-         * dir WITH
-         * |pipe
-         */
-        p = parameter;
-        while (isspace(*p) && *p) p++;
-        if (*p == '|') {
-            if (*(p+1) == '|') {
-                p++;
-                data->param.pipe.cached = 0;
-            } else {
-                data->param.pipe.cached = 1;
-            }
-            data->type = PipeInfo;
-            data->param.pipe.command = wtrimspace(p+1);
-        } else {
-            char *s;
-
-            p = wstrdup(p);
-
-            s = strstr(p, "WITH");
-            if (s) {
-                char **tokens;
-                char **ctokens;
-                int tokn;
-                int i, j;
-
-                data->type = DirectoryInfo;
-
-                *s = '\0';
-                s += 5;
-                while (*s && isspace(*s)) s++;
-                data->param.directory.command = wstrdup(s);
-
-                wtokensplit(p, &tokens, &tokn);
-                wfree(p);
-
-                ctokens = wmalloc(sizeof(char*)*tokn);
-
-                for (i = 0, j = 0; i < tokn; i++) {
-                    if (strcmp(tokens[i], "-noext") == 0) {
-                        wfree(tokens[i]);
-                        data->param.directory.stripExt = 1;
-                    } else {
-                        ctokens[j++] = tokens[i];
-                    }
-                }
-                data->param.directory.directory = wtokenjoin(ctokens, j);
-                wfree(ctokens);
-
-                wtokenfree(tokens, tokn);
-            } else {
-                data->type = ExternalInfo;
-                data->param.external.path = p;
-            }
-        }
-    } else if (strcmp(command, "WORKSPACE_MENU") == 0) {
-        data->type = WSMenuInfo;
-    } else if (strcmp(command, "WINDOWS_MENU") == 0) {
-        data->type = WWindowListInfo;
-    } else {
-        int cmd;
-
-        if (strcmp(command, "ARRANGE_ICONS") == 0) {
-            cmd = 0;
-        } else if (strcmp(command, "HIDE_OTHERS") == 0) {
-            cmd = 1;
-        } else if (strcmp(command, "SHOW_ALL") == 0) {
-            cmd = 2;
-        } else if (strcmp(command, "EXIT") == 0) {
-            cmd = 3;
-        } else if (strcmp(command, "SHUTDOWN") == 0) {
-            cmd = 4;
-        } else if (strcmp(command, "RESTART") == 0) {
-            if (parameter) {
-                cmd = 6;
-            } else {
-                cmd = 5;
-            }
-        } else if (strcmp(command, "SAVE_SESSION") == 0) {
-            cmd = 7;
-        } else if (strcmp(command, "CLEAR_SESSION") == 0) {
-            cmd = 8;
-        } else if (strcmp(command, "REFRESH") == 0) {
-            cmd = 9;
-        } else if (strcmp(command, "INFO_PANEL") == 0) {
-            cmd = 10;
-        } else if (strcmp(command, "LEGAL_PANEL") == 0) {
-            cmd = 11;
-        } else {
-            wwarning(_("unknown command '%s' in menu"), command);
-            goto error;
-        }
-
-        data->type = CommandInfo;
-
-        data->param.command.command = cmd;
-        if (shortcut)
-            data->param.command.shortcut = wstrdup(shortcut);
-        if (parameter)
-            data->param.command.parameter = wstrdup(parameter);
-    }
-
-    return data;
-
-error:
-    wfree(data);
-
-    return NULL;
-}
-
-
-
-
-static void
-updateFrameTitle(_Panel *panel, char *title, InfoType type)
-{
-    if (type != NoInfo) {
-        char *tmp;
-
-        switch (type) {
-        case ExecInfo:
-            tmp = wstrconcat(title, _(": Execute Program"));
-            break;
-
-        case CommandInfo:
-            tmp = wstrconcat(title, _(": Perform Internal Command"));
-            break;
-
-        case ExternalInfo:
-            tmp = wstrconcat(title, _(": Open a Submenu"));
-            break;
-
-        case PipeInfo:
-            tmp = wstrconcat(title, _(": Program Generated Submenu"));
-            break;
-
-        case DirectoryInfo:
-            tmp = wstrconcat(title, _(": Directory Contents Menu"));
-            break;
-
-        case WSMenuInfo:
-            tmp = wstrconcat(title, _(": Open Workspaces Submenu"));
-            break;
-
-        case WWindowListInfo:
-            tmp = wstrconcat(title, _(": Open Window List Submenu"));
-            break;
-
-        default:
-            tmp = NULL;
-            break;
-        }
-        WMSetFrameTitle(panel->optionsF, tmp);
-        wfree(tmp);
-    } else {
-        WMSetFrameTitle(panel->optionsF, NULL);
-    }
-}
-
-
-
-static void
-changeInfoType(_Panel *panel, char *title, InfoType type)
-{
-    WMWidget **w;
-
-    if (panel->currentType != type) {
-
-        w = panel->sections[panel->currentType];
-
-        while (*w) {
-            WMUnmapWidget(*w);
-            w++;
-        }
-        WMUnmapWidget(panel->paramF);
-        WMUnmapWidget(panel->quickB);
-
-
-        w = panel->sections[type];
-
-        while (*w) {
-            WMMapWidget(*w);
-            w++;
-        }
-    }
-
-    updateFrameTitle(panel, title, type);
-
-    panel->currentType = type;
-}
-
-
-
-
-static void
-updateMenuItem(_Panel *panel, WEditMenuItem *item, WMWidget *changedWidget)
-{
-    ItemData *data = WGetEditMenuItemData(item);
-
-    assert(data != NULL);
-
-#define REPLACE(v, d) if (v) wfree(v); v = d
-
-    switch (data->type) {
-    case ExecInfo:
-        if (changedWidget == panel->commandT) {
-            REPLACE(data->param.exec.command,
-                    WMGetTextFieldText(panel->commandT));
-        }
-        if (changedWidget == panel->shortT) {
-            REPLACE(data->param.exec.shortcut,
-                    WMGetTextFieldText(panel->shortT));
-        }
-        break;
-
-    case CommandInfo:
-        if (changedWidget == panel->icommandL) {
-            data->param.command.command =
-                WMGetListSelectedItemRow(panel->icommandL);
-        }
-        switch (data->param.command.command) {
-        case 3:
-        case 4:
-            if (changedWidget == panel->quickB) {
-                REPLACE(data->param.command.parameter,
-                        WMGetButtonSelected(panel->quickB)
-                        ? wstrdup("QUICK") : NULL);
-            }
-            break;
-
-        case 6:
-            if (changedWidget == panel->paramT) {
-                REPLACE(data->param.command.parameter,
-                        WMGetTextFieldText(panel->paramT));
-            }
-            break;
-        }
-        if (changedWidget == panel->shortT) {
-            REPLACE(data->param.command.shortcut,
-                    WMGetTextFieldText(panel->shortT));
-        }
-
-
-        break;
-
-    case PipeInfo:
-        if (changedWidget == panel->pipeT) {
-            REPLACE(data->param.pipe.command,
-                    WMGetTextFieldText(panel->pipeT));
-        }
-        if (changedWidget == panel->pipeCacheB) {
-            data->param.pipe.cached =
-                WMGetButtonSelected(panel->pipeCacheB);
-        }
-        break;
-
-    case ExternalInfo:
-        if (changedWidget == panel->pathT) {
-            REPLACE(data->param.external.path,
-                    WMGetTextFieldText(panel->pathT));
-        }
-        break;
-
-    case DirectoryInfo:
-        if (changedWidget == panel->dpathT) {
-            REPLACE(data->param.directory.directory,
-                    WMGetTextFieldText(panel->dpathT));
-        }
-        if (changedWidget == panel->dcommandT) {
-            REPLACE(data->param.directory.command,
-                    WMGetTextFieldText(panel->dcommandT));
-        }
-        if (changedWidget == panel->dstripB) {
-            data->param.directory.stripExt =
-                WMGetButtonSelected(panel->dstripB);
-        }
-        break;
-
-    default:
-        assert(0);
-        break;
-    }
-
-#undef REPLACE
-}
-
-
-
-static void
-menuItemCloned(WEditMenuDelegate *delegate, WEditMenu *menu,
-               WEditMenuItem *origItem, WEditMenuItem *newItem)
-{
-    ItemData *data = WGetEditMenuItemData(origItem);
-    ItemData *newData;
-
-    if (!data)
-        return;
-
-#define DUP(s) (s) ? wstrdup(s) : NULL
-
-    newData = NEW(ItemData);
-
-    newData->type = data->type;
-
-    switch (data->type) {
-    case ExecInfo:
-        newData->param.exec.command = DUP(data->param.exec.command);
-        newData->param.exec.shortcut = DUP(data->param.exec.shortcut);
-        break;
-
-    case CommandInfo:
-        newData->param.command.command = data->param.command.command;
-        newData->param.command.parameter = DUP(data->param.command.parameter);
-        newData->param.command.shortcut = DUP(data->param.command.shortcut);
-        break;
-
-    case PipeInfo:
-        newData->param.pipe.command = DUP(data->param.pipe.command);
-        newData->param.pipe.cached = data->param.pipe.cached;
-        break;
-
-    case ExternalInfo:
-        newData->param.external.path = DUP(data->param.external.path);
-        break;
-
-    case DirectoryInfo:
-        newData->param.directory.directory = DUP(data->param.directory.directory);
-        newData->param.directory.command = DUP(data->param.directory.command);
-        newData->param.directory.stripExt = data->param.directory.stripExt;
-        break;
-
-    default:
-        break;
-    }
-
-#undef DUP
-
-    WSetEditMenuItemData(newItem, newData, (WMCallback*)freeItemData);
-}
-
-
-static void
-menuItemEdited(struct WEditMenuDelegate *delegate, WEditMenu *menu,
-               WEditMenuItem *item)
-{
-    _Panel *panel = (_Panel*)delegate->data;
-    WEditMenu *submenu;
-
-    updateFrameTitle(panel, WGetEditMenuItemTitle(item), panel->currentType);
-
-    submenu = WGetEditMenuSubmenu(menu, item);
-    if (submenu) {
-        WSetEditMenuTitle(submenu, WGetEditMenuItemTitle(item));
-    }
-}
-
-
-static Bool
-shouldRemoveItem(struct WEditMenuDelegate *delegate, WEditMenu *menu,
-                 WEditMenuItem *item)
-{
-    _Panel *panel = (_Panel*)delegate->data;
-
-    if (panel->dontAsk)
-        return True;
-
-    if (WGetEditMenuSubmenu(menu, item)) {
-        int res;
-
-        res = WMRunAlertPanel(WMWidgetScreen(menu), NULL,
-                              _("Remove Submenu"),
-                              _("Removing this item will destroy all items inside\n"
-                                "the submenu. Do you really want to do that?"),
-                              _("Yes"), _("No"),
-                              _("Yes, don't ask again."));
-        switch (res) {
-        case WAPRDefault:
-            return True;
-        case WAPRAlternate:
-            return False;
-        case WAPROther:
-            panel->dontAsk = True;
-            return True;
-        }
-    }
-    return True;
-}
-
-
-static void
-menuItemDeselected(WEditMenuDelegate *delegate, WEditMenu *menu,
-                   WEditMenuItem *item)
-{
-    _Panel *panel = (_Panel*)delegate->data;
-
-    changeInfoType(panel, NULL, NoInfo);
-}
-
-
-static void
-menuItemSelected(WEditMenuDelegate *delegate, WEditMenu *menu,
-                 WEditMenuItem *item)
-{
-    ItemData *data = WGetEditMenuItemData(item);
-    _Panel *panel = (_Panel*)delegate->data;
-
-    panel->currentItem = item;
-
-    if (data) {
-        changeInfoType(panel, WGetEditMenuItemTitle(item), data->type);
-
-        switch (data->type) {
-        case NoInfo:
-            break;
-
-        case ExecInfo:
-            WMSetTextFieldText(panel->commandT, data->param.exec.command);
-            WMSetTextFieldText(panel->shortT, data->param.exec.shortcut);
-            break;
-
-        case CommandInfo:
-            WMSelectListItem(panel->icommandL,
-                             data->param.command.command);
-            WMSetListPosition(panel->icommandL,
-                              data->param.command.command - 2);
-            WMSetTextFieldText(panel->shortT, data->param.command.shortcut);
-
-            switch (data->param.command.command) {
-            case 3:
-            case 4:
-                WMSetButtonSelected(panel->quickB,
-                                    data->param.command.parameter!=NULL);
-                break;
-            case 6:
-                WMSetTextFieldText(panel->paramT,
-                                   data->param.command.parameter);
-                break;
-            }
-
-            icommandLClicked(panel->icommandL, panel);
-            break;
-
-        case PipeInfo:
-            WMSetTextFieldText(panel->pipeT, data->param.pipe.command);
-            WMSetButtonSelected(panel->pipeCacheB, data->param.pipe.cached);
-            break;
-
-        case ExternalInfo:
-            WMSetTextFieldText(panel->pathT, data->param.external.path);
-            break;
-
-        case DirectoryInfo:
-            WMSetTextFieldText(panel->dpathT, data->param.directory.directory);
-            WMSetTextFieldText(panel->dcommandT, data->param.directory.command);
-            WMSetButtonSelected(panel->dstripB, data->param.directory.stripExt);
-            break;
-
-        case WSMenuInfo:
-            break;
-
-        default:
-            break;
-        }
-    }
-}
-
-
-
-static WEditMenu*
-buildSubmenu(_Panel *panel, WMPropList *pl)
-{
-    WMScreen *scr = WMWidgetScreen(panel->parent);
-    WEditMenu *menu;
-    WEditMenuItem *item;
-    char *title;
-    WMPropList *tp, *bp;
-    int i;
-
-    tp = WMGetFromPLArray(pl, 0);
-    title = WMGetFromPLString(tp);
-
-    menu = WCreateEditMenu(scr, title);
-
-    for (i = 1; i < WMGetPropListItemCount(pl); i++) {
-        WMPropList *pi;
-
-        pi = WMGetFromPLArray(pl, i);
-
-        tp = WMGetFromPLArray(pi, 0);
-        bp = WMGetFromPLArray(pi, 1);
-
-        title = WMGetFromPLString(tp);
-
-        if (!bp || WMIsPLArray(bp)) {         /* it's a submenu */
-            WEditMenu *submenu;
-
-            submenu = buildSubmenu(panel, pi);
-
-            item = WAddMenuItemWithTitle(menu, title);
-
-            WSetEditMenuSubmenu(menu, item, submenu);
-        } else {
-            ItemData *data;
-
-            item = WAddMenuItemWithTitle(menu, title);
-
-            data = parseCommand(pi);
-
-            if (panel->markerPix[data->type])
-                WSetEditMenuItemImage(item, panel->markerPix[data->type]);
-            WSetEditMenuItemData(item, data, (WMCallback*)freeItemData);
-        }
-    }
-
-    WSetEditMenuAcceptsDrop(menu, True);
-    WSetEditMenuDelegate(menu, &menuDelegate);
-
-    WMRealizeWidget(menu);
-
-    return menu;
-}
-
-
-
-static void
-buildMenuFromPL(_Panel *panel, WMPropList *pl)
-{
-    panel->menu = buildSubmenu(panel, pl);
-}
-
-
-
-static WMPropList*
-getDefaultMenu(_Panel *panel)
-{
-    WMPropList *menu;
-    char *menuPath, *gspath;
-
-    gspath = wusergnusteppath();
-
-    menuPath = wmalloc(strlen(gspath)+128);
-    sprintf(menuPath, "%s/Library/WindowMaker/plmenu", gspath);
-
-    menu = WMReadPropListFromFile(menuPath);
-
-    if (!menu) {
-        char *buffer, *msg;
-
-        msg = _("Could not open default menu from '%s'");
-        buffer = wmalloc(strlen(msg) + strlen(menuPath) + 10);
-        sprintf(buffer, msg, menuPath);
-        WMRunAlertPanel(WMWidgetScreen(panel->parent), panel->parent,
-                        _("Error"), buffer,    _("OK"), NULL, NULL);
-        wfree(buffer);
-    }
-
-    wfree(menuPath);
-
-    return menu;
-}
-
-
-static void
-showData(_Panel *panel)
-{
-    char *gspath;
-    char *menuPath;
-    WMPropList *pmenu;
-
-    gspath = wusergnusteppath();
-
-    menuPath = wmalloc(strlen(gspath)+32);
-    strcpy(menuPath, gspath);
-    strcat(menuPath, "/Defaults/WMRootMenu");
-
-    pmenu = WMReadPropListFromFile(menuPath);
-
-    if (!pmenu || !WMIsPLArray(pmenu)) {
-        int res;
-
-        res = WMRunAlertPanel(WMWidgetScreen(panel->parent), panel->parent,
-                              _("Warning"),
-                              _("The menu file format currently in use is not supported\n"
-                                "by this tool. Do you want to discard the current menu\n"
-                                "to use this tool?"),
-                              _("Yes, Discard and Update"),
-                              _("No, Keep Current Menu"), NULL);
-
-        if (res == WAPRDefault) {
-            pmenu = getDefaultMenu(panel);
-
-            if (!pmenu) {
-                pmenu = WMCreatePLArray(WMCreatePLString("Applications"),
-                                        NULL);
-            }
-        } else {
-            panel->dontSave = True;
-            return;
-        }
-    }
-
-    panel->menuPath = menuPath;
-
-    buildMenuFromPL(panel, pmenu);
-
-    WMReleasePropList(pmenu);
-}
-
-
-static Bool
-notblank(char *s)
-{
-    if (s) {
-        while (*s++) {
-            if (!isspace(*s))
-                return True;
-        }
-    }
-    return False;
-}
-
-
-static WMPropList*
-processData(char *title, ItemData *data)
-{
-    WMPropList *item;
-    char *s1;
-    static WMPropList *pscut = NULL;
-    static WMPropList *pomenu = NULL;
-    int i;
-
-    if (!pscut) {
-        pscut = WMCreatePLString("SHORTCUT");
-        pomenu = WMCreatePLString("OPEN_MENU");
-    }
-
-    item = WMCreatePLArray(WMCreatePLString(title), NULL);
-
-
-    switch (data->type) {
-    case ExecInfo:
-        if (data->param.exec.command == NULL)
-            return NULL;
-#if 1
-        if (strpbrk(data->param.exec.command, "&$*|><?`=;")) {
-            s1 = "SHEXEC";
-        } else {
-            s1 = "EXEC";
-        }
-#else
-        s1 = "SHEXEC";
-#endif
-
-        if (notblank(data->param.exec.shortcut)) {
-            WMAddToPLArray(item, pscut);
-            WMAddToPLArray(item,
-                           WMCreatePLString(data->param.exec.shortcut));
-        }
-
-        WMAddToPLArray(item, WMCreatePLString(s1));
-        WMAddToPLArray(item, WMCreatePLString(data->param.exec.command));
-        break;
-
-    case CommandInfo:
-        if (notblank(data->param.command.shortcut)) {
-            WMAddToPLArray(item, pscut);
-            WMAddToPLArray(item,
-                           WMCreatePLString(data->param.command.shortcut));
-        }
-
-        i = data->param.command.command;
-
-        WMAddToPLArray(item, WMCreatePLString(commandNames[i]));
-
-        switch (i) {
-        case 3:
-        case 4:
-            if (data->param.command.parameter) {
-                WMAddToPLArray(item,
-                               WMCreatePLString(data->param.command.parameter));
-            }
-            break;
-
-        case 6: /* restart */
-            if (data->param.command.parameter) {
-                WMAddToPLArray(item,
-                               WMCreatePLString(data->param.command.parameter));
-            }
-            break;
-        }
-
-        break;
-
-    case PipeInfo:
-        if (!data->param.pipe.command)
-            return NULL;
-        WMAddToPLArray(item, pomenu);
-        if (data->param.pipe.cached)
-            s1 = wstrconcat("| ", data->param.pipe.command);
-        else
-            s1 = wstrconcat("|| ", data->param.pipe.command);
-        WMAddToPLArray(item, WMCreatePLString(s1));
-        wfree(s1);
-        break;
-
-    case ExternalInfo:
-        if (!data->param.external.path)
-            return NULL;
-        WMAddToPLArray(item, pomenu);
-        WMAddToPLArray(item, WMCreatePLString(data->param.external.path));
-        break;
-
-    case DirectoryInfo:
-        if (!data->param.directory.directory
-            || !data->param.directory.command)
-            return NULL;
-        {
-            int l;
-            char *tmp;
-
-            l = strlen(data->param.directory.directory);
-            l += strlen(data->param.directory.command);
-            l += 32;
-
-            WMAddToPLArray(item, pomenu);
-
-            tmp = wmalloc(l);
-            sprintf(tmp, "%s%s WITH %s",
-                    data->param.directory.stripExt ? "-noext " : "",
-                    data->param.directory.directory,
-                    data->param.directory.command);
-
-            WMAddToPLArray(item, WMCreatePLString(tmp));
-            wfree(tmp);
-        }
-        break;
-
-    case WSMenuInfo:
-        WMAddToPLArray(item, WMCreatePLString("WORKSPACE_MENU"));
-        break;
-
-    case WWindowListInfo:
-        WMAddToPLArray(item, WMCreatePLString("WINDOWS_MENU"));
-        break;
-
-    default:
-        assert(0);
-        break;
-    }
-
-    return item;
-}
-
-
-static WMPropList*
-processSubmenu(WEditMenu *menu)
-{
-    WEditMenuItem *item;
-    WMPropList *pmenu;
-    WMPropList *pl;
-    char *s;
-    int i;
-
-
-    s = WGetEditMenuTitle(menu);
-    pl = WMCreatePLString(s);
-
-    pmenu = WMCreatePLArray(pl, NULL);
-
-    i = 0;
-    while ((item = WGetEditMenuItem(menu, i++))) {
-        WEditMenu *submenu;
-
-        s = WGetEditMenuItemTitle(item);
-
-        submenu = WGetEditMenuSubmenu(menu, item);
-        if (submenu) {
-            pl = processSubmenu(submenu);
-        } else {
-            pl = processData(s, WGetEditMenuItemData(item));
-        }
-
-        if (!pl)
-            continue;
-
-        WMAddToPLArray(pmenu, pl);
-    }
-
-    return pmenu;
-}
-
-
-
-static WMPropList*
-buildPLFromMenu(_Panel *panel)
-{
-    WMPropList *menu;
-
-    menu = processSubmenu(panel->menu);
-
-    return menu;
-}
-
-
-
-
-static void
-storeData(_Panel *panel)
-{
-    WMPropList *menu;
-
-    if (panel->dontSave)
-        return;
-
-    menu = buildPLFromMenu(panel);
-
-    WMWritePropListToFile(menu, panel->menuPath, True);
-
-    WMReleasePropList(menu);
-}
-
-
-
-static void
-showMenus(_Panel *panel)
-{
-    if (panel->menu)
-        WEditMenuUnhide(panel->menu);
-}
-
-
-static void
-hideMenus(_Panel *panel)
-{
-    if (panel->menu)
-        WEditMenuHide(panel->menu);
-}
-
-
-
-
-Panel*
-InitMenu(WMScreen *scr, WMWidget *parent)
-{
-    _Panel *panel;
-
-    panel = wmalloc(sizeof(_Panel));
-    memset(panel, 0, sizeof(_Panel));
-
-    panel->sectionName = _("Applications Menu Definition");
-
-    panel->description = _("Edit the menu for launching applications.");
-
-    panel->parent = parent;
-
-    panel->callbacks.createWidgets = createPanel;
-    panel->callbacks.updateDomain = storeData;
-    panel->callbacks.showPanel = showMenus;
-    panel->callbacks.hidePanel = hideMenus;
-
-
-    AddSection(panel, ICON_FILE);
-
-    return panel;
-}
-
+/* Menu.c- menu definition
+ *
+ *  WPrefs - Window Maker Preferences Program
+ *
+ *  Copyright (c) 2000-2003 Alfredo K. Kojima
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program; if not, write to the Free Software
+ *  Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307,
+ *  USA.
+ */
+
+#include "WPrefs.h"
+#include <assert.h>
+#include <ctype.h>
+
+#include <X11/keysym.h>
+#include <X11/cursorfont.h>
+
+#include "editmenu.h"
+
+typedef enum {
+       NoInfo,
+       ExecInfo,
+       CommandInfo,
+       ExternalInfo,
+       PipeInfo,
+       DirectoryInfo,
+       WSMenuInfo,
+       WWindowListInfo,
+       LastInfo
+} InfoType;
+
+#define MAX_SECTION_SIZE 4
+
+typedef struct _Panel {
+       WMBox *box;
+       char *sectionName;
+
+       char *description;
+
+       CallbackRec callbacks;
+       WMWidget *parent;
+
+       WMFont *boldFont;
+       WMFont *normalFont;
+       WMColor *white;
+       WMColor *gray;
+       WMColor *black;
+
+       WMPixmap *markerPix[LastInfo];
+
+       WMPopUpButton *typeP;
+
+       WMWidget *itemPad[3];
+       int currentPad;
+
+       WEditMenu *menu;
+       char *menuPath;
+
+       WMFrame *optionsF;
+
+       WMFrame *commandF;
+       WMTextField *commandT;  /* command to run */
+       WMButton *browseB;
+       WMButton *xtermC;       /* inside xterm? */
+
+       WMFrame *pathF;
+       WMTextField *pathT;
+
+       WMFrame *pipeF;
+       WMTextField *pipeT;
+       WMButton *pipeCacheB;
+
+       WMFrame *dpathF;
+       WMTextField *dpathT;
+
+       WMFrame *dcommandF;
+       WMTextField *dcommandT;
+
+       WMButton *dstripB;
+
+       WMFrame *shortF;
+       WMTextField *shortT;
+       WMButton *sgrabB;
+       WMButton *sclearB;
+
+       WMList *icommandL;
+
+       WMFrame *paramF;
+       WMTextField *paramT;
+
+       WMButton *quickB;
+
+       Bool dontAsk;           /* whether to comfirm submenu remove */
+       Bool dontSave;
+
+       Bool capturing;
+
+       /* about the currently selected item */
+       WEditMenuItem *currentItem;
+       InfoType currentType;
+       WMWidget *sections[LastInfo][MAX_SECTION_SIZE];
+} _Panel;
+
+typedef struct {
+       InfoType type;
+       union {
+               struct {
+                       int command;
+                       char *parameter;
+                       char *shortcut;
+               } command;
+               struct {
+                       char *command;
+                       char *shortcut;
+               } exec;
+               struct {
+                       char *path;
+               } external;
+               struct {
+                       char *command;
+                       unsigned cached:1;
+               } pipe;
+               struct {
+                       char *directory;
+                       char *command;
+                       unsigned stripExt:1;
+               } directory;
+       } param;
+} ItemData;
+
+static char *commandNames[] = {
+       "ARRANGE_ICONS",
+       "HIDE_OTHERS",
+       "SHOW_ALL",
+       "EXIT",
+       "SHUTDOWN",
+       "RESTART",
+       "RESTART",
+       "SAVE_SESSION",
+       "CLEAR_SESSION",
+       "REFRESH",
+       "INFO_PANEL",
+       "LEGAL_PANEL"
+};
+
+#define NEW(type) memset(wmalloc(sizeof(type)), 0, sizeof(type))
+
+#define ICON_FILE      "menus"
+
+static void showData(_Panel * panel);
+
+static void updateMenuItem(_Panel * panel, WEditMenuItem * item, WMWidget * changedWidget);
+
+static void menuItemSelected(struct WEditMenuDelegate *delegate, WEditMenu * menu, WEditMenuItem * item);
+
+static void menuItemDeselected(struct WEditMenuDelegate *delegate, WEditMenu * menu, WEditMenuItem * item);
+
+static void menuItemCloned(struct WEditMenuDelegate *delegate, WEditMenu * menu,
+                          WEditMenuItem * origItem, WEditMenuItem * newItem);
+
+static void menuItemEdited(struct WEditMenuDelegate *delegate, WEditMenu * menu, WEditMenuItem * item);
+
+static Bool shouldRemoveItem(struct WEditMenuDelegate *delegate, WEditMenu * menu, WEditMenuItem * item);
+
+static void freeItemData(ItemData * data);
+
+static WEditMenuDelegate menuDelegate = {
+       NULL,
+       menuItemCloned,
+       menuItemEdited,
+       menuItemSelected,
+       menuItemDeselected,
+       shouldRemoveItem
+};
+
+static void dataChanged(void *self, WMNotification * notif)
+{
+       _Panel *panel = (_Panel *) self;
+       WEditMenuItem *item = panel->currentItem;
+       WMWidget *w = (WMWidget *) WMGetNotificationObject(notif);
+
+       updateMenuItem(panel, item, w);
+}
+
+static void buttonClicked(WMWidget * w, void *data)
+{
+       _Panel *panel = (_Panel *) data;
+       WEditMenuItem *item = panel->currentItem;
+
+       updateMenuItem(panel, item, w);
+}
+
+static void icommandLClicked(WMWidget * w, void *data)
+{
+       _Panel *panel = (_Panel *) data;
+       int cmd;
+
+       cmd = WMGetListSelectedItemRow(w);
+       if (cmd == 3 || cmd == 4) {
+               WMMapWidget(panel->quickB);
+       } else {
+               WMUnmapWidget(panel->quickB);
+       }
+       if (cmd == 6) {
+               WMMapWidget(panel->paramF);
+       } else {
+               WMUnmapWidget(panel->paramF);
+       }
+}
+
+static void browseForFile(WMWidget * self, void *clientData)
+{
+       _Panel *panel = (_Panel *) clientData;
+       WMFilePanel *filePanel;
+       char *text, *oldprog, *newprog;
+
+       filePanel = WMGetOpenPanel(WMWidgetScreen(self));
+       text = WMGetTextFieldText(panel->commandT);
+
+       oldprog = wtrimspace(text);
+       wfree(text);
+
+       if (oldprog[0] == 0 || oldprog[0] != '/') {
+               wfree(oldprog);
+               oldprog = wstrdup("/");
+       } else {
+               char *ptr = oldprog;
+               while (*ptr && !isspace(*ptr))
+                       ptr++;
+               *ptr = 0;
+       }
+
+       WMSetFilePanelCanChooseDirectories(filePanel, False);
+
+       if (WMRunModalFilePanelForDirectory(filePanel, panel->parent, oldprog, _("Select Program"), NULL) == True) {
+               newprog = WMGetFilePanelFileName(filePanel);
+               WMSetTextFieldText(panel->commandT, newprog);
+               updateMenuItem(panel, panel->currentItem, panel->commandT);
+               wfree(newprog);
+       }
+
+       wfree(oldprog);
+}
+
+static char *captureShortcut(Display * dpy, _Panel * panel)
+{
+       XEvent ev;
+       KeySym ksym;
+       char buffer[64];
+       char *key = NULL;
+
+       while (panel->capturing) {
+               XAllowEvents(dpy, AsyncKeyboard, CurrentTime);
+               WMNextEvent(dpy, &ev);
+               if (ev.type == KeyPress && ev.xkey.keycode != 0) {
+                       ksym = XKeycodeToKeysym(dpy, ev.xkey.keycode, 0);
+                       if (!IsModifierKey(ksym)) {
+                               key = XKeysymToString(ksym);
+                               panel->capturing = 0;
+                               break;
+                       }
+               }
+               WMHandleEvent(&ev);
+       }
+
+       if (!key)
+               return NULL;
+
+       buffer[0] = 0;
+
+       if (ev.xkey.state & ControlMask) {
+               strcat(buffer, "Control+");
+       }
+       if (ev.xkey.state & ShiftMask) {
+               strcat(buffer, "Shift+");
+       }
+       if (ev.xkey.state & Mod1Mask) {
+               strcat(buffer, "Mod1+");
+       }
+       if (ev.xkey.state & Mod2Mask) {
+               strcat(buffer, "Mod2+");
+       }
+       if (ev.xkey.state & Mod3Mask) {
+               strcat(buffer, "Mod3+");
+       }
+       if (ev.xkey.state & Mod4Mask) {
+               strcat(buffer, "Mod4+");
+       }
+       if (ev.xkey.state & Mod5Mask) {
+               strcat(buffer, "Mod5+");
+       }
+       strcat(buffer, key);
+
+       return wstrdup(buffer);
+}
+
+static void sgrabClicked(WMWidget * w, void *data)
+{
+       _Panel *panel = (_Panel *) data;
+       Display *dpy = WMScreenDisplay(WMWidgetScreen(panel->parent));
+       char *shortcut;
+
+       if (w == panel->sclearB) {
+               WMSetTextFieldText(panel->shortT, "");
+               updateMenuItem(panel, panel->currentItem, panel->shortT);
+               return;
+       }
+
+       if (!panel->capturing) {
+               panel->capturing = 1;
+               WMSetButtonText(w, _("Cancel"));
+               XGrabKeyboard(dpy, WMWidgetXID(panel->parent), True, GrabModeAsync, GrabModeAsync, CurrentTime);
+               shortcut = captureShortcut(dpy, panel);
+               if (shortcut) {
+                       WMSetTextFieldText(panel->shortT, shortcut);
+                       updateMenuItem(panel, panel->currentItem, panel->shortT);
+                       wfree(shortcut);
+               }
+       }
+       panel->capturing = 0;
+       WMSetButtonText(w, _("Capture"));
+       XUngrabKeyboard(dpy, CurrentTime);
+}
+
+static void changedItemPad(WMWidget * w, void *data)
+{
+       _Panel *panel = (_Panel *) data;
+       int padn = WMGetPopUpButtonSelectedItem(w);
+
+       WMUnmapWidget(panel->itemPad[panel->currentPad]);
+       WMMapWidget(panel->itemPad[padn]);
+
+       panel->currentPad = padn;
+}
+
+static WEditMenu *putNewSubmenu(WEditMenu * menu, char *title)
+{
+       WEditMenu *tmp;
+       WEditMenuItem *item;
+
+       item = WAddMenuItemWithTitle(menu, title);
+
+       tmp = WCreateEditMenu(WMWidgetScreen(menu), title);
+       WSetEditMenuAcceptsDrop(tmp, True);
+       WSetEditMenuDelegate(tmp, &menuDelegate);
+       WSetEditMenuSubmenu(menu, item, tmp);
+
+       return tmp;
+}
+
+static ItemData *putNewItem(_Panel * panel, WEditMenu * menu, int type, char *title)
+{
+       WEditMenuItem *item;
+       ItemData *data;
+
+       item = WAddMenuItemWithTitle(menu, title);
+
+       data = NEW(ItemData);
+       data->type = type;
+       WSetEditMenuItemData(item, data, (WMCallback *) freeItemData);
+       WSetEditMenuItemImage(item, panel->markerPix[type]);
+
+       return data;
+}
+
+static WEditMenu *makeFactoryMenu(WMWidget * parent, int width)
+{
+       WEditMenu *pad;
+
+       pad = WCreateEditMenuPad(parent);
+       WMResizeWidget(pad, width, 10);
+       WSetEditMenuMinSize(pad, wmksize(width, 0));
+       WSetEditMenuMaxSize(pad, wmksize(width, 0));
+       WSetEditMenuSelectable(pad, False);
+       WSetEditMenuEditable(pad, False);
+       WSetEditMenuIsFactory(pad, True);
+       WSetEditMenuDelegate(pad, &menuDelegate);
+
+       return pad;
+}
+
+static void createPanel(_Panel * p)
+{
+       _Panel *panel = (_Panel *) p;
+       WMScreen *scr = WMWidgetScreen(panel->parent);
+       WMColor *black = WMBlackColor(scr);
+       WMColor *white = WMWhiteColor(scr);
+       WMColor *gray = WMGrayColor(scr);
+       WMFont *bold = WMBoldSystemFontOfSize(scr, 12);
+       WMFont *font = WMSystemFontOfSize(scr, 12);
+       WMLabel *label;
+       int width;
+
+       menuDelegate.data = panel;
+
+       panel->boldFont = bold;
+       panel->normalFont = font;
+
+       panel->black = black;
+       panel->white = white;
+       panel->gray = gray;
+
+       {
+               Pixmap pix;
+               Display *dpy = WMScreenDisplay(scr);
+               GC gc;
+               WMPixmap *pixm;
+
+               pixm = WMCreatePixmap(scr, 7, 7, WMScreenDepth(scr), True);
+
+               pix = WMGetPixmapXID(pixm);
+
+               XDrawLine(dpy, pix, WMColorGC(black), 0, 3, 6, 3);
+               XDrawLine(dpy, pix, WMColorGC(black), 3, 0, 3, 6);
+               /*
+                  XDrawLine(dpy, pix, WMColorGC(black), 1, 0, 3, 3);
+                  XDrawLine(dpy, pix, WMColorGC(black), 1, 6, 3, 3);
+                  XDrawLine(dpy, pix, WMColorGC(black), 0, 0, 0, 6);
+                */
+
+               pix = WMGetPixmapMaskXID(pixm);
+
+               gc = XCreateGC(dpy, pix, 0, NULL);
+
+               XSetForeground(dpy, gc, 0);
+               XFillRectangle(dpy, pix, gc, 0, 0, 7, 7);
+
+               XSetForeground(dpy, gc, 1);
+               XDrawLine(dpy, pix, gc, 0, 3, 6, 3);
+               XDrawLine(dpy, pix, gc, 3, 0, 3, 6);
+
+               panel->markerPix[ExternalInfo] = pixm;
+               panel->markerPix[PipeInfo] = pixm;
+               panel->markerPix[DirectoryInfo] = pixm;
+               panel->markerPix[WSMenuInfo] = pixm;
+               panel->markerPix[WWindowListInfo] = pixm;
+
+               XFreeGC(dpy, gc);
+       }
+
+       panel->box = WMCreateBox(panel->parent);
+       WMSetViewExpandsToParent(WMWidgetView(panel->box), 2, 2, 2, 2);
+
+       panel->typeP = WMCreatePopUpButton(panel->box);
+       WMResizeWidget(panel->typeP, 150, 20);
+       WMMoveWidget(panel->typeP, 10, 10);
+
+       WMAddPopUpButtonItem(panel->typeP, _("New Items"));
+       WMAddPopUpButtonItem(panel->typeP, _("Sample Commands"));
+       WMAddPopUpButtonItem(panel->typeP, _("Sample Submenus"));
+
+       WMSetPopUpButtonAction(panel->typeP, changedItemPad, panel);
+
+       WMSetPopUpButtonSelectedItem(panel->typeP, 0);
+
+       {
+               WEditMenu *pad;
+               WEditMenu *smenu;
+               ItemData *data;
+
+               pad = makeFactoryMenu(panel->box, 150);
+               WMMoveWidget(pad, 10, 40);
+
+               data = putNewItem(panel, pad, ExecInfo, _("Run Program"));
+               data = putNewItem(panel, pad, CommandInfo, _("Internal Command"));
+               smenu = putNewSubmenu(pad, _("Submenu"));
+               data = putNewItem(panel, pad, ExternalInfo, _("External Submenu"));
+               data = putNewItem(panel, pad, PipeInfo, _("Generated Submenu"));
+               data = putNewItem(panel, pad, DirectoryInfo, _("Directory Contents"));
+               data = putNewItem(panel, pad, WSMenuInfo, _("Workspace Menu"));
+               data = putNewItem(panel, pad, WWindowListInfo, _("Window List Menu"));
+
+               panel->itemPad[0] = pad;
+       }
+
+       {
+               WEditMenu *pad;
+               ItemData *data;
+               WMScrollView *sview;
+
+               sview = WMCreateScrollView(panel->box);
+               WMResizeWidget(sview, 150, 180);
+               WMMoveWidget(sview, 10, 40);
+               WMSetScrollViewHasVerticalScroller(sview, True);
+
+               pad = makeFactoryMenu(panel->box, 130);
+
+               WMSetScrollViewContentView(sview, WMWidgetView(pad));
+
+               data = putNewItem(panel, pad, ExecInfo, _("XTerm"));
+               data->param.exec.command = "xterm -sb -sl 2000 -bg black -fg white";
+
+               data = putNewItem(panel, pad, ExecInfo, _("rxvt"));
+               data->param.exec.command = "rxvt";
+
+               data = putNewItem(panel, pad, ExecInfo, _("ETerm"));
+               data->param.exec.command = "eterm";
+
+               data = putNewItem(panel, pad, ExecInfo, _("Run..."));
+               data->param.exec.command = _("%a(Run,Type command to run)");
+
+               data = putNewItem(panel, pad, ExecInfo, _("Netscape"));
+               data->param.exec.command = "netscape";
+
+               data = putNewItem(panel, pad, ExecInfo, _("gimp"));
+               data->param.exec.command = "gimp";
+
+               data = putNewItem(panel, pad, ExecInfo, _("epic"));
+               data->param.exec.command = "xterm -e epic";
+
+               data = putNewItem(panel, pad, ExecInfo, _("ee"));
+               data->param.exec.command = "ee";
+
+               data = putNewItem(panel, pad, ExecInfo, _("xv"));
+               data->param.exec.command = "xv";
+
+               data = putNewItem(panel, pad, ExecInfo, _("Acrobat Reader"));
+               data->param.exec.command = "acroread || /usr/local/Acrobat4/bin/acroread";
+
+               data = putNewItem(panel, pad, ExecInfo, _("ghostview"));
+               data->param.exec.command = "gv";
+
+               data = putNewItem(panel, pad, CommandInfo, _("Exit Window Maker"));
+               data->param.command.command = 3;
+
+               WMMapWidget(pad);
+
+               panel->itemPad[1] = sview;
+       }
+
+       {
+               WEditMenu *pad, *smenu;
+               ItemData *data;
+               WMScrollView *sview;
+
+               sview = WMCreateScrollView(panel->box);
+               WMResizeWidget(sview, 150, 180);
+               WMMoveWidget(sview, 10, 40);
+               WMSetScrollViewHasVerticalScroller(sview, True);
+
+               pad = makeFactoryMenu(panel->box, 130);
+
+               WMSetScrollViewContentView(sview, WMWidgetView(pad));
+
+               data = putNewItem(panel, pad, ExternalInfo, _("Debian Menu"));
+               data->param.pipe.command = "/etc/X11/WindowMaker/menu.hook";
+
+               data = putNewItem(panel, pad, PipeInfo, _("RedHat Menu"));
+               data->param.pipe.command = "wmconfig --output wmaker";
+
+               data = putNewItem(panel, pad, PipeInfo, _("Menu Conectiva"));
+               data->param.pipe.command = "wmconfig --output wmaker";
+
+               data = putNewItem(panel, pad, DirectoryInfo, _("Themes"));
+               data->param.directory.command = "setstyle";
+               data->param.directory.directory =
+                   "/usr/share/WindowMaker/Themes /usr/local/share/WindowMaker/Themes $HOME/GNUstep/Library/WindowMaker/Themes";
+               data->param.directory.stripExt = 1;
+
+               data = putNewItem(panel, pad, DirectoryInfo, _("Bg Images (scale)"));
+               data->param.directory.command = "wmsetbg -u -s";
+               data->param.directory.directory =
+                   "/opt/kde2/share/wallpapers /usr/share/WindowMaker/Backgrounds $HOME/GNUstep/Library/WindowMaker/Backgrounds";
+               data->param.directory.stripExt = 1;
+
+               data = putNewItem(panel, pad, DirectoryInfo, _("Bg Images (tile)"));
+               data->param.directory.command = "wmsetbg -u -t";
+               data->param.directory.directory =
+                   "/opt/kde2/share/wallpapers /usr/share/WindowMaker/Backgrounds $HOME/GNUstep/Library/WindowMaker/Backgrounds";
+               data->param.directory.stripExt = 1;
+
+               smenu = putNewSubmenu(pad, _("Assorted XTerms"));
+
+               data = putNewItem(panel, smenu, ExecInfo, _("XTerm Yellow on Blue"));
+               data->param.exec.command = "xterm -sb -sl 2000 -bg midnightblue -fg yellow";
+
+               data = putNewItem(panel, smenu, ExecInfo, _("XTerm White on Black"));
+               data->param.exec.command = "xterm -sb -sl 2000 -bg black -fg white";
+
+               data = putNewItem(panel, smenu, ExecInfo, _("XTerm Black on White"));
+               data->param.exec.command = "xterm -sb -sl 2000 -bg white -fg black";
+
+               data = putNewItem(panel, smenu, ExecInfo, _("XTerm Black on Beige"));
+               data->param.exec.command = "xterm -sb -sl 2000 -bg '#bbbb99' -fg black";
+
+               data = putNewItem(panel, smenu, ExecInfo, _("XTerm White on Green"));
+               data->param.exec.command = "xterm -sb -sl 2000 -bg '#228822' -fg white";
+
+               data = putNewItem(panel, smenu, ExecInfo, _("XTerm White on Olive"));
+               data->param.exec.command = "xterm -sb -sl 2000 -bg '#335533' -fg white";
+
+               data = putNewItem(panel, smenu, ExecInfo, _("XTerm Blue on Blue"));
+               data->param.exec.command = "xterm -sb -sl 2000 -bg '#112244' -fg '#88aabb'";
+
+               data = putNewItem(panel, smenu, ExecInfo, _("XTerm BIG FONTS"));
+               data->param.exec.command = "xterm -sb -sl 2000 -bg black -fg white -fn 10x20";
+
+               WMMapWidget(pad);
+
+               panel->itemPad[2] = sview;
+       }
+
+       width = FRAME_WIDTH - 20 - 150 - 10 - 2;
+
+       panel->optionsF = WMCreateFrame(panel->box);
+       WMResizeWidget(panel->optionsF, width, FRAME_HEIGHT - 15);
+       WMMoveWidget(panel->optionsF, 10 + 150 + 10, 5);
+
+       width -= 20;
+
+       /* command */
+
+       panel->commandF = WMCreateFrame(panel->optionsF);
+       WMResizeWidget(panel->commandF, width, 50);
+       WMMoveWidget(panel->commandF, 10, 20);
+       WMSetFrameTitle(panel->commandF, _("Program to Run"));
+       WMSetFrameTitlePosition(panel->commandF, WTPAtTop);
+
+       panel->commandT = WMCreateTextField(panel->commandF);
+       WMResizeWidget(panel->commandT, width - 95, 20);
+       WMMoveWidget(panel->commandT, 10, 20);
+
+       panel->browseB = WMCreateCommandButton(panel->commandF);
+       WMResizeWidget(panel->browseB, 70, 24);
+       WMMoveWidget(panel->browseB, width - 80, 18);
+       WMSetButtonText(panel->browseB, _("Browse"));
+       WMSetButtonAction(panel->browseB, browseForFile, panel);
+
+       WMAddNotificationObserver(dataChanged, panel, WMTextDidChangeNotification, panel->commandT);
+
+#if 0
+       panel->xtermC = WMCreateSwitchButton(panel->commandF);
+       WMResizeWidget(panel->xtermC, width - 20, 20);
+       WMMoveWidget(panel->xtermC, 10, 50);
+       WMSetButtonText(panel->xtermC, _("Run the program inside a Xterm"));
+#endif
+       WMMapSubwidgets(panel->commandF);
+
+       /* path */
+
+       panel->pathF = WMCreateFrame(panel->optionsF);
+       WMResizeWidget(panel->pathF, width, 150);
+       WMMoveWidget(panel->pathF, 10, 40);
+       WMSetFrameTitle(panel->pathF, _("Path for Menu"));
+
+       panel->pathT = WMCreateTextField(panel->pathF);
+       WMResizeWidget(panel->pathT, width - 20, 20);
+       WMMoveWidget(panel->pathT, 10, 20);
+
+       WMAddNotificationObserver(dataChanged, panel, WMTextDidChangeNotification, panel->pathT);
+
+       label = WMCreateLabel(panel->pathF);
+       WMResizeWidget(label, width - 20, 80);
+       WMMoveWidget(label, 10, 50);
+       WMSetLabelText(label, _("Enter the path for a file containing a menu\n"
+                               "or a list of directories with the programs you\n"
+                               "want to have listed in the menu. Ex:\n"
+                               "~/GNUstep/Library/WindowMaker/menu\n" "or\n" "/usr/X11R6/bin ~/xbin"));
+
+       WMMapSubwidgets(panel->pathF);
+
+       /* pipe */
+
+       panel->pipeF = WMCreateFrame(panel->optionsF);
+       WMResizeWidget(panel->pipeF, width, 155);
+       WMMoveWidget(panel->pipeF, 10, 30);
+       WMSetFrameTitle(panel->pipeF, _("Command"));
+
+       panel->pipeT = WMCreateTextField(panel->pipeF);
+       WMResizeWidget(panel->pipeT, width - 20, 20);
+       WMMoveWidget(panel->pipeT, 10, 20);
+
+       WMAddNotificationObserver(dataChanged, panel, WMTextDidChangeNotification, panel->pipeT);
+
+       label = WMCreateLabel(panel->pipeF);
+       WMResizeWidget(label, width - 20, 40);
+       WMMoveWidget(label, 10, 50);
+       WMSetLabelText(label, _("Enter a command that outputs a menu\n" "definition to stdout when invoked."));
+
+       panel->pipeCacheB = WMCreateSwitchButton(panel->pipeF);
+       WMResizeWidget(panel->pipeCacheB, width - 20, 40);
+       WMMoveWidget(panel->pipeCacheB, 10, 110);
+       WMSetButtonText(panel->pipeCacheB, _("Cache menu contents after opening for\n" "the first time"));
+
+       WMMapSubwidgets(panel->pipeF);
+
+       /* directory menu */
+
+       panel->dcommandF = WMCreateFrame(panel->optionsF);
+       WMResizeWidget(panel->dcommandF, width, 90);
+       WMMoveWidget(panel->dcommandF, 10, 25);
+       WMSetFrameTitle(panel->dcommandF, _("Command to Open Files"));
+
+       panel->dcommandT = WMCreateTextField(panel->dcommandF);
+       WMResizeWidget(panel->dcommandT, width - 20, 20);
+       WMMoveWidget(panel->dcommandT, 10, 20);
+
+       WMAddNotificationObserver(dataChanged, panel, WMTextDidChangeNotification, panel->dcommandT);
+
+       label = WMCreateLabel(panel->dcommandF);
+       WMResizeWidget(label, width - 20, 45);
+       WMMoveWidget(label, 10, 40);
+       WMSetLabelText(label, _("Enter the command you want to use to open the\n"
+                               "files in the directories listed below."));
+
+       WMMapSubwidgets(panel->dcommandF);
+
+       panel->dpathF = WMCreateFrame(panel->optionsF);
+       WMResizeWidget(panel->dpathF, width, 80);
+       WMMoveWidget(panel->dpathF, 10, 125);
+       WMSetFrameTitle(panel->dpathF, _("Directories with Files"));
+
+       panel->dpathT = WMCreateTextField(panel->dpathF);
+       WMResizeWidget(panel->dpathT, width - 20, 20);
+       WMMoveWidget(panel->dpathT, 10, 20);
+
+       WMAddNotificationObserver(dataChanged, panel, WMTextDidChangeNotification, panel->dpathT);
+
+       panel->dstripB = WMCreateSwitchButton(panel->dpathF);
+       WMResizeWidget(panel->dstripB, width - 20, 20);
+       WMMoveWidget(panel->dstripB, 10, 50);
+       WMSetButtonText(panel->dstripB, _("Strip extensions from file names"));
+
+       WMSetButtonAction(panel->dstripB, buttonClicked, panel);
+
+       WMMapSubwidgets(panel->dpathF);
+
+       /* shortcut */
+
+       panel->shortF = WMCreateFrame(panel->optionsF);
+       WMResizeWidget(panel->shortF, width, 50);
+       WMMoveWidget(panel->shortF, 10, 160);
+       WMSetFrameTitle(panel->shortF, _("Keyboard Shortcut"));
+
+       panel->shortT = WMCreateTextField(panel->shortF);
+       WMResizeWidget(panel->shortT, width - 20 - 150, 20);
+       WMMoveWidget(panel->shortT, 10, 20);
+
+       WMAddNotificationObserver(dataChanged, panel, WMTextDidChangeNotification, panel->shortT);
+
+       panel->sgrabB = WMCreateCommandButton(panel->shortF);
+       WMResizeWidget(panel->sgrabB, 70, 24);
+       WMMoveWidget(panel->sgrabB, width - 80, 18);
+       WMSetButtonText(panel->sgrabB, _("Capture"));
+       WMSetButtonAction(panel->sgrabB, sgrabClicked, panel);
+
+       panel->sclearB = WMCreateCommandButton(panel->shortF);
+       WMResizeWidget(panel->sclearB, 70, 24);
+       WMMoveWidget(panel->sclearB, width - 155, 18);
+       WMSetButtonText(panel->sclearB, _("Clear"));
+       WMSetButtonAction(panel->sclearB, sgrabClicked, panel);
+
+       WMMapSubwidgets(panel->shortF);
+
+       /* internal command */
+
+       panel->icommandL = WMCreateList(panel->optionsF);
+       WMResizeWidget(panel->icommandL, width, 80);
+       WMMoveWidget(panel->icommandL, 10, 20);
+
+       WMSetListAction(panel->icommandL, icommandLClicked, panel);
+
+       WMAddNotificationObserver(dataChanged, panel, WMListSelectionDidChangeNotification, panel->icommandL);
+
+       WMInsertListItem(panel->icommandL, 0, _("Arrange Icons"));
+       WMInsertListItem(panel->icommandL, 1, _("Hide All Windows Except For The Focused One"));
+       WMInsertListItem(panel->icommandL, 2, _("Show All Windows"));
+
+       WMInsertListItem(panel->icommandL, 3, _("Exit Window Maker"));
+       WMInsertListItem(panel->icommandL, 4, _("Exit X Session"));
+       WMInsertListItem(panel->icommandL, 5, _("Restart Window Maker"));
+       WMInsertListItem(panel->icommandL, 6, _("Start Another Window Manager   : ("));
+
+       WMInsertListItem(panel->icommandL, 7, _("Save Current Session"));
+       WMInsertListItem(panel->icommandL, 8, _("Clear Saved Session"));
+       WMInsertListItem(panel->icommandL, 9, _("Refresh Screen"));
+       WMInsertListItem(panel->icommandL, 10, _("Open Info Panel"));
+       WMInsertListItem(panel->icommandL, 11, _("Open Copyright Panel"));
+
+       panel->paramF = WMCreateFrame(panel->optionsF);
+       WMResizeWidget(panel->paramF, width, 50);
+       WMMoveWidget(panel->paramF, 10, 105);
+       WMSetFrameTitle(panel->paramF, _("Window Manager to Start"));
+
+       panel->paramT = WMCreateTextField(panel->paramF);
+       WMResizeWidget(panel->paramT, width - 20, 20);
+       WMMoveWidget(panel->paramT, 10, 20);
+
+       WMAddNotificationObserver(dataChanged, panel, WMTextDidChangeNotification, panel->paramT);
+
+       WMMapSubwidgets(panel->paramF);
+
+       panel->quickB = WMCreateSwitchButton(panel->optionsF);
+       WMResizeWidget(panel->quickB, width, 20);
+       WMMoveWidget(panel->quickB, 10, 120);
+       WMSetButtonText(panel->quickB, _("Do not confirm action."));
+       WMSetButtonAction(panel->quickB, buttonClicked, panel);
+
+       label = WMCreateLabel(panel->optionsF);
+       WMResizeWidget(label, width + 5, FRAME_HEIGHT - 50);
+       WMMoveWidget(label, 7, 20);
+       WMSetLabelText(label,
+                      _("Instructions:\n\n"
+                        " - drag items from the left to the menu to add new items\n"
+                        " - drag items out of the menu to remove items\n"
+                        " - drag items in menu to change their position\n"
+                        " - drag items with Control pressed to copy them\n"
+                        " - double click in a menu item to change the label\n"
+                        " - click on a menu item to change related information"));
+       WMMapWidget(label);
+
+       WMRealizeWidget(panel->box);
+       WMMapSubwidgets(panel->box);
+       WMMapWidget(panel->box);
+
+       {
+               int i;
+               for (i = 0; i < 3; i++)
+                       WMUnmapWidget(panel->itemPad[i]);
+       }
+       changedItemPad(panel->typeP, panel);
+
+       panel->sections[NoInfo][0] = label;
+
+       panel->sections[ExecInfo][0] = panel->commandF;
+       panel->sections[ExecInfo][1] = panel->shortF;
+
+       panel->sections[CommandInfo][0] = panel->icommandL;
+       panel->sections[CommandInfo][1] = panel->shortF;
+
+       panel->sections[ExternalInfo][0] = panel->pathF;
+
+       panel->sections[PipeInfo][0] = panel->pipeF;
+
+       panel->sections[DirectoryInfo][0] = panel->dpathF;
+       panel->sections[DirectoryInfo][1] = panel->dcommandF;
+
+       panel->currentType = NoInfo;
+
+       showData(panel);
+
+       {
+               WMPoint pos;
+
+               pos = WMGetViewScreenPosition(WMWidgetView(panel->box));
+
+               if (pos.x < 200) {
+                       pos.x += FRAME_WIDTH + 20;
+               } else {
+                       pos.x = 10;
+               }
+
+               pos.y = WMAX(pos.y - 100, 0);
+
+               if (panel->menu)
+                       WEditMenuShowAt(panel->menu, pos.x, pos.y);
+       }
+}
+
+static void freeItemData(ItemData * data)
+{
+#define CFREE(d) if (d) wfree(d)
+
+       /* TODO */
+       switch (data->type) {
+       case CommandInfo:
+               CFREE(data->param.command.parameter);
+               CFREE(data->param.command.shortcut);
+               break;
+
+       case ExecInfo:
+               CFREE(data->param.exec.command);
+               CFREE(data->param.exec.shortcut);
+               break;
+
+       case PipeInfo:
+               CFREE(data->param.pipe.command);
+               break;
+
+       case ExternalInfo:
+               CFREE(data->param.external.path);
+               break;
+
+       case DirectoryInfo:
+               CFREE(data->param.directory.command);
+               CFREE(data->param.directory.directory);
+               break;
+
+       default:
+               break;
+       }
+
+       wfree(data);
+#undef CFREE
+}
+
+static ItemData *parseCommand(WMPropList * item)
+{
+       ItemData *data = NEW(ItemData);
+       WMPropList *p;
+       char *command = NULL;
+       char *parameter = NULL;
+       char *shortcut = NULL;
+       int i = 1;
+
+       p = WMGetFromPLArray(item, i++);
+       command = WMGetFromPLString(p);
+       if (strcmp(command, "SHORTCUT") == 0) {
+               p = WMGetFromPLArray(item, i++);
+               shortcut = WMGetFromPLString(p);
+               p = WMGetFromPLArray(item, i++);
+               command = WMGetFromPLString(p);
+       }
+       p = WMGetFromPLArray(item, i++);
+       if (p)
+               parameter = WMGetFromPLString(p);
+
+       if (strcmp(command, "EXEC") == 0 || strcmp(command, "SHEXEC") == 0) {
+
+               data->type = ExecInfo;
+
+               data->param.exec.command = wstrdup(parameter);
+               if (shortcut)
+                       data->param.exec.shortcut = wstrdup(shortcut);
+
+       } else if (strcmp(command, "OPEN_MENU") == 0) {
+               char *p;
+               /*
+                * dir menu, menu file
+                * dir WITH
+                * |pipe
+                */
+               p = parameter;
+               while (isspace(*p) && *p)
+                       p++;
+               if (*p == '|') {
+                       if (*(p + 1) == '|') {
+                               p++;
+                               data->param.pipe.cached = 0;
+                       } else {
+                               data->param.pipe.cached = 1;
+                       }
+                       data->type = PipeInfo;
+                       data->param.pipe.command = wtrimspace(p + 1);
+               } else {
+                       char *s;
+
+                       p = wstrdup(p);
+
+                       s = strstr(p, "WITH");
+                       if (s) {
+                               char **tokens;
+                               char **ctokens;
+                               int tokn;
+                               int i, j;
+
+                               data->type = DirectoryInfo;
+
+                               *s = '\0';
+                               s += 5;
+                               while (*s && isspace(*s))
+                                       s++;
+                               data->param.directory.command = wstrdup(s);
+
+                               wtokensplit(p, &tokens, &tokn);
+                               wfree(p);
+
+                               ctokens = wmalloc(sizeof(char *) * tokn);
+
+                               for (i = 0, j = 0; i < tokn; i++) {
+                                       if (strcmp(tokens[i], "-noext") == 0) {
+                                               wfree(tokens[i]);
+                                               data->param.directory.stripExt = 1;
+                                       } else {
+                                               ctokens[j++] = tokens[i];
+                                       }
+                               }
+                               data->param.directory.directory = wtokenjoin(ctokens, j);
+                               wfree(ctokens);
+
+                               wtokenfree(tokens, tokn);
+                       } else {
+                               data->type = ExternalInfo;
+                               data->param.external.path = p;
+                       }
+               }
+       } else if (strcmp(command, "WORKSPACE_MENU") == 0) {
+               data->type = WSMenuInfo;
+       } else if (strcmp(command, "WINDOWS_MENU") == 0) {
+               data->type = WWindowListInfo;
+       } else {
+               int cmd;
+
+               if (strcmp(command, "ARRANGE_ICONS") == 0) {
+                       cmd = 0;
+               } else if (strcmp(command, "HIDE_OTHERS") == 0) {
+                       cmd = 1;
+               } else if (strcmp(command, "SHOW_ALL") == 0) {
+                       cmd = 2;
+               } else if (strcmp(command, "EXIT") == 0) {
+                       cmd = 3;
+               } else if (strcmp(command, "SHUTDOWN") == 0) {
+                       cmd = 4;
+               } else if (strcmp(command, "RESTART") == 0) {
+                       if (parameter) {
+                               cmd = 6;
+                       } else {
+                               cmd = 5;
+                       }
+               } else if (strcmp(command, "SAVE_SESSION") == 0) {
+                       cmd = 7;
+               } else if (strcmp(command, "CLEAR_SESSION") == 0) {
+                       cmd = 8;
+               } else if (strcmp(command, "REFRESH") == 0) {
+                       cmd = 9;
+               } else if (strcmp(command, "INFO_PANEL") == 0) {
+                       cmd = 10;
+               } else if (strcmp(command, "LEGAL_PANEL") == 0) {
+                       cmd = 11;
+               } else {
+                       wwarning(_("unknown command '%s' in menu"), command);
+                       goto error;
+               }
+
+               data->type = CommandInfo;
+
+               data->param.command.command = cmd;
+               if (shortcut)
+                       data->param.command.shortcut = wstrdup(shortcut);
+               if (parameter)
+                       data->param.command.parameter = wstrdup(parameter);
+       }
+
+       return data;
+
+ error:
+       wfree(data);
+
+       return NULL;
+}
+
+static void updateFrameTitle(_Panel * panel, char *title, InfoType type)
+{
+       if (type != NoInfo) {
+               char *tmp;
+
+               switch (type) {
+               case ExecInfo:
+                       tmp = wstrconcat(title, _(": Execute Program"));
+                       break;
+
+               case CommandInfo:
+                       tmp = wstrconcat(title, _(": Perform Internal Command"));
+                       break;
+
+               case ExternalInfo:
+                       tmp = wstrconcat(title, _(": Open a Submenu"));
+                       break;
+
+               case PipeInfo:
+                       tmp = wstrconcat(title, _(": Program Generated Submenu"));
+                       break;
+
+               case DirectoryInfo:
+                       tmp = wstrconcat(title, _(": Directory Contents Menu"));
+                       break;
+
+               case WSMenuInfo:
+                       tmp = wstrconcat(title, _(": Open Workspaces Submenu"));
+                       break;
+
+               case WWindowListInfo:
+                       tmp = wstrconcat(title, _(": Open Window List Submenu"));
+                       break;
+
+               default:
+                       tmp = NULL;
+                       break;
+               }
+               WMSetFrameTitle(panel->optionsF, tmp);
+               wfree(tmp);
+       } else {
+               WMSetFrameTitle(panel->optionsF, NULL);
+       }
+}
+
+static void changeInfoType(_Panel * panel, char *title, InfoType type)
+{
+       WMWidget **w;
+
+       if (panel->currentType != type) {
+
+               w = panel->sections[panel->currentType];
+
+               while (*w) {
+                       WMUnmapWidget(*w);
+                       w++;
+               }
+               WMUnmapWidget(panel->paramF);
+               WMUnmapWidget(panel->quickB);
+
+               w = panel->sections[type];
+
+               while (*w) {
+                       WMMapWidget(*w);
+                       w++;
+               }
+       }
+
+       updateFrameTitle(panel, title, type);
+
+       panel->currentType = type;
+}
+
+static void updateMenuItem(_Panel * panel, WEditMenuItem * item, WMWidget * changedWidget)
+{
+       ItemData *data = WGetEditMenuItemData(item);
+
+       assert(data != NULL);
+
+#define REPLACE(v, d) if (v) wfree(v); v = d
+
+       switch (data->type) {
+       case ExecInfo:
+               if (changedWidget == panel->commandT) {
+                       REPLACE(data->param.exec.command, WMGetTextFieldText(panel->commandT));
+               }
+               if (changedWidget == panel->shortT) {
+                       REPLACE(data->param.exec.shortcut, WMGetTextFieldText(panel->shortT));
+               }
+               break;
+
+       case CommandInfo:
+               if (changedWidget == panel->icommandL) {
+                       data->param.command.command = WMGetListSelectedItemRow(panel->icommandL);
+               }
+               switch (data->param.command.command) {
+               case 3:
+               case 4:
+                       if (changedWidget == panel->quickB) {
+                               REPLACE(data->param.command.parameter, WMGetButtonSelected(panel->quickB)
+                                       ? wstrdup("QUICK") : NULL);
+                       }
+                       break;
+
+               case 6:
+                       if (changedWidget == panel->paramT) {
+                               REPLACE(data->param.command.parameter, WMGetTextFieldText(panel->paramT));
+                       }
+                       break;
+               }
+               if (changedWidget == panel->shortT) {
+                       REPLACE(data->param.command.shortcut, WMGetTextFieldText(panel->shortT));
+               }
+
+               break;
+
+       case PipeInfo:
+               if (changedWidget == panel->pipeT) {
+                       REPLACE(data->param.pipe.command, WMGetTextFieldText(panel->pipeT));
+               }
+               if (changedWidget == panel->pipeCacheB) {
+                       data->param.pipe.cached = WMGetButtonSelected(panel->pipeCacheB);
+               }
+               break;
+
+       case ExternalInfo:
+               if (changedWidget == panel->pathT) {
+                       REPLACE(data->param.external.path, WMGetTextFieldText(panel->pathT));
+               }
+               break;
+
+       case DirectoryInfo:
+               if (changedWidget == panel->dpathT) {
+                       REPLACE(data->param.directory.directory, WMGetTextFieldText(panel->dpathT));
+               }
+               if (changedWidget == panel->dcommandT) {
+                       REPLACE(data->param.directory.command, WMGetTextFieldText(panel->dcommandT));
+               }
+               if (changedWidget == panel->dstripB) {
+                       data->param.directory.stripExt = WMGetButtonSelected(panel->dstripB);
+               }
+               break;
+
+       default:
+               assert(0);
+               break;
+       }
+
+#undef REPLACE
+}
+
+static void
+menuItemCloned(WEditMenuDelegate * delegate, WEditMenu * menu, WEditMenuItem * origItem, WEditMenuItem * newItem)
+{
+       ItemData *data = WGetEditMenuItemData(origItem);
+       ItemData *newData;
+
+       if (!data)
+               return;
+
+#define DUP(s) (s) ? wstrdup(s) : NULL
+
+       newData = NEW(ItemData);
+
+       newData->type = data->type;
+
+       switch (data->type) {
+       case ExecInfo:
+               newData->param.exec.command = DUP(data->param.exec.command);
+               newData->param.exec.shortcut = DUP(data->param.exec.shortcut);
+               break;
+
+       case CommandInfo:
+               newData->param.command.command = data->param.command.command;
+               newData->param.command.parameter = DUP(data->param.command.parameter);
+               newData->param.command.shortcut = DUP(data->param.command.shortcut);
+               break;
+
+       case PipeInfo:
+               newData->param.pipe.command = DUP(data->param.pipe.command);
+               newData->param.pipe.cached = data->param.pipe.cached;
+               break;
+
+       case ExternalInfo:
+               newData->param.external.path = DUP(data->param.external.path);
+               break;
+
+       case DirectoryInfo:
+               newData->param.directory.directory = DUP(data->param.directory.directory);
+               newData->param.directory.command = DUP(data->param.directory.command);
+               newData->param.directory.stripExt = data->param.directory.stripExt;
+               break;
+
+       default:
+               break;
+       }
+
+#undef DUP
+
+       WSetEditMenuItemData(newItem, newData, (WMCallback *) freeItemData);
+}
+
+static void menuItemEdited(struct WEditMenuDelegate *delegate, WEditMenu * menu, WEditMenuItem * item)
+{
+       _Panel *panel = (_Panel *) delegate->data;
+       WEditMenu *submenu;
+
+       updateFrameTitle(panel, WGetEditMenuItemTitle(item), panel->currentType);
+
+       submenu = WGetEditMenuSubmenu(menu, item);
+       if (submenu) {
+               WSetEditMenuTitle(submenu, WGetEditMenuItemTitle(item));
+       }
+}
+
+static Bool shouldRemoveItem(struct WEditMenuDelegate *delegate, WEditMenu * menu, WEditMenuItem * item)
+{
+       _Panel *panel = (_Panel *) delegate->data;
+
+       if (panel->dontAsk)
+               return True;
+
+       if (WGetEditMenuSubmenu(menu, item)) {
+               int res;
+
+               res = WMRunAlertPanel(WMWidgetScreen(menu), NULL,
+                                     _("Remove Submenu"),
+                                     _("Removing this item will destroy all items inside\n"
+                                       "the submenu. Do you really want to do that?"),
+                                     _("Yes"), _("No"), _("Yes, don't ask again."));
+               switch (res) {
+               case WAPRDefault:
+                       return True;
+               case WAPRAlternate:
+                       return False;
+               case WAPROther:
+                       panel->dontAsk = True;
+                       return True;
+               }
+       }
+       return True;
+}
+
+static void menuItemDeselected(WEditMenuDelegate * delegate, WEditMenu * menu, WEditMenuItem * item)
+{
+       _Panel *panel = (_Panel *) delegate->data;
+
+       changeInfoType(panel, NULL, NoInfo);
+}
+
+static void menuItemSelected(WEditMenuDelegate * delegate, WEditMenu * menu, WEditMenuItem * item)
+{
+       ItemData *data = WGetEditMenuItemData(item);
+       _Panel *panel = (_Panel *) delegate->data;
+
+       panel->currentItem = item;
+
+       if (data) {
+               changeInfoType(panel, WGetEditMenuItemTitle(item), data->type);
+
+               switch (data->type) {
+               case NoInfo:
+                       break;
+
+               case ExecInfo:
+                       WMSetTextFieldText(panel->commandT, data->param.exec.command);
+                       WMSetTextFieldText(panel->shortT, data->param.exec.shortcut);
+                       break;
+
+               case CommandInfo:
+                       WMSelectListItem(panel->icommandL, data->param.command.command);
+                       WMSetListPosition(panel->icommandL, data->param.command.command - 2);
+                       WMSetTextFieldText(panel->shortT, data->param.command.shortcut);
+
+                       switch (data->param.command.command) {
+                       case 3:
+                       case 4:
+                               WMSetButtonSelected(panel->quickB, data->param.command.parameter != NULL);
+                               break;
+                       case 6:
+                               WMSetTextFieldText(panel->paramT, data->param.command.parameter);
+                               break;
+                       }
+
+                       icommandLClicked(panel->icommandL, panel);
+                       break;
+
+               case PipeInfo:
+                       WMSetTextFieldText(panel->pipeT, data->param.pipe.command);
+                       WMSetButtonSelected(panel->pipeCacheB, data->param.pipe.cached);
+                       break;
+
+               case ExternalInfo:
+                       WMSetTextFieldText(panel->pathT, data->param.external.path);
+                       break;
+
+               case DirectoryInfo:
+                       WMSetTextFieldText(panel->dpathT, data->param.directory.directory);
+                       WMSetTextFieldText(panel->dcommandT, data->param.directory.command);
+                       WMSetButtonSelected(panel->dstripB, data->param.directory.stripExt);
+                       break;
+
+               case WSMenuInfo:
+                       break;
+
+               default:
+                       break;
+               }
+       }
+}
+
+static WEditMenu *buildSubmenu(_Panel * panel, WMPropList * pl)
+{
+       WMScreen *scr = WMWidgetScreen(panel->parent);
+       WEditMenu *menu;
+       WEditMenuItem *item;
+       char *title;
+       WMPropList *tp, *bp;
+       int i;
+
+       tp = WMGetFromPLArray(pl, 0);
+       title = WMGetFromPLString(tp);
+
+       menu = WCreateEditMenu(scr, title);
+
+       for (i = 1; i < WMGetPropListItemCount(pl); i++) {
+               WMPropList *pi;
+
+               pi = WMGetFromPLArray(pl, i);
+
+               tp = WMGetFromPLArray(pi, 0);
+               bp = WMGetFromPLArray(pi, 1);
+
+               title = WMGetFromPLString(tp);
+
+               if (!bp || WMIsPLArray(bp)) {   /* it's a submenu */
+                       WEditMenu *submenu;
+
+                       submenu = buildSubmenu(panel, pi);
+
+                       item = WAddMenuItemWithTitle(menu, title);
+
+                       WSetEditMenuSubmenu(menu, item, submenu);
+               } else {
+                       ItemData *data;
+
+                       item = WAddMenuItemWithTitle(menu, title);
+
+                       data = parseCommand(pi);
+
+                       if (panel->markerPix[data->type])
+                               WSetEditMenuItemImage(item, panel->markerPix[data->type]);
+                       WSetEditMenuItemData(item, data, (WMCallback *) freeItemData);
+               }
+       }
+
+       WSetEditMenuAcceptsDrop(menu, True);
+       WSetEditMenuDelegate(menu, &menuDelegate);
+
+       WMRealizeWidget(menu);
+
+       return menu;
+}
+
+static void buildMenuFromPL(_Panel * panel, WMPropList * pl)
+{
+       panel->menu = buildSubmenu(panel, pl);
+}
+
+static WMPropList *getDefaultMenu(_Panel * panel)
+{
+       WMPropList *menu;
+       char *menuPath, *gspath;
+
+       gspath = wusergnusteppath();
+
+       menuPath = wmalloc(strlen(gspath) + 128);
+       sprintf(menuPath, "%s/Library/WindowMaker/plmenu", gspath);
+
+       menu = WMReadPropListFromFile(menuPath);
+
+       if (!menu) {
+               char *buffer, *msg;
+
+               msg = _("Could not open default menu from '%s'");
+               buffer = wmalloc(strlen(msg) + strlen(menuPath) + 10);
+               sprintf(buffer, msg, menuPath);
+               WMRunAlertPanel(WMWidgetScreen(panel->parent), panel->parent,
+                               _("Error"), buffer, _("OK"), NULL, NULL);
+               wfree(buffer);
+       }
+
+       wfree(menuPath);
+
+       return menu;
+}
+
+static void showData(_Panel * panel)
+{
+       char *gspath;
+       char *menuPath;
+       WMPropList *pmenu;
+
+       gspath = wusergnusteppath();
+
+       menuPath = wmalloc(strlen(gspath) + 32);
+       strcpy(menuPath, gspath);
+       strcat(menuPath, "/Defaults/WMRootMenu");
+
+       pmenu = WMReadPropListFromFile(menuPath);
+
+       if (!pmenu || !WMIsPLArray(pmenu)) {
+               int res;
+
+               res = WMRunAlertPanel(WMWidgetScreen(panel->parent), panel->parent,
+                                     _("Warning"),
+                                     _("The menu file format currently in use is not supported\n"
+                                       "by this tool. Do you want to discard the current menu\n"
+                                       "to use this tool?"),
+                                     _("Yes, Discard and Update"), _("No, Keep Current Menu"), NULL);
+
+               if (res == WAPRDefault) {
+                       pmenu = getDefaultMenu(panel);
+
+                       if (!pmenu) {
+                               pmenu = WMCreatePLArray(WMCreatePLString("Applications"), NULL);
+                       }
+               } else {
+                       panel->dontSave = True;
+                       return;
+               }
+       }
+
+       panel->menuPath = menuPath;
+
+       buildMenuFromPL(panel, pmenu);
+
+       WMReleasePropList(pmenu);
+}
+
+static Bool notblank(char *s)
+{
+       if (s) {
+               while (*s++) {
+                       if (!isspace(*s))
+                               return True;
+               }
+       }
+       return False;
+}
+
+static WMPropList *processData(char *title, ItemData * data)
+{
+       WMPropList *item;
+       char *s1;
+       static WMPropList *pscut = NULL;
+       static WMPropList *pomenu = NULL;
+       int i;
+
+       if (!pscut) {
+               pscut = WMCreatePLString("SHORTCUT");
+               pomenu = WMCreatePLString("OPEN_MENU");
+       }
+
+       item = WMCreatePLArray(WMCreatePLString(title), NULL);
+
+       switch (data->type) {
+       case ExecInfo:
+               if (data->param.exec.command == NULL)
+                       return NULL;
+#if 1
+               if (strpbrk(data->param.exec.command, "&$*|><?`=;")) {
+                       s1 = "SHEXEC";
+               } else {
+                       s1 = "EXEC";
+               }
+#else
+               s1 = "SHEXEC";
+#endif
+
+               if (notblank(data->param.exec.shortcut)) {
+                       WMAddToPLArray(item, pscut);
+                       WMAddToPLArray(item, WMCreatePLString(data->param.exec.shortcut));
+               }
+
+               WMAddToPLArray(item, WMCreatePLString(s1));
+               WMAddToPLArray(item, WMCreatePLString(data->param.exec.command));
+               break;
+
+       case CommandInfo:
+               if (notblank(data->param.command.shortcut)) {
+                       WMAddToPLArray(item, pscut);
+                       WMAddToPLArray(item, WMCreatePLString(data->param.command.shortcut));
+               }
+
+               i = data->param.command.command;
+
+               WMAddToPLArray(item, WMCreatePLString(commandNames[i]));
+
+               switch (i) {
+               case 3:
+               case 4:
+                       if (data->param.command.parameter) {
+                               WMAddToPLArray(item, WMCreatePLString(data->param.command.parameter));
+                       }
+                       break;
+
+               case 6: /* restart */
+                       if (data->param.command.parameter) {
+                               WMAddToPLArray(item, WMCreatePLString(data->param.command.parameter));
+                       }
+                       break;
+               }
+
+               break;
+
+       case PipeInfo:
+               if (!data->param.pipe.command)
+                       return NULL;
+               WMAddToPLArray(item, pomenu);
+               if (data->param.pipe.cached)
+                       s1 = wstrconcat("| ", data->param.pipe.command);
+               else
+                       s1 = wstrconcat("|| ", data->param.pipe.command);
+               WMAddToPLArray(item, WMCreatePLString(s1));
+               wfree(s1);
+               break;
+
+       case ExternalInfo:
+               if (!data->param.external.path)
+                       return NULL;
+               WMAddToPLArray(item, pomenu);
+               WMAddToPLArray(item, WMCreatePLString(data->param.external.path));
+               break;
+
+       case DirectoryInfo:
+               if (!data->param.directory.directory || !data->param.directory.command)
+                       return NULL;
+               {
+                       int l;
+                       char *tmp;
+
+                       l = strlen(data->param.directory.directory);
+                       l += strlen(data->param.directory.command);
+                       l += 32;
+
+                       WMAddToPLArray(item, pomenu);
+
+                       tmp = wmalloc(l);
+                       sprintf(tmp, "%s%s WITH %s",
+                               data->param.directory.stripExt ? "-noext " : "",
+                               data->param.directory.directory, data->param.directory.command);
+
+                       WMAddToPLArray(item, WMCreatePLString(tmp));
+                       wfree(tmp);
+               }
+               break;
+
+       case WSMenuInfo:
+               WMAddToPLArray(item, WMCreatePLString("WORKSPACE_MENU"));
+               break;
+
+       case WWindowListInfo:
+               WMAddToPLArray(item, WMCreatePLString("WINDOWS_MENU"));
+               break;
+
+       default:
+               assert(0);
+               break;
+       }
+
+       return item;
+}
+
+static WMPropList *processSubmenu(WEditMenu * menu)
+{
+       WEditMenuItem *item;
+       WMPropList *pmenu;
+       WMPropList *pl;
+       char *s;
+       int i;
+
+       s = WGetEditMenuTitle(menu);
+       pl = WMCreatePLString(s);
+
+       pmenu = WMCreatePLArray(pl, NULL);
+
+       i = 0;
+       while ((item = WGetEditMenuItem(menu, i++))) {
+               WEditMenu *submenu;
+
+               s = WGetEditMenuItemTitle(item);
+
+               submenu = WGetEditMenuSubmenu(menu, item);
+               if (submenu) {
+                       pl = processSubmenu(submenu);
+               } else {
+                       pl = processData(s, WGetEditMenuItemData(item));
+               }
+
+               if (!pl)
+                       continue;
+
+               WMAddToPLArray(pmenu, pl);
+       }
+
+       return pmenu;
+}
+
+static WMPropList *buildPLFromMenu(_Panel * panel)
+{
+       WMPropList *menu;
+
+       menu = processSubmenu(panel->menu);
+
+       return menu;
+}
+
+static void storeData(_Panel * panel)
+{
+       WMPropList *menu;
+
+       if (panel->dontSave)
+               return;
+
+       menu = buildPLFromMenu(panel);
+
+       WMWritePropListToFile(menu, panel->menuPath, True);
+
+       WMReleasePropList(menu);
+}
+
+static void showMenus(_Panel * panel)
+{
+       if (panel->menu)
+               WEditMenuUnhide(panel->menu);
+}
+
+static void hideMenus(_Panel * panel)
+{
+       if (panel->menu)
+               WEditMenuHide(panel->menu);
+}
+
+Panel *InitMenu(WMScreen * scr, WMWidget * parent)
+{
+       _Panel *panel;
+
+       panel = wmalloc(sizeof(_Panel));
+       memset(panel, 0, sizeof(_Panel));
+
+       panel->sectionName = _("Applications Menu Definition");
+
+       panel->description = _("Edit the menu for launching applications.");
+
+       panel->parent = parent;
+
+       panel->callbacks.createWidgets = createPanel;
+       panel->callbacks.updateDomain = storeData;
+       panel->callbacks.showPanel = showMenus;
+       panel->callbacks.hidePanel = hideMenus;
+
+       AddSection(panel, ICON_FILE);
+
+       return panel;
+}