/* 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 #include #include #include #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) { 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, "&$*|>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; }