Change to the linux kernel coding style
[wmaker-crm.git] / WPrefs.app / Menu.c
1 /* Menu.c- menu definition
2  *
3  *  WPrefs - Window Maker Preferences Program
4  *
5  *  Copyright (c) 2000-2003 Alfredo K. Kojima
6  *
7  *  This program is free software; you can redistribute it and/or modify
8  *  it under the terms of the GNU General Public License as published by
9  *  the Free Software Foundation; either version 2 of the License, or
10  *  (at your option) any later version.
11  *
12  *  This program is distributed in the hope that it will be useful,
13  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
14  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15  *  GNU General Public License for more details.
16  *
17  *  You should have received a copy of the GNU General Public License
18  *  along with this program; if not, write to the Free Software
19  *  Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307,
20  *  USA.
21  */
22
23 #include "WPrefs.h"
24 #include <assert.h>
25 #include <ctype.h>
26
27 #include <X11/keysym.h>
28 #include <X11/cursorfont.h>
29
30 #include "editmenu.h"
31
32 typedef enum {
33         NoInfo,
34         ExecInfo,
35         CommandInfo,
36         ExternalInfo,
37         PipeInfo,
38         DirectoryInfo,
39         WSMenuInfo,
40         WWindowListInfo,
41         LastInfo
42 } InfoType;
43
44 #define MAX_SECTION_SIZE 4
45
46 typedef struct _Panel {
47         WMBox *box;
48         char *sectionName;
49
50         char *description;
51
52         CallbackRec callbacks;
53         WMWidget *parent;
54
55         WMFont *boldFont;
56         WMFont *normalFont;
57         WMColor *white;
58         WMColor *gray;
59         WMColor *black;
60
61         WMPixmap *markerPix[LastInfo];
62
63         WMPopUpButton *typeP;
64
65         WMWidget *itemPad[3];
66         int currentPad;
67
68         WEditMenu *menu;
69         char *menuPath;
70
71         WMFrame *optionsF;
72
73         WMFrame *commandF;
74         WMTextField *commandT;  /* command to run */
75         WMButton *browseB;
76         WMButton *xtermC;       /* inside xterm? */
77
78         WMFrame *pathF;
79         WMTextField *pathT;
80
81         WMFrame *pipeF;
82         WMTextField *pipeT;
83         WMButton *pipeCacheB;
84
85         WMFrame *dpathF;
86         WMTextField *dpathT;
87
88         WMFrame *dcommandF;
89         WMTextField *dcommandT;
90
91         WMButton *dstripB;
92
93         WMFrame *shortF;
94         WMTextField *shortT;
95         WMButton *sgrabB;
96         WMButton *sclearB;
97
98         WMList *icommandL;
99
100         WMFrame *paramF;
101         WMTextField *paramT;
102
103         WMButton *quickB;
104
105         Bool dontAsk;           /* whether to comfirm submenu remove */
106         Bool dontSave;
107
108         Bool capturing;
109
110         /* about the currently selected item */
111         WEditMenuItem *currentItem;
112         InfoType currentType;
113         WMWidget *sections[LastInfo][MAX_SECTION_SIZE];
114 } _Panel;
115
116 typedef struct {
117         InfoType type;
118         union {
119                 struct {
120                         int command;
121                         char *parameter;
122                         char *shortcut;
123                 } command;
124                 struct {
125                         char *command;
126                         char *shortcut;
127                 } exec;
128                 struct {
129                         char *path;
130                 } external;
131                 struct {
132                         char *command;
133                         unsigned cached:1;
134                 } pipe;
135                 struct {
136                         char *directory;
137                         char *command;
138                         unsigned stripExt:1;
139                 } directory;
140         } param;
141 } ItemData;
142
143 static char *commandNames[] = {
144         "ARRANGE_ICONS",
145         "HIDE_OTHERS",
146         "SHOW_ALL",
147         "EXIT",
148         "SHUTDOWN",
149         "RESTART",
150         "RESTART",
151         "SAVE_SESSION",
152         "CLEAR_SESSION",
153         "REFRESH",
154         "INFO_PANEL",
155         "LEGAL_PANEL"
156 };
157
158 #define NEW(type) memset(wmalloc(sizeof(type)), 0, sizeof(type))
159
160 #define ICON_FILE       "menus"
161
162 static void showData(_Panel * panel);
163
164 static void updateMenuItem(_Panel * panel, WEditMenuItem * item, WMWidget * changedWidget);
165
166 static void menuItemSelected(struct WEditMenuDelegate *delegate, WEditMenu * menu, WEditMenuItem * item);
167
168 static void menuItemDeselected(struct WEditMenuDelegate *delegate, WEditMenu * menu, WEditMenuItem * item);
169
170 static void menuItemCloned(struct WEditMenuDelegate *delegate, WEditMenu * menu,
171                            WEditMenuItem * origItem, WEditMenuItem * newItem);
172
173 static void menuItemEdited(struct WEditMenuDelegate *delegate, WEditMenu * menu, WEditMenuItem * item);
174
175 static Bool shouldRemoveItem(struct WEditMenuDelegate *delegate, WEditMenu * menu, WEditMenuItem * item);
176
177 static void freeItemData(ItemData * data);
178
179 static WEditMenuDelegate menuDelegate = {
180         NULL,
181         menuItemCloned,
182         menuItemEdited,
183         menuItemSelected,
184         menuItemDeselected,
185         shouldRemoveItem
186 };
187
188 static void dataChanged(void *self, WMNotification * notif)
189 {
190         _Panel *panel = (_Panel *) self;
191         WEditMenuItem *item = panel->currentItem;
192         WMWidget *w = (WMWidget *) WMGetNotificationObject(notif);
193
194         updateMenuItem(panel, item, w);
195 }
196
197 static void buttonClicked(WMWidget * w, void *data)
198 {
199         _Panel *panel = (_Panel *) data;
200         WEditMenuItem *item = panel->currentItem;
201
202         updateMenuItem(panel, item, w);
203 }
204
205 static void icommandLClicked(WMWidget * w, void *data)
206 {
207         _Panel *panel = (_Panel *) data;
208         int cmd;
209
210         cmd = WMGetListSelectedItemRow(w);
211         if (cmd == 3 || cmd == 4) {
212                 WMMapWidget(panel->quickB);
213         } else {
214                 WMUnmapWidget(panel->quickB);
215         }
216         if (cmd == 6) {
217                 WMMapWidget(panel->paramF);
218         } else {
219                 WMUnmapWidget(panel->paramF);
220         }
221 }
222
223 static void browseForFile(WMWidget * self, void *clientData)
224 {
225         _Panel *panel = (_Panel *) clientData;
226         WMFilePanel *filePanel;
227         char *text, *oldprog, *newprog;
228
229         filePanel = WMGetOpenPanel(WMWidgetScreen(self));
230         text = WMGetTextFieldText(panel->commandT);
231
232         oldprog = wtrimspace(text);
233         wfree(text);
234
235         if (oldprog[0] == 0 || oldprog[0] != '/') {
236                 wfree(oldprog);
237                 oldprog = wstrdup("/");
238         } else {
239                 char *ptr = oldprog;
240                 while (*ptr && !isspace(*ptr))
241                         ptr++;
242                 *ptr = 0;
243         }
244
245         WMSetFilePanelCanChooseDirectories(filePanel, False);
246
247         if (WMRunModalFilePanelForDirectory(filePanel, panel->parent, oldprog, _("Select Program"), NULL) == True) {
248                 newprog = WMGetFilePanelFileName(filePanel);
249                 WMSetTextFieldText(panel->commandT, newprog);
250                 updateMenuItem(panel, panel->currentItem, panel->commandT);
251                 wfree(newprog);
252         }
253
254         wfree(oldprog);
255 }
256
257 static char *captureShortcut(Display * dpy, _Panel * panel)
258 {
259         XEvent ev;
260         KeySym ksym;
261         char buffer[64];
262         char *key = NULL;
263
264         while (panel->capturing) {
265                 XAllowEvents(dpy, AsyncKeyboard, CurrentTime);
266                 WMNextEvent(dpy, &ev);
267                 if (ev.type == KeyPress && ev.xkey.keycode != 0) {
268                         ksym = XKeycodeToKeysym(dpy, ev.xkey.keycode, 0);
269                         if (!IsModifierKey(ksym)) {
270                                 key = XKeysymToString(ksym);
271                                 panel->capturing = 0;
272                                 break;
273                         }
274                 }
275                 WMHandleEvent(&ev);
276         }
277
278         if (!key)
279                 return NULL;
280
281         buffer[0] = 0;
282
283         if (ev.xkey.state & ControlMask) {
284                 strcat(buffer, "Control+");
285         }
286         if (ev.xkey.state & ShiftMask) {
287                 strcat(buffer, "Shift+");
288         }
289         if (ev.xkey.state & Mod1Mask) {
290                 strcat(buffer, "Mod1+");
291         }
292         if (ev.xkey.state & Mod2Mask) {
293                 strcat(buffer, "Mod2+");
294         }
295         if (ev.xkey.state & Mod3Mask) {
296                 strcat(buffer, "Mod3+");
297         }
298         if (ev.xkey.state & Mod4Mask) {
299                 strcat(buffer, "Mod4+");
300         }
301         if (ev.xkey.state & Mod5Mask) {
302                 strcat(buffer, "Mod5+");
303         }
304         strcat(buffer, key);
305
306         return wstrdup(buffer);
307 }
308
309 static void sgrabClicked(WMWidget * w, void *data)
310 {
311         _Panel *panel = (_Panel *) data;
312         Display *dpy = WMScreenDisplay(WMWidgetScreen(panel->parent));
313         char *shortcut;
314
315         if (w == panel->sclearB) {
316                 WMSetTextFieldText(panel->shortT, "");
317                 updateMenuItem(panel, panel->currentItem, panel->shortT);
318                 return;
319         }
320
321         if (!panel->capturing) {
322                 panel->capturing = 1;
323                 WMSetButtonText(w, _("Cancel"));
324                 XGrabKeyboard(dpy, WMWidgetXID(panel->parent), True, GrabModeAsync, GrabModeAsync, CurrentTime);
325                 shortcut = captureShortcut(dpy, panel);
326                 if (shortcut) {
327                         WMSetTextFieldText(panel->shortT, shortcut);
328                         updateMenuItem(panel, panel->currentItem, panel->shortT);
329                         wfree(shortcut);
330                 }
331         }
332         panel->capturing = 0;
333         WMSetButtonText(w, _("Capture"));
334         XUngrabKeyboard(dpy, CurrentTime);
335 }
336
337 static void changedItemPad(WMWidget * w, void *data)
338 {
339         _Panel *panel = (_Panel *) data;
340         int padn = WMGetPopUpButtonSelectedItem(w);
341
342         WMUnmapWidget(panel->itemPad[panel->currentPad]);
343         WMMapWidget(panel->itemPad[padn]);
344
345         panel->currentPad = padn;
346 }
347
348 static WEditMenu *putNewSubmenu(WEditMenu * menu, char *title)
349 {
350         WEditMenu *tmp;
351         WEditMenuItem *item;
352
353         item = WAddMenuItemWithTitle(menu, title);
354
355         tmp = WCreateEditMenu(WMWidgetScreen(menu), title);
356         WSetEditMenuAcceptsDrop(tmp, True);
357         WSetEditMenuDelegate(tmp, &menuDelegate);
358         WSetEditMenuSubmenu(menu, item, tmp);
359
360         return tmp;
361 }
362
363 static ItemData *putNewItem(_Panel * panel, WEditMenu * menu, int type, char *title)
364 {
365         WEditMenuItem *item;
366         ItemData *data;
367
368         item = WAddMenuItemWithTitle(menu, title);
369
370         data = NEW(ItemData);
371         data->type = type;
372         WSetEditMenuItemData(item, data, (WMCallback *) freeItemData);
373         WSetEditMenuItemImage(item, panel->markerPix[type]);
374
375         return data;
376 }
377
378 static WEditMenu *makeFactoryMenu(WMWidget * parent, int width)
379 {
380         WEditMenu *pad;
381
382         pad = WCreateEditMenuPad(parent);
383         WMResizeWidget(pad, width, 10);
384         WSetEditMenuMinSize(pad, wmksize(width, 0));
385         WSetEditMenuMaxSize(pad, wmksize(width, 0));
386         WSetEditMenuSelectable(pad, False);
387         WSetEditMenuEditable(pad, False);
388         WSetEditMenuIsFactory(pad, True);
389         WSetEditMenuDelegate(pad, &menuDelegate);
390
391         return pad;
392 }
393
394 static void createPanel(_Panel * p)
395 {
396         _Panel *panel = (_Panel *) p;
397         WMScreen *scr = WMWidgetScreen(panel->parent);
398         WMColor *black = WMBlackColor(scr);
399         WMColor *white = WMWhiteColor(scr);
400         WMColor *gray = WMGrayColor(scr);
401         WMFont *bold = WMBoldSystemFontOfSize(scr, 12);
402         WMFont *font = WMSystemFontOfSize(scr, 12);
403         WMLabel *label;
404         int width;
405
406         menuDelegate.data = panel;
407
408         panel->boldFont = bold;
409         panel->normalFont = font;
410
411         panel->black = black;
412         panel->white = white;
413         panel->gray = gray;
414
415         {
416                 Pixmap pix;
417                 Display *dpy = WMScreenDisplay(scr);
418                 GC gc;
419                 WMPixmap *pixm;
420
421                 pixm = WMCreatePixmap(scr, 7, 7, WMScreenDepth(scr), True);
422
423                 pix = WMGetPixmapXID(pixm);
424
425                 XDrawLine(dpy, pix, WMColorGC(black), 0, 3, 6, 3);
426                 XDrawLine(dpy, pix, WMColorGC(black), 3, 0, 3, 6);
427                 /*
428                    XDrawLine(dpy, pix, WMColorGC(black), 1, 0, 3, 3);
429                    XDrawLine(dpy, pix, WMColorGC(black), 1, 6, 3, 3);
430                    XDrawLine(dpy, pix, WMColorGC(black), 0, 0, 0, 6);
431                  */
432
433                 pix = WMGetPixmapMaskXID(pixm);
434
435                 gc = XCreateGC(dpy, pix, 0, NULL);
436
437                 XSetForeground(dpy, gc, 0);
438                 XFillRectangle(dpy, pix, gc, 0, 0, 7, 7);
439
440                 XSetForeground(dpy, gc, 1);
441                 XDrawLine(dpy, pix, gc, 0, 3, 6, 3);
442                 XDrawLine(dpy, pix, gc, 3, 0, 3, 6);
443
444                 panel->markerPix[ExternalInfo] = pixm;
445                 panel->markerPix[PipeInfo] = pixm;
446                 panel->markerPix[DirectoryInfo] = pixm;
447                 panel->markerPix[WSMenuInfo] = pixm;
448                 panel->markerPix[WWindowListInfo] = pixm;
449
450                 XFreeGC(dpy, gc);
451         }
452
453         panel->box = WMCreateBox(panel->parent);
454         WMSetViewExpandsToParent(WMWidgetView(panel->box), 2, 2, 2, 2);
455
456         panel->typeP = WMCreatePopUpButton(panel->box);
457         WMResizeWidget(panel->typeP, 150, 20);
458         WMMoveWidget(panel->typeP, 10, 10);
459
460         WMAddPopUpButtonItem(panel->typeP, _("New Items"));
461         WMAddPopUpButtonItem(panel->typeP, _("Sample Commands"));
462         WMAddPopUpButtonItem(panel->typeP, _("Sample Submenus"));
463
464         WMSetPopUpButtonAction(panel->typeP, changedItemPad, panel);
465
466         WMSetPopUpButtonSelectedItem(panel->typeP, 0);
467
468         {
469                 WEditMenu *pad;
470                 WEditMenu *smenu;
471                 ItemData *data;
472
473                 pad = makeFactoryMenu(panel->box, 150);
474                 WMMoveWidget(pad, 10, 40);
475
476                 data = putNewItem(panel, pad, ExecInfo, _("Run Program"));
477                 data = putNewItem(panel, pad, CommandInfo, _("Internal Command"));
478                 smenu = putNewSubmenu(pad, _("Submenu"));
479                 data = putNewItem(panel, pad, ExternalInfo, _("External Submenu"));
480                 data = putNewItem(panel, pad, PipeInfo, _("Generated Submenu"));
481                 data = putNewItem(panel, pad, DirectoryInfo, _("Directory Contents"));
482                 data = putNewItem(panel, pad, WSMenuInfo, _("Workspace Menu"));
483                 data = putNewItem(panel, pad, WWindowListInfo, _("Window List Menu"));
484
485                 panel->itemPad[0] = pad;
486         }
487
488         {
489                 WEditMenu *pad;
490                 ItemData *data;
491                 WMScrollView *sview;
492
493                 sview = WMCreateScrollView(panel->box);
494                 WMResizeWidget(sview, 150, 180);
495                 WMMoveWidget(sview, 10, 40);
496                 WMSetScrollViewHasVerticalScroller(sview, True);
497
498                 pad = makeFactoryMenu(panel->box, 130);
499
500                 WMSetScrollViewContentView(sview, WMWidgetView(pad));
501
502                 data = putNewItem(panel, pad, ExecInfo, _("XTerm"));
503                 data->param.exec.command = "xterm -sb -sl 2000 -bg black -fg white";
504
505                 data = putNewItem(panel, pad, ExecInfo, _("rxvt"));
506                 data->param.exec.command = "rxvt";
507
508                 data = putNewItem(panel, pad, ExecInfo, _("ETerm"));
509                 data->param.exec.command = "eterm";
510
511                 data = putNewItem(panel, pad, ExecInfo, _("Run..."));
512                 data->param.exec.command = _("%a(Run,Type command to run)");
513
514                 data = putNewItem(panel, pad, ExecInfo, _("Netscape"));
515                 data->param.exec.command = "netscape";
516
517                 data = putNewItem(panel, pad, ExecInfo, _("gimp"));
518                 data->param.exec.command = "gimp";
519
520                 data = putNewItem(panel, pad, ExecInfo, _("epic"));
521                 data->param.exec.command = "xterm -e epic";
522
523                 data = putNewItem(panel, pad, ExecInfo, _("ee"));
524                 data->param.exec.command = "ee";
525
526                 data = putNewItem(panel, pad, ExecInfo, _("xv"));
527                 data->param.exec.command = "xv";
528
529                 data = putNewItem(panel, pad, ExecInfo, _("Acrobat Reader"));
530                 data->param.exec.command = "acroread || /usr/local/Acrobat4/bin/acroread";
531
532                 data = putNewItem(panel, pad, ExecInfo, _("ghostview"));
533                 data->param.exec.command = "gv";
534
535                 data = putNewItem(panel, pad, CommandInfo, _("Exit Window Maker"));
536                 data->param.command.command = 3;
537
538                 WMMapWidget(pad);
539
540                 panel->itemPad[1] = sview;
541         }
542
543         {
544                 WEditMenu *pad, *smenu;
545                 ItemData *data;
546                 WMScrollView *sview;
547
548                 sview = WMCreateScrollView(panel->box);
549                 WMResizeWidget(sview, 150, 180);
550                 WMMoveWidget(sview, 10, 40);
551                 WMSetScrollViewHasVerticalScroller(sview, True);
552
553                 pad = makeFactoryMenu(panel->box, 130);
554
555                 WMSetScrollViewContentView(sview, WMWidgetView(pad));
556
557                 data = putNewItem(panel, pad, ExternalInfo, _("Debian Menu"));
558                 data->param.pipe.command = "/etc/X11/WindowMaker/menu.hook";
559
560                 data = putNewItem(panel, pad, PipeInfo, _("RedHat Menu"));
561                 data->param.pipe.command = "wmconfig --output wmaker";
562
563                 data = putNewItem(panel, pad, PipeInfo, _("Menu Conectiva"));
564                 data->param.pipe.command = "wmconfig --output wmaker";
565
566                 data = putNewItem(panel, pad, DirectoryInfo, _("Themes"));
567                 data->param.directory.command = "setstyle";
568                 data->param.directory.directory =
569                     "/usr/share/WindowMaker/Themes /usr/local/share/WindowMaker/Themes $HOME/GNUstep/Library/WindowMaker/Themes";
570                 data->param.directory.stripExt = 1;
571
572                 data = putNewItem(panel, pad, DirectoryInfo, _("Bg Images (scale)"));
573                 data->param.directory.command = "wmsetbg -u -s";
574                 data->param.directory.directory =
575                     "/opt/kde2/share/wallpapers /usr/share/WindowMaker/Backgrounds $HOME/GNUstep/Library/WindowMaker/Backgrounds";
576                 data->param.directory.stripExt = 1;
577
578                 data = putNewItem(panel, pad, DirectoryInfo, _("Bg Images (tile)"));
579                 data->param.directory.command = "wmsetbg -u -t";
580                 data->param.directory.directory =
581                     "/opt/kde2/share/wallpapers /usr/share/WindowMaker/Backgrounds $HOME/GNUstep/Library/WindowMaker/Backgrounds";
582                 data->param.directory.stripExt = 1;
583
584                 smenu = putNewSubmenu(pad, _("Assorted XTerms"));
585
586                 data = putNewItem(panel, smenu, ExecInfo, _("XTerm Yellow on Blue"));
587                 data->param.exec.command = "xterm -sb -sl 2000 -bg midnightblue -fg yellow";
588
589                 data = putNewItem(panel, smenu, ExecInfo, _("XTerm White on Black"));
590                 data->param.exec.command = "xterm -sb -sl 2000 -bg black -fg white";
591
592                 data = putNewItem(panel, smenu, ExecInfo, _("XTerm Black on White"));
593                 data->param.exec.command = "xterm -sb -sl 2000 -bg white -fg black";
594
595                 data = putNewItem(panel, smenu, ExecInfo, _("XTerm Black on Beige"));
596                 data->param.exec.command = "xterm -sb -sl 2000 -bg '#bbbb99' -fg black";
597
598                 data = putNewItem(panel, smenu, ExecInfo, _("XTerm White on Green"));
599                 data->param.exec.command = "xterm -sb -sl 2000 -bg '#228822' -fg white";
600
601                 data = putNewItem(panel, smenu, ExecInfo, _("XTerm White on Olive"));
602                 data->param.exec.command = "xterm -sb -sl 2000 -bg '#335533' -fg white";
603
604                 data = putNewItem(panel, smenu, ExecInfo, _("XTerm Blue on Blue"));
605                 data->param.exec.command = "xterm -sb -sl 2000 -bg '#112244' -fg '#88aabb'";
606
607                 data = putNewItem(panel, smenu, ExecInfo, _("XTerm BIG FONTS"));
608                 data->param.exec.command = "xterm -sb -sl 2000 -bg black -fg white -fn 10x20";
609
610                 WMMapWidget(pad);
611
612                 panel->itemPad[2] = sview;
613         }
614
615         width = FRAME_WIDTH - 20 - 150 - 10 - 2;
616
617         panel->optionsF = WMCreateFrame(panel->box);
618         WMResizeWidget(panel->optionsF, width, FRAME_HEIGHT - 15);
619         WMMoveWidget(panel->optionsF, 10 + 150 + 10, 5);
620
621         width -= 20;
622
623         /* command */
624
625         panel->commandF = WMCreateFrame(panel->optionsF);
626         WMResizeWidget(panel->commandF, width, 50);
627         WMMoveWidget(panel->commandF, 10, 20);
628         WMSetFrameTitle(panel->commandF, _("Program to Run"));
629         WMSetFrameTitlePosition(panel->commandF, WTPAtTop);
630
631         panel->commandT = WMCreateTextField(panel->commandF);
632         WMResizeWidget(panel->commandT, width - 95, 20);
633         WMMoveWidget(panel->commandT, 10, 20);
634
635         panel->browseB = WMCreateCommandButton(panel->commandF);
636         WMResizeWidget(panel->browseB, 70, 24);
637         WMMoveWidget(panel->browseB, width - 80, 18);
638         WMSetButtonText(panel->browseB, _("Browse"));
639         WMSetButtonAction(panel->browseB, browseForFile, panel);
640
641         WMAddNotificationObserver(dataChanged, panel, WMTextDidChangeNotification, panel->commandT);
642
643 #if 0
644         panel->xtermC = WMCreateSwitchButton(panel->commandF);
645         WMResizeWidget(panel->xtermC, width - 20, 20);
646         WMMoveWidget(panel->xtermC, 10, 50);
647         WMSetButtonText(panel->xtermC, _("Run the program inside a Xterm"));
648 #endif
649         WMMapSubwidgets(panel->commandF);
650
651         /* path */
652
653         panel->pathF = WMCreateFrame(panel->optionsF);
654         WMResizeWidget(panel->pathF, width, 150);
655         WMMoveWidget(panel->pathF, 10, 40);
656         WMSetFrameTitle(panel->pathF, _("Path for Menu"));
657
658         panel->pathT = WMCreateTextField(panel->pathF);
659         WMResizeWidget(panel->pathT, width - 20, 20);
660         WMMoveWidget(panel->pathT, 10, 20);
661
662         WMAddNotificationObserver(dataChanged, panel, WMTextDidChangeNotification, panel->pathT);
663
664         label = WMCreateLabel(panel->pathF);
665         WMResizeWidget(label, width - 20, 80);
666         WMMoveWidget(label, 10, 50);
667         WMSetLabelText(label, _("Enter the path for a file containing a menu\n"
668                                 "or a list of directories with the programs you\n"
669                                 "want to have listed in the menu. Ex:\n"
670                                 "~/GNUstep/Library/WindowMaker/menu\n" "or\n" "/usr/X11R6/bin ~/xbin"));
671
672         WMMapSubwidgets(panel->pathF);
673
674         /* pipe */
675
676         panel->pipeF = WMCreateFrame(panel->optionsF);
677         WMResizeWidget(panel->pipeF, width, 155);
678         WMMoveWidget(panel->pipeF, 10, 30);
679         WMSetFrameTitle(panel->pipeF, _("Command"));
680
681         panel->pipeT = WMCreateTextField(panel->pipeF);
682         WMResizeWidget(panel->pipeT, width - 20, 20);
683         WMMoveWidget(panel->pipeT, 10, 20);
684
685         WMAddNotificationObserver(dataChanged, panel, WMTextDidChangeNotification, panel->pipeT);
686
687         label = WMCreateLabel(panel->pipeF);
688         WMResizeWidget(label, width - 20, 40);
689         WMMoveWidget(label, 10, 50);
690         WMSetLabelText(label, _("Enter a command that outputs a menu\n" "definition to stdout when invoked."));
691
692         panel->pipeCacheB = WMCreateSwitchButton(panel->pipeF);
693         WMResizeWidget(panel->pipeCacheB, width - 20, 40);
694         WMMoveWidget(panel->pipeCacheB, 10, 110);
695         WMSetButtonText(panel->pipeCacheB, _("Cache menu contents after opening for\n" "the first time"));
696
697         WMMapSubwidgets(panel->pipeF);
698
699         /* directory menu */
700
701         panel->dcommandF = WMCreateFrame(panel->optionsF);
702         WMResizeWidget(panel->dcommandF, width, 90);
703         WMMoveWidget(panel->dcommandF, 10, 25);
704         WMSetFrameTitle(panel->dcommandF, _("Command to Open Files"));
705
706         panel->dcommandT = WMCreateTextField(panel->dcommandF);
707         WMResizeWidget(panel->dcommandT, width - 20, 20);
708         WMMoveWidget(panel->dcommandT, 10, 20);
709
710         WMAddNotificationObserver(dataChanged, panel, WMTextDidChangeNotification, panel->dcommandT);
711
712         label = WMCreateLabel(panel->dcommandF);
713         WMResizeWidget(label, width - 20, 45);
714         WMMoveWidget(label, 10, 40);
715         WMSetLabelText(label, _("Enter the command you want to use to open the\n"
716                                 "files in the directories listed below."));
717
718         WMMapSubwidgets(panel->dcommandF);
719
720         panel->dpathF = WMCreateFrame(panel->optionsF);
721         WMResizeWidget(panel->dpathF, width, 80);
722         WMMoveWidget(panel->dpathF, 10, 125);
723         WMSetFrameTitle(panel->dpathF, _("Directories with Files"));
724
725         panel->dpathT = WMCreateTextField(panel->dpathF);
726         WMResizeWidget(panel->dpathT, width - 20, 20);
727         WMMoveWidget(panel->dpathT, 10, 20);
728
729         WMAddNotificationObserver(dataChanged, panel, WMTextDidChangeNotification, panel->dpathT);
730
731         panel->dstripB = WMCreateSwitchButton(panel->dpathF);
732         WMResizeWidget(panel->dstripB, width - 20, 20);
733         WMMoveWidget(panel->dstripB, 10, 50);
734         WMSetButtonText(panel->dstripB, _("Strip extensions from file names"));
735
736         WMSetButtonAction(panel->dstripB, buttonClicked, panel);
737
738         WMMapSubwidgets(panel->dpathF);
739
740         /* shortcut */
741
742         panel->shortF = WMCreateFrame(panel->optionsF);
743         WMResizeWidget(panel->shortF, width, 50);
744         WMMoveWidget(panel->shortF, 10, 160);
745         WMSetFrameTitle(panel->shortF, _("Keyboard Shortcut"));
746
747         panel->shortT = WMCreateTextField(panel->shortF);
748         WMResizeWidget(panel->shortT, width - 20 - 150, 20);
749         WMMoveWidget(panel->shortT, 10, 20);
750
751         WMAddNotificationObserver(dataChanged, panel, WMTextDidChangeNotification, panel->shortT);
752
753         panel->sgrabB = WMCreateCommandButton(panel->shortF);
754         WMResizeWidget(panel->sgrabB, 70, 24);
755         WMMoveWidget(panel->sgrabB, width - 80, 18);
756         WMSetButtonText(panel->sgrabB, _("Capture"));
757         WMSetButtonAction(panel->sgrabB, sgrabClicked, panel);
758
759         panel->sclearB = WMCreateCommandButton(panel->shortF);
760         WMResizeWidget(panel->sclearB, 70, 24);
761         WMMoveWidget(panel->sclearB, width - 155, 18);
762         WMSetButtonText(panel->sclearB, _("Clear"));
763         WMSetButtonAction(panel->sclearB, sgrabClicked, panel);
764
765         WMMapSubwidgets(panel->shortF);
766
767         /* internal command */
768
769         panel->icommandL = WMCreateList(panel->optionsF);
770         WMResizeWidget(panel->icommandL, width, 80);
771         WMMoveWidget(panel->icommandL, 10, 20);
772
773         WMSetListAction(panel->icommandL, icommandLClicked, panel);
774
775         WMAddNotificationObserver(dataChanged, panel, WMListSelectionDidChangeNotification, panel->icommandL);
776
777         WMInsertListItem(panel->icommandL, 0, _("Arrange Icons"));
778         WMInsertListItem(panel->icommandL, 1, _("Hide All Windows Except For The Focused One"));
779         WMInsertListItem(panel->icommandL, 2, _("Show All Windows"));
780
781         WMInsertListItem(panel->icommandL, 3, _("Exit Window Maker"));
782         WMInsertListItem(panel->icommandL, 4, _("Exit X Session"));
783         WMInsertListItem(panel->icommandL, 5, _("Restart Window Maker"));
784         WMInsertListItem(panel->icommandL, 6, _("Start Another Window Manager   : ("));
785
786         WMInsertListItem(panel->icommandL, 7, _("Save Current Session"));
787         WMInsertListItem(panel->icommandL, 8, _("Clear Saved Session"));
788         WMInsertListItem(panel->icommandL, 9, _("Refresh Screen"));
789         WMInsertListItem(panel->icommandL, 10, _("Open Info Panel"));
790         WMInsertListItem(panel->icommandL, 11, _("Open Copyright Panel"));
791
792         panel->paramF = WMCreateFrame(panel->optionsF);
793         WMResizeWidget(panel->paramF, width, 50);
794         WMMoveWidget(panel->paramF, 10, 105);
795         WMSetFrameTitle(panel->paramF, _("Window Manager to Start"));
796
797         panel->paramT = WMCreateTextField(panel->paramF);
798         WMResizeWidget(panel->paramT, width - 20, 20);
799         WMMoveWidget(panel->paramT, 10, 20);
800
801         WMAddNotificationObserver(dataChanged, panel, WMTextDidChangeNotification, panel->paramT);
802
803         WMMapSubwidgets(panel->paramF);
804
805         panel->quickB = WMCreateSwitchButton(panel->optionsF);
806         WMResizeWidget(panel->quickB, width, 20);
807         WMMoveWidget(panel->quickB, 10, 120);
808         WMSetButtonText(panel->quickB, _("Do not confirm action."));
809         WMSetButtonAction(panel->quickB, buttonClicked, panel);
810
811         label = WMCreateLabel(panel->optionsF);
812         WMResizeWidget(label, width + 5, FRAME_HEIGHT - 50);
813         WMMoveWidget(label, 7, 20);
814         WMSetLabelText(label,
815                        _("Instructions:\n\n"
816                          " - drag items from the left to the menu to add new items\n"
817                          " - drag items out of the menu to remove items\n"
818                          " - drag items in menu to change their position\n"
819                          " - drag items with Control pressed to copy them\n"
820                          " - double click in a menu item to change the label\n"
821                          " - click on a menu item to change related information"));
822         WMMapWidget(label);
823
824         WMRealizeWidget(panel->box);
825         WMMapSubwidgets(panel->box);
826         WMMapWidget(panel->box);
827
828         {
829                 int i;
830                 for (i = 0; i < 3; i++)
831                         WMUnmapWidget(panel->itemPad[i]);
832         }
833         changedItemPad(panel->typeP, panel);
834
835         panel->sections[NoInfo][0] = label;
836
837         panel->sections[ExecInfo][0] = panel->commandF;
838         panel->sections[ExecInfo][1] = panel->shortF;
839
840         panel->sections[CommandInfo][0] = panel->icommandL;
841         panel->sections[CommandInfo][1] = panel->shortF;
842
843         panel->sections[ExternalInfo][0] = panel->pathF;
844
845         panel->sections[PipeInfo][0] = panel->pipeF;
846
847         panel->sections[DirectoryInfo][0] = panel->dpathF;
848         panel->sections[DirectoryInfo][1] = panel->dcommandF;
849
850         panel->currentType = NoInfo;
851
852         showData(panel);
853
854         {
855                 WMPoint pos;
856
857                 pos = WMGetViewScreenPosition(WMWidgetView(panel->box));
858
859                 if (pos.x < 200) {
860                         pos.x += FRAME_WIDTH + 20;
861                 } else {
862                         pos.x = 10;
863                 }
864
865                 pos.y = WMAX(pos.y - 100, 0);
866
867                 if (panel->menu)
868                         WEditMenuShowAt(panel->menu, pos.x, pos.y);
869         }
870 }
871
872 static void freeItemData(ItemData * data)
873 {
874 #define CFREE(d) if (d) wfree(d)
875
876         /* TODO */
877         switch (data->type) {
878         case CommandInfo:
879                 CFREE(data->param.command.parameter);
880                 CFREE(data->param.command.shortcut);
881                 break;
882
883         case ExecInfo:
884                 CFREE(data->param.exec.command);
885                 CFREE(data->param.exec.shortcut);
886                 break;
887
888         case PipeInfo:
889                 CFREE(data->param.pipe.command);
890                 break;
891
892         case ExternalInfo:
893                 CFREE(data->param.external.path);
894                 break;
895
896         case DirectoryInfo:
897                 CFREE(data->param.directory.command);
898                 CFREE(data->param.directory.directory);
899                 break;
900
901         default:
902                 break;
903         }
904
905         wfree(data);
906 #undef CFREE
907 }
908
909 static ItemData *parseCommand(WMPropList * item)
910 {
911         ItemData *data = NEW(ItemData);
912         WMPropList *p;
913         char *command = NULL;
914         char *parameter = NULL;
915         char *shortcut = NULL;
916         int i = 1;
917
918         p = WMGetFromPLArray(item, i++);
919         command = WMGetFromPLString(p);
920         if (strcmp(command, "SHORTCUT") == 0) {
921                 p = WMGetFromPLArray(item, i++);
922                 shortcut = WMGetFromPLString(p);
923                 p = WMGetFromPLArray(item, i++);
924                 command = WMGetFromPLString(p);
925         }
926         p = WMGetFromPLArray(item, i++);
927         if (p)
928                 parameter = WMGetFromPLString(p);
929
930         if (strcmp(command, "EXEC") == 0 || strcmp(command, "SHEXEC") == 0) {
931
932                 data->type = ExecInfo;
933
934                 data->param.exec.command = wstrdup(parameter);
935                 if (shortcut)
936                         data->param.exec.shortcut = wstrdup(shortcut);
937
938         } else if (strcmp(command, "OPEN_MENU") == 0) {
939                 char *p;
940                 /*
941                  * dir menu, menu file
942                  * dir WITH
943                  * |pipe
944                  */
945                 p = parameter;
946                 while (isspace(*p) && *p)
947                         p++;
948                 if (*p == '|') {
949                         if (*(p + 1) == '|') {
950                                 p++;
951                                 data->param.pipe.cached = 0;
952                         } else {
953                                 data->param.pipe.cached = 1;
954                         }
955                         data->type = PipeInfo;
956                         data->param.pipe.command = wtrimspace(p + 1);
957                 } else {
958                         char *s;
959
960                         p = wstrdup(p);
961
962                         s = strstr(p, "WITH");
963                         if (s) {
964                                 char **tokens;
965                                 char **ctokens;
966                                 int tokn;
967                                 int i, j;
968
969                                 data->type = DirectoryInfo;
970
971                                 *s = '\0';
972                                 s += 5;
973                                 while (*s && isspace(*s))
974                                         s++;
975                                 data->param.directory.command = wstrdup(s);
976
977                                 wtokensplit(p, &tokens, &tokn);
978                                 wfree(p);
979
980                                 ctokens = wmalloc(sizeof(char *) * tokn);
981
982                                 for (i = 0, j = 0; i < tokn; i++) {
983                                         if (strcmp(tokens[i], "-noext") == 0) {
984                                                 wfree(tokens[i]);
985                                                 data->param.directory.stripExt = 1;
986                                         } else {
987                                                 ctokens[j++] = tokens[i];
988                                         }
989                                 }
990                                 data->param.directory.directory = wtokenjoin(ctokens, j);
991                                 wfree(ctokens);
992
993                                 wtokenfree(tokens, tokn);
994                         } else {
995                                 data->type = ExternalInfo;
996                                 data->param.external.path = p;
997                         }
998                 }
999         } else if (strcmp(command, "WORKSPACE_MENU") == 0) {
1000                 data->type = WSMenuInfo;
1001         } else if (strcmp(command, "WINDOWS_MENU") == 0) {
1002                 data->type = WWindowListInfo;
1003         } else {
1004                 int cmd;
1005
1006                 if (strcmp(command, "ARRANGE_ICONS") == 0) {
1007                         cmd = 0;
1008                 } else if (strcmp(command, "HIDE_OTHERS") == 0) {
1009                         cmd = 1;
1010                 } else if (strcmp(command, "SHOW_ALL") == 0) {
1011                         cmd = 2;
1012                 } else if (strcmp(command, "EXIT") == 0) {
1013                         cmd = 3;
1014                 } else if (strcmp(command, "SHUTDOWN") == 0) {
1015                         cmd = 4;
1016                 } else if (strcmp(command, "RESTART") == 0) {
1017                         if (parameter) {
1018                                 cmd = 6;
1019                         } else {
1020                                 cmd = 5;
1021                         }
1022                 } else if (strcmp(command, "SAVE_SESSION") == 0) {
1023                         cmd = 7;
1024                 } else if (strcmp(command, "CLEAR_SESSION") == 0) {
1025                         cmd = 8;
1026                 } else if (strcmp(command, "REFRESH") == 0) {
1027                         cmd = 9;
1028                 } else if (strcmp(command, "INFO_PANEL") == 0) {
1029                         cmd = 10;
1030                 } else if (strcmp(command, "LEGAL_PANEL") == 0) {
1031                         cmd = 11;
1032                 } else {
1033                         wwarning(_("unknown command '%s' in menu"), command);
1034                         goto error;
1035                 }
1036
1037                 data->type = CommandInfo;
1038
1039                 data->param.command.command = cmd;
1040                 if (shortcut)
1041                         data->param.command.shortcut = wstrdup(shortcut);
1042                 if (parameter)
1043                         data->param.command.parameter = wstrdup(parameter);
1044         }
1045
1046         return data;
1047
1048  error:
1049         wfree(data);
1050
1051         return NULL;
1052 }
1053
1054 static void updateFrameTitle(_Panel * panel, char *title, InfoType type)
1055 {
1056         if (type != NoInfo) {
1057                 char *tmp;
1058
1059                 switch (type) {
1060                 case ExecInfo:
1061                         tmp = wstrconcat(title, _(": Execute Program"));
1062                         break;
1063
1064                 case CommandInfo:
1065                         tmp = wstrconcat(title, _(": Perform Internal Command"));
1066                         break;
1067
1068                 case ExternalInfo:
1069                         tmp = wstrconcat(title, _(": Open a Submenu"));
1070                         break;
1071
1072                 case PipeInfo:
1073                         tmp = wstrconcat(title, _(": Program Generated Submenu"));
1074                         break;
1075
1076                 case DirectoryInfo:
1077                         tmp = wstrconcat(title, _(": Directory Contents Menu"));
1078                         break;
1079
1080                 case WSMenuInfo:
1081                         tmp = wstrconcat(title, _(": Open Workspaces Submenu"));
1082                         break;
1083
1084                 case WWindowListInfo:
1085                         tmp = wstrconcat(title, _(": Open Window List Submenu"));
1086                         break;
1087
1088                 default:
1089                         tmp = NULL;
1090                         break;
1091                 }
1092                 WMSetFrameTitle(panel->optionsF, tmp);
1093                 wfree(tmp);
1094         } else {
1095                 WMSetFrameTitle(panel->optionsF, NULL);
1096         }
1097 }
1098
1099 static void changeInfoType(_Panel * panel, char *title, InfoType type)
1100 {
1101         WMWidget **w;
1102
1103         if (panel->currentType != type) {
1104
1105                 w = panel->sections[panel->currentType];
1106
1107                 while (*w) {
1108                         WMUnmapWidget(*w);
1109                         w++;
1110                 }
1111                 WMUnmapWidget(panel->paramF);
1112                 WMUnmapWidget(panel->quickB);
1113
1114                 w = panel->sections[type];
1115
1116                 while (*w) {
1117                         WMMapWidget(*w);
1118                         w++;
1119                 }
1120         }
1121
1122         updateFrameTitle(panel, title, type);
1123
1124         panel->currentType = type;
1125 }
1126
1127 static void updateMenuItem(_Panel * panel, WEditMenuItem * item, WMWidget * changedWidget)
1128 {
1129         ItemData *data = WGetEditMenuItemData(item);
1130
1131         assert(data != NULL);
1132
1133 #define REPLACE(v, d) if (v) wfree(v); v = d
1134
1135         switch (data->type) {
1136         case ExecInfo:
1137                 if (changedWidget == panel->commandT) {
1138                         REPLACE(data->param.exec.command, WMGetTextFieldText(panel->commandT));
1139                 }
1140                 if (changedWidget == panel->shortT) {
1141                         REPLACE(data->param.exec.shortcut, WMGetTextFieldText(panel->shortT));
1142                 }
1143                 break;
1144
1145         case CommandInfo:
1146                 if (changedWidget == panel->icommandL) {
1147                         data->param.command.command = WMGetListSelectedItemRow(panel->icommandL);
1148                 }
1149                 switch (data->param.command.command) {
1150                 case 3:
1151                 case 4:
1152                         if (changedWidget == panel->quickB) {
1153                                 REPLACE(data->param.command.parameter, WMGetButtonSelected(panel->quickB)
1154                                         ? wstrdup("QUICK") : NULL);
1155                         }
1156                         break;
1157
1158                 case 6:
1159                         if (changedWidget == panel->paramT) {
1160                                 REPLACE(data->param.command.parameter, WMGetTextFieldText(panel->paramT));
1161                         }
1162                         break;
1163                 }
1164                 if (changedWidget == panel->shortT) {
1165                         REPLACE(data->param.command.shortcut, WMGetTextFieldText(panel->shortT));
1166                 }
1167
1168                 break;
1169
1170         case PipeInfo:
1171                 if (changedWidget == panel->pipeT) {
1172                         REPLACE(data->param.pipe.command, WMGetTextFieldText(panel->pipeT));
1173                 }
1174                 if (changedWidget == panel->pipeCacheB) {
1175                         data->param.pipe.cached = WMGetButtonSelected(panel->pipeCacheB);
1176                 }
1177                 break;
1178
1179         case ExternalInfo:
1180                 if (changedWidget == panel->pathT) {
1181                         REPLACE(data->param.external.path, WMGetTextFieldText(panel->pathT));
1182                 }
1183                 break;
1184
1185         case DirectoryInfo:
1186                 if (changedWidget == panel->dpathT) {
1187                         REPLACE(data->param.directory.directory, WMGetTextFieldText(panel->dpathT));
1188                 }
1189                 if (changedWidget == panel->dcommandT) {
1190                         REPLACE(data->param.directory.command, WMGetTextFieldText(panel->dcommandT));
1191                 }
1192                 if (changedWidget == panel->dstripB) {
1193                         data->param.directory.stripExt = WMGetButtonSelected(panel->dstripB);
1194                 }
1195                 break;
1196
1197         default:
1198                 assert(0);
1199                 break;
1200         }
1201
1202 #undef REPLACE
1203 }
1204
1205 static void
1206 menuItemCloned(WEditMenuDelegate * delegate, WEditMenu * menu, WEditMenuItem * origItem, WEditMenuItem * newItem)
1207 {
1208         ItemData *data = WGetEditMenuItemData(origItem);
1209         ItemData *newData;
1210
1211         if (!data)
1212                 return;
1213
1214 #define DUP(s) (s) ? wstrdup(s) : NULL
1215
1216         newData = NEW(ItemData);
1217
1218         newData->type = data->type;
1219
1220         switch (data->type) {
1221         case ExecInfo:
1222                 newData->param.exec.command = DUP(data->param.exec.command);
1223                 newData->param.exec.shortcut = DUP(data->param.exec.shortcut);
1224                 break;
1225
1226         case CommandInfo:
1227                 newData->param.command.command = data->param.command.command;
1228                 newData->param.command.parameter = DUP(data->param.command.parameter);
1229                 newData->param.command.shortcut = DUP(data->param.command.shortcut);
1230                 break;
1231
1232         case PipeInfo:
1233                 newData->param.pipe.command = DUP(data->param.pipe.command);
1234                 newData->param.pipe.cached = data->param.pipe.cached;
1235                 break;
1236
1237         case ExternalInfo:
1238                 newData->param.external.path = DUP(data->param.external.path);
1239                 break;
1240
1241         case DirectoryInfo:
1242                 newData->param.directory.directory = DUP(data->param.directory.directory);
1243                 newData->param.directory.command = DUP(data->param.directory.command);
1244                 newData->param.directory.stripExt = data->param.directory.stripExt;
1245                 break;
1246
1247         default:
1248                 break;
1249         }
1250
1251 #undef DUP
1252
1253         WSetEditMenuItemData(newItem, newData, (WMCallback *) freeItemData);
1254 }
1255
1256 static void menuItemEdited(struct WEditMenuDelegate *delegate, WEditMenu * menu, WEditMenuItem * item)
1257 {
1258         _Panel *panel = (_Panel *) delegate->data;
1259         WEditMenu *submenu;
1260
1261         updateFrameTitle(panel, WGetEditMenuItemTitle(item), panel->currentType);
1262
1263         submenu = WGetEditMenuSubmenu(menu, item);
1264         if (submenu) {
1265                 WSetEditMenuTitle(submenu, WGetEditMenuItemTitle(item));
1266         }
1267 }
1268
1269 static Bool shouldRemoveItem(struct WEditMenuDelegate *delegate, WEditMenu * menu, WEditMenuItem * item)
1270 {
1271         _Panel *panel = (_Panel *) delegate->data;
1272
1273         if (panel->dontAsk)
1274                 return True;
1275
1276         if (WGetEditMenuSubmenu(menu, item)) {
1277                 int res;
1278
1279                 res = WMRunAlertPanel(WMWidgetScreen(menu), NULL,
1280                                       _("Remove Submenu"),
1281                                       _("Removing this item will destroy all items inside\n"
1282                                         "the submenu. Do you really want to do that?"),
1283                                       _("Yes"), _("No"), _("Yes, don't ask again."));
1284                 switch (res) {
1285                 case WAPRDefault:
1286                         return True;
1287                 case WAPRAlternate:
1288                         return False;
1289                 case WAPROther:
1290                         panel->dontAsk = True;
1291                         return True;
1292                 }
1293         }
1294         return True;
1295 }
1296
1297 static void menuItemDeselected(WEditMenuDelegate * delegate, WEditMenu * menu, WEditMenuItem * item)
1298 {
1299         _Panel *panel = (_Panel *) delegate->data;
1300
1301         changeInfoType(panel, NULL, NoInfo);
1302 }
1303
1304 static void menuItemSelected(WEditMenuDelegate * delegate, WEditMenu * menu, WEditMenuItem * item)
1305 {
1306         ItemData *data = WGetEditMenuItemData(item);
1307         _Panel *panel = (_Panel *) delegate->data;
1308
1309         panel->currentItem = item;
1310
1311         if (data) {
1312                 changeInfoType(panel, WGetEditMenuItemTitle(item), data->type);
1313
1314                 switch (data->type) {
1315                 case NoInfo:
1316                         break;
1317
1318                 case ExecInfo:
1319                         WMSetTextFieldText(panel->commandT, data->param.exec.command);
1320                         WMSetTextFieldText(panel->shortT, data->param.exec.shortcut);
1321                         break;
1322
1323                 case CommandInfo:
1324                         WMSelectListItem(panel->icommandL, data->param.command.command);
1325                         WMSetListPosition(panel->icommandL, data->param.command.command - 2);
1326                         WMSetTextFieldText(panel->shortT, data->param.command.shortcut);
1327
1328                         switch (data->param.command.command) {
1329                         case 3:
1330                         case 4:
1331                                 WMSetButtonSelected(panel->quickB, data->param.command.parameter != NULL);
1332                                 break;
1333                         case 6:
1334                                 WMSetTextFieldText(panel->paramT, data->param.command.parameter);
1335                                 break;
1336                         }
1337
1338                         icommandLClicked(panel->icommandL, panel);
1339                         break;
1340
1341                 case PipeInfo:
1342                         WMSetTextFieldText(panel->pipeT, data->param.pipe.command);
1343                         WMSetButtonSelected(panel->pipeCacheB, data->param.pipe.cached);
1344                         break;
1345
1346                 case ExternalInfo:
1347                         WMSetTextFieldText(panel->pathT, data->param.external.path);
1348                         break;
1349
1350                 case DirectoryInfo:
1351                         WMSetTextFieldText(panel->dpathT, data->param.directory.directory);
1352                         WMSetTextFieldText(panel->dcommandT, data->param.directory.command);
1353                         WMSetButtonSelected(panel->dstripB, data->param.directory.stripExt);
1354                         break;
1355
1356                 case WSMenuInfo:
1357                         break;
1358
1359                 default:
1360                         break;
1361                 }
1362         }
1363 }
1364
1365 static WEditMenu *buildSubmenu(_Panel * panel, WMPropList * pl)
1366 {
1367         WMScreen *scr = WMWidgetScreen(panel->parent);
1368         WEditMenu *menu;
1369         WEditMenuItem *item;
1370         char *title;
1371         WMPropList *tp, *bp;
1372         int i;
1373
1374         tp = WMGetFromPLArray(pl, 0);
1375         title = WMGetFromPLString(tp);
1376
1377         menu = WCreateEditMenu(scr, title);
1378
1379         for (i = 1; i < WMGetPropListItemCount(pl); i++) {
1380                 WMPropList *pi;
1381
1382                 pi = WMGetFromPLArray(pl, i);
1383
1384                 tp = WMGetFromPLArray(pi, 0);
1385                 bp = WMGetFromPLArray(pi, 1);
1386
1387                 title = WMGetFromPLString(tp);
1388
1389                 if (!bp || WMIsPLArray(bp)) {   /* it's a submenu */
1390                         WEditMenu *submenu;
1391
1392                         submenu = buildSubmenu(panel, pi);
1393
1394                         item = WAddMenuItemWithTitle(menu, title);
1395
1396                         WSetEditMenuSubmenu(menu, item, submenu);
1397                 } else {
1398                         ItemData *data;
1399
1400                         item = WAddMenuItemWithTitle(menu, title);
1401
1402                         data = parseCommand(pi);
1403
1404                         if (panel->markerPix[data->type])
1405                                 WSetEditMenuItemImage(item, panel->markerPix[data->type]);
1406                         WSetEditMenuItemData(item, data, (WMCallback *) freeItemData);
1407                 }
1408         }
1409
1410         WSetEditMenuAcceptsDrop(menu, True);
1411         WSetEditMenuDelegate(menu, &menuDelegate);
1412
1413         WMRealizeWidget(menu);
1414
1415         return menu;
1416 }
1417
1418 static void buildMenuFromPL(_Panel * panel, WMPropList * pl)
1419 {
1420         panel->menu = buildSubmenu(panel, pl);
1421 }
1422
1423 static WMPropList *getDefaultMenu(_Panel * panel)
1424 {
1425         WMPropList *menu;
1426         char *menuPath, *gspath;
1427
1428         gspath = wusergnusteppath();
1429
1430         menuPath = wmalloc(strlen(gspath) + 128);
1431         sprintf(menuPath, "%s/Library/WindowMaker/plmenu", gspath);
1432
1433         menu = WMReadPropListFromFile(menuPath);
1434
1435         if (!menu) {
1436                 char *buffer, *msg;
1437
1438                 msg = _("Could not open default menu from '%s'");
1439                 buffer = wmalloc(strlen(msg) + strlen(menuPath) + 10);
1440                 sprintf(buffer, msg, menuPath);
1441                 WMRunAlertPanel(WMWidgetScreen(panel->parent), panel->parent,
1442                                 _("Error"), buffer, _("OK"), NULL, NULL);
1443                 wfree(buffer);
1444         }
1445
1446         wfree(menuPath);
1447
1448         return menu;
1449 }
1450
1451 static void showData(_Panel * panel)
1452 {
1453         char *gspath;
1454         char *menuPath;
1455         WMPropList *pmenu;
1456
1457         gspath = wusergnusteppath();
1458
1459         menuPath = wmalloc(strlen(gspath) + 32);
1460         strcpy(menuPath, gspath);
1461         strcat(menuPath, "/Defaults/WMRootMenu");
1462
1463         pmenu = WMReadPropListFromFile(menuPath);
1464
1465         if (!pmenu || !WMIsPLArray(pmenu)) {
1466                 int res;
1467
1468                 res = WMRunAlertPanel(WMWidgetScreen(panel->parent), panel->parent,
1469                                       _("Warning"),
1470                                       _("The menu file format currently in use is not supported\n"
1471                                         "by this tool. Do you want to discard the current menu\n"
1472                                         "to use this tool?"),
1473                                       _("Yes, Discard and Update"), _("No, Keep Current Menu"), NULL);
1474
1475                 if (res == WAPRDefault) {
1476                         pmenu = getDefaultMenu(panel);
1477
1478                         if (!pmenu) {
1479                                 pmenu = WMCreatePLArray(WMCreatePLString("Applications"), NULL);
1480                         }
1481                 } else {
1482                         panel->dontSave = True;
1483                         return;
1484                 }
1485         }
1486
1487         panel->menuPath = menuPath;
1488
1489         buildMenuFromPL(panel, pmenu);
1490
1491         WMReleasePropList(pmenu);
1492 }
1493
1494 static Bool notblank(char *s)
1495 {
1496         if (s) {
1497                 while (*s++) {
1498                         if (!isspace(*s))
1499                                 return True;
1500                 }
1501         }
1502         return False;
1503 }
1504
1505 static WMPropList *processData(char *title, ItemData * data)
1506 {
1507         WMPropList *item;
1508         char *s1;
1509         static WMPropList *pscut = NULL;
1510         static WMPropList *pomenu = NULL;
1511         int i;
1512
1513         if (!pscut) {
1514                 pscut = WMCreatePLString("SHORTCUT");
1515                 pomenu = WMCreatePLString("OPEN_MENU");
1516         }
1517
1518         item = WMCreatePLArray(WMCreatePLString(title), NULL);
1519
1520         switch (data->type) {
1521         case ExecInfo:
1522                 if (data->param.exec.command == NULL)
1523                         return NULL;
1524 #if 1
1525                 if (strpbrk(data->param.exec.command, "&$*|><?`=;")) {
1526                         s1 = "SHEXEC";
1527                 } else {
1528                         s1 = "EXEC";
1529                 }
1530 #else
1531                 s1 = "SHEXEC";
1532 #endif
1533
1534                 if (notblank(data->param.exec.shortcut)) {
1535                         WMAddToPLArray(item, pscut);
1536                         WMAddToPLArray(item, WMCreatePLString(data->param.exec.shortcut));
1537                 }
1538
1539                 WMAddToPLArray(item, WMCreatePLString(s1));
1540                 WMAddToPLArray(item, WMCreatePLString(data->param.exec.command));
1541                 break;
1542
1543         case CommandInfo:
1544                 if (notblank(data->param.command.shortcut)) {
1545                         WMAddToPLArray(item, pscut);
1546                         WMAddToPLArray(item, WMCreatePLString(data->param.command.shortcut));
1547                 }
1548
1549                 i = data->param.command.command;
1550
1551                 WMAddToPLArray(item, WMCreatePLString(commandNames[i]));
1552
1553                 switch (i) {
1554                 case 3:
1555                 case 4:
1556                         if (data->param.command.parameter) {
1557                                 WMAddToPLArray(item, WMCreatePLString(data->param.command.parameter));
1558                         }
1559                         break;
1560
1561                 case 6: /* restart */
1562                         if (data->param.command.parameter) {
1563                                 WMAddToPLArray(item, WMCreatePLString(data->param.command.parameter));
1564                         }
1565                         break;
1566                 }
1567
1568                 break;
1569
1570         case PipeInfo:
1571                 if (!data->param.pipe.command)
1572                         return NULL;
1573                 WMAddToPLArray(item, pomenu);
1574                 if (data->param.pipe.cached)
1575                         s1 = wstrconcat("| ", data->param.pipe.command);
1576                 else
1577                         s1 = wstrconcat("|| ", data->param.pipe.command);
1578                 WMAddToPLArray(item, WMCreatePLString(s1));
1579                 wfree(s1);
1580                 break;
1581
1582         case ExternalInfo:
1583                 if (!data->param.external.path)
1584                         return NULL;
1585                 WMAddToPLArray(item, pomenu);
1586                 WMAddToPLArray(item, WMCreatePLString(data->param.external.path));
1587                 break;
1588
1589         case DirectoryInfo:
1590                 if (!data->param.directory.directory || !data->param.directory.command)
1591                         return NULL;
1592                 {
1593                         int l;
1594                         char *tmp;
1595
1596                         l = strlen(data->param.directory.directory);
1597                         l += strlen(data->param.directory.command);
1598                         l += 32;
1599
1600                         WMAddToPLArray(item, pomenu);
1601
1602                         tmp = wmalloc(l);
1603                         sprintf(tmp, "%s%s WITH %s",
1604                                 data->param.directory.stripExt ? "-noext " : "",
1605                                 data->param.directory.directory, data->param.directory.command);
1606
1607                         WMAddToPLArray(item, WMCreatePLString(tmp));
1608                         wfree(tmp);
1609                 }
1610                 break;
1611
1612         case WSMenuInfo:
1613                 WMAddToPLArray(item, WMCreatePLString("WORKSPACE_MENU"));
1614                 break;
1615
1616         case WWindowListInfo:
1617                 WMAddToPLArray(item, WMCreatePLString("WINDOWS_MENU"));
1618                 break;
1619
1620         default:
1621                 assert(0);
1622                 break;
1623         }
1624
1625         return item;
1626 }
1627
1628 static WMPropList *processSubmenu(WEditMenu * menu)
1629 {
1630         WEditMenuItem *item;
1631         WMPropList *pmenu;
1632         WMPropList *pl;
1633         char *s;
1634         int i;
1635
1636         s = WGetEditMenuTitle(menu);
1637         pl = WMCreatePLString(s);
1638
1639         pmenu = WMCreatePLArray(pl, NULL);
1640
1641         i = 0;
1642         while ((item = WGetEditMenuItem(menu, i++))) {
1643                 WEditMenu *submenu;
1644
1645                 s = WGetEditMenuItemTitle(item);
1646
1647                 submenu = WGetEditMenuSubmenu(menu, item);
1648                 if (submenu) {
1649                         pl = processSubmenu(submenu);
1650                 } else {
1651                         pl = processData(s, WGetEditMenuItemData(item));
1652                 }
1653
1654                 if (!pl)
1655                         continue;
1656
1657                 WMAddToPLArray(pmenu, pl);
1658         }
1659
1660         return pmenu;
1661 }
1662
1663 static WMPropList *buildPLFromMenu(_Panel * panel)
1664 {
1665         WMPropList *menu;
1666
1667         menu = processSubmenu(panel->menu);
1668
1669         return menu;
1670 }
1671
1672 static void storeData(_Panel * panel)
1673 {
1674         WMPropList *menu;
1675
1676         if (panel->dontSave)
1677                 return;
1678
1679         menu = buildPLFromMenu(panel);
1680
1681         WMWritePropListToFile(menu, panel->menuPath, True);
1682
1683         WMReleasePropList(menu);
1684 }
1685
1686 static void showMenus(_Panel * panel)
1687 {
1688         if (panel->menu)
1689                 WEditMenuUnhide(panel->menu);
1690 }
1691
1692 static void hideMenus(_Panel * panel)
1693 {
1694         if (panel->menu)
1695                 WEditMenuHide(panel->menu);
1696 }
1697
1698 Panel *InitMenu(WMScreen * scr, WMWidget * parent)
1699 {
1700         _Panel *panel;
1701
1702         panel = wmalloc(sizeof(_Panel));
1703         memset(panel, 0, sizeof(_Panel));
1704
1705         panel->sectionName = _("Applications Menu Definition");
1706
1707         panel->description = _("Edit the menu for launching applications.");
1708
1709         panel->parent = parent;
1710
1711         panel->callbacks.createWidgets = createPanel;
1712         panel->callbacks.updateDomain = storeData;
1713         panel->callbacks.showPanel = showMenus;
1714         panel->callbacks.hidePanel = hideMenus;
1715
1716         AddSection(panel, ICON_FILE);
1717
1718         return panel;
1719 }