Fixes missing appicons after restarting Window Maker
[wmaker-crm.git] / WPrefs.app / Menu.c
blob54e53faad7b6431e9d610fd5239f8da0b7cf1bd1
1 /* Menu.c- menu definition
3 * WPrefs - Window Maker Preferences Program
5 * Copyright (c) 2000-2003 Alfredo K. Kojima
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.
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.
17 * You should have received a copy of the GNU General Public License along
18 * with this program; if not, write to the Free Software Foundation, Inc.,
19 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
22 #include "WPrefs.h"
23 #include <assert.h>
24 #include <ctype.h>
25 #include <unistd.h>
27 #include <X11/keysym.h>
28 #include <X11/cursorfont.h>
30 #include "editmenu.h"
32 typedef enum {
33 NoInfo,
34 ExecInfo,
35 CommandInfo,
36 ExternalInfo,
37 PipeInfo,
38 PLPipeInfo,
39 DirectoryInfo,
40 WSMenuInfo,
41 WWindowListInfo,
42 LastInfo
43 } InfoType;
45 #define MAX_SECTION_SIZE 4
47 typedef struct _Panel {
48 WMBox *box;
49 char *sectionName;
51 char *description;
53 CallbackRec callbacks;
54 WMWidget *parent;
56 WMFont *boldFont;
57 WMFont *normalFont;
58 WMColor *white;
59 WMColor *gray;
60 WMColor *black;
62 WMPixmap *markerPix[LastInfo];
64 WMPopUpButton *typeP;
66 WMWidget *itemPad[3];
67 int currentPad;
69 WEditMenu *menu;
70 char *menuPath;
72 WMFrame *optionsF;
74 WMFrame *commandF;
75 WMTextField *commandT; /* command to run */
76 WMButton *browseB;
77 WMButton *xtermC; /* inside xterm? */
79 WMFrame *pathF;
80 WMTextField *pathT;
82 WMFrame *pipeF;
83 WMTextField *pipeT;
84 WMButton *pipeCacheB;
86 WMFrame *plpipeF;
87 WMTextField *plpipeT;
88 WMButton *plpipeCacheB;
90 WMFrame *dpathF;
91 WMTextField *dpathT;
93 WMFrame *dcommandF;
94 WMTextField *dcommandT;
96 WMButton *dstripB;
98 WMFrame *shortF;
99 WMTextField *shortT;
100 WMButton *sgrabB;
101 WMButton *sclearB;
103 WMList *icommandL;
105 WMFrame *paramF;
106 WMTextField *paramT;
108 WMButton *quickB;
110 Bool dontAsk; /* whether to comfirm submenu remove */
111 Bool dontSave;
113 Bool capturing;
115 /* about the currently selected item */
116 WEditMenuItem *currentItem;
117 InfoType currentType;
118 WMWidget *sections[LastInfo][MAX_SECTION_SIZE];
119 } _Panel;
121 typedef struct {
122 InfoType type;
123 union {
124 struct {
125 int command;
126 char *parameter;
127 char *shortcut;
128 } command;
129 struct {
130 char *command;
131 char *shortcut;
132 } exec;
133 struct {
134 char *path;
135 } external;
136 struct {
137 char *command;
138 unsigned cached:1;
139 } pipe;
140 struct {
141 char *directory;
142 char *command;
143 unsigned stripExt:1;
144 } directory;
145 } param;
146 } ItemData;
148 static char *commandNames[] = {
149 "ARRANGE_ICONS",
150 "HIDE_OTHERS",
151 "SHOW_ALL",
152 "EXIT",
153 "SHUTDOWN",
154 "RESTART",
155 "RESTART",
156 "SAVE_SESSION",
157 "CLEAR_SESSION",
158 "REFRESH",
159 "INFO_PANEL",
160 "LEGAL_PANEL"
163 #define ICON_FILE "menus"
165 static void showData(_Panel * panel);
167 static void updateMenuItem(_Panel * panel, WEditMenuItem * item, WMWidget * changedWidget);
169 static void menuItemSelected(struct WEditMenuDelegate *delegate, WEditMenu * menu, WEditMenuItem * item);
171 static void menuItemDeselected(struct WEditMenuDelegate *delegate, WEditMenu * menu, WEditMenuItem * item);
173 static void menuItemCloned(struct WEditMenuDelegate *delegate, WEditMenu * menu,
174 WEditMenuItem * origItem, WEditMenuItem * newItem);
176 static void menuItemEdited(struct WEditMenuDelegate *delegate, WEditMenu * menu, WEditMenuItem * item);
178 static Bool shouldRemoveItem(struct WEditMenuDelegate *delegate, WEditMenu * menu, WEditMenuItem * item);
180 static void freeItemData(ItemData * data);
183 static WEditMenuDelegate menuDelegate = {
184 NULL,
185 menuItemCloned,
186 menuItemEdited,
187 menuItemSelected,
188 menuItemDeselected,
189 shouldRemoveItem
192 static void dataChanged(void *self, WMNotification * notif)
194 _Panel *panel = (_Panel *) self;
195 WEditMenuItem *item = panel->currentItem;
196 WMWidget *w = (WMWidget *) WMGetNotificationObject(notif);
198 updateMenuItem(panel, item, w);
201 static void buttonClicked(WMWidget * w, void *data)
203 _Panel *panel = (_Panel *) data;
204 WEditMenuItem *item = panel->currentItem;
206 updateMenuItem(panel, item, w);
209 static void icommandLClicked(WMWidget * w, void *data)
211 _Panel *panel = (_Panel *) data;
212 int cmd;
214 cmd = WMGetListSelectedItemRow(w);
215 if (cmd == 3 || cmd == 4) {
216 WMMapWidget(panel->quickB);
217 } else {
218 WMUnmapWidget(panel->quickB);
220 if (cmd == 6) {
221 WMMapWidget(panel->paramF);
222 } else {
223 WMUnmapWidget(panel->paramF);
227 static void browseForFile(WMWidget * self, void *clientData)
229 _Panel *panel = (_Panel *) clientData;
230 WMFilePanel *filePanel;
231 char *text, *oldprog, *newprog;
233 filePanel = WMGetOpenPanel(WMWidgetScreen(self));
234 text = WMGetTextFieldText(panel->commandT);
236 oldprog = wtrimspace(text);
237 wfree(text);
239 if (oldprog[0] == 0 || oldprog[0] != '/') {
240 wfree(oldprog);
241 oldprog = wstrdup("/");
242 } else {
243 char *ptr = oldprog;
244 while (*ptr && !isspace(*ptr))
245 ptr++;
246 *ptr = 0;
249 WMSetFilePanelCanChooseDirectories(filePanel, False);
251 if (WMRunModalFilePanelForDirectory(filePanel, panel->parent, oldprog, _("Select Program"), NULL) == True) {
252 newprog = WMGetFilePanelFileName(filePanel);
253 WMSetTextFieldText(panel->commandT, newprog);
254 updateMenuItem(panel, panel->currentItem, panel->commandT);
255 wfree(newprog);
258 wfree(oldprog);
261 static void sgrabClicked(WMWidget * w, void *data)
263 _Panel *panel = (_Panel *) data;
264 Display *dpy = WMScreenDisplay(WMWidgetScreen(panel->parent));
265 char *shortcut;
267 if (w == panel->sclearB) {
268 WMSetTextFieldText(panel->shortT, "");
269 updateMenuItem(panel, panel->currentItem, panel->shortT);
270 return;
273 if (!panel->capturing) {
274 panel->capturing = 1;
275 WMSetButtonText(w, _("Cancel"));
276 XGrabKeyboard(dpy, WMWidgetXID(panel->parent), True, GrabModeAsync, GrabModeAsync, CurrentTime);
277 shortcut = capture_shortcut(dpy, &panel->capturing, 0);
278 if (shortcut) {
279 WMSetTextFieldText(panel->shortT, shortcut);
280 updateMenuItem(panel, panel->currentItem, panel->shortT);
281 wfree(shortcut);
284 panel->capturing = 0;
285 WMSetButtonText(w, _("Capture"));
286 XUngrabKeyboard(dpy, CurrentTime);
289 static void changedItemPad(WMWidget * w, void *data)
291 _Panel *panel = (_Panel *) data;
292 int padn = WMGetPopUpButtonSelectedItem(w);
294 WMUnmapWidget(panel->itemPad[panel->currentPad]);
295 WMMapWidget(panel->itemPad[padn]);
297 panel->currentPad = padn;
300 static WEditMenu *putNewSubmenu(WEditMenu * menu, const char *title)
302 WEditMenu *tmp;
303 WEditMenuItem *item;
305 item = WAddMenuItemWithTitle(menu, title);
307 tmp = WCreateEditMenu(WMWidgetScreen(menu), title);
308 WSetEditMenuAcceptsDrop(tmp, True);
309 WSetEditMenuDelegate(tmp, &menuDelegate);
310 WSetEditMenuSubmenu(menu, item, tmp);
312 return tmp;
315 static ItemData *putNewItem(_Panel * panel, WEditMenu * menu, int type, const char *title)
317 WEditMenuItem *item;
318 ItemData *data;
320 item = WAddMenuItemWithTitle(menu, title);
322 data = wmalloc(sizeof(ItemData));
323 data->type = type;
324 WSetEditMenuItemData(item, data, (WMCallback *) freeItemData);
325 WSetEditMenuItemImage(item, panel->markerPix[type]);
327 return data;
330 static WEditMenu *makeFactoryMenu(WMWidget * parent, int width)
332 WEditMenu *pad;
334 pad = WCreateEditMenuPad(parent);
335 WMResizeWidget(pad, width, 10);
336 WSetEditMenuMinSize(pad, wmksize(width, 0));
337 WSetEditMenuMaxSize(pad, wmksize(width, 0));
338 WSetEditMenuSelectable(pad, False);
339 WSetEditMenuEditable(pad, False);
340 WSetEditMenuIsFactory(pad, True);
341 WSetEditMenuDelegate(pad, &menuDelegate);
343 return pad;
346 static void createPanel(_Panel * p)
348 _Panel *panel = (_Panel *) p;
349 WMScreen *scr = WMWidgetScreen(panel->parent);
350 WMColor *black = WMBlackColor(scr);
351 WMColor *white = WMWhiteColor(scr);
352 WMColor *gray = WMGrayColor(scr);
353 WMFont *bold = WMBoldSystemFontOfSize(scr, 12);
354 WMFont *font = WMSystemFontOfSize(scr, 12);
355 WMLabel *label;
356 int width;
358 menuDelegate.data = panel;
360 panel->boldFont = bold;
361 panel->normalFont = font;
363 panel->black = black;
364 panel->white = white;
365 panel->gray = gray;
368 Pixmap pix;
369 Display *dpy = WMScreenDisplay(scr);
370 GC gc;
371 WMPixmap *pixm;
373 pixm = WMCreatePixmap(scr, 7, 7, WMScreenDepth(scr), True);
375 pix = WMGetPixmapXID(pixm);
377 XDrawLine(dpy, pix, WMColorGC(black), 0, 3, 6, 3);
378 XDrawLine(dpy, pix, WMColorGC(black), 3, 0, 3, 6);
380 XDrawLine(dpy, pix, WMColorGC(black), 1, 0, 3, 3);
381 XDrawLine(dpy, pix, WMColorGC(black), 1, 6, 3, 3);
382 XDrawLine(dpy, pix, WMColorGC(black), 0, 0, 0, 6);
385 pix = WMGetPixmapMaskXID(pixm);
387 gc = XCreateGC(dpy, pix, 0, NULL);
389 XSetForeground(dpy, gc, 0);
390 XFillRectangle(dpy, pix, gc, 0, 0, 7, 7);
392 XSetForeground(dpy, gc, 1);
393 XDrawLine(dpy, pix, gc, 0, 3, 6, 3);
394 XDrawLine(dpy, pix, gc, 3, 0, 3, 6);
396 panel->markerPix[ExternalInfo] = pixm;
397 panel->markerPix[PipeInfo] = pixm;
398 panel->markerPix[PLPipeInfo] = pixm;
399 panel->markerPix[DirectoryInfo] = pixm;
400 panel->markerPix[WSMenuInfo] = pixm;
401 panel->markerPix[WWindowListInfo] = pixm;
403 XFreeGC(dpy, gc);
406 panel->box = WMCreateBox(panel->parent);
407 WMSetViewExpandsToParent(WMWidgetView(panel->box), 2, 2, 2, 2);
409 panel->typeP = WMCreatePopUpButton(panel->box);
410 WMResizeWidget(panel->typeP, 150, 20);
411 WMMoveWidget(panel->typeP, 10, 10);
413 WMAddPopUpButtonItem(panel->typeP, _("New Items"));
414 WMAddPopUpButtonItem(panel->typeP, _("Sample Commands"));
415 WMAddPopUpButtonItem(panel->typeP, _("Sample Submenus"));
417 WMSetPopUpButtonAction(panel->typeP, changedItemPad, panel);
419 WMSetPopUpButtonSelectedItem(panel->typeP, 0);
422 WEditMenu *pad;
424 pad = makeFactoryMenu(panel->box, 150);
425 WMMoveWidget(pad, 10, 40);
427 putNewItem(panel, pad, ExecInfo, _("Run Program"));
428 putNewItem(panel, pad, CommandInfo, _("Internal Command"));
429 putNewSubmenu(pad, _("Submenu"));
430 putNewItem(panel, pad, ExternalInfo, _("External Submenu"));
431 putNewItem(panel, pad, PipeInfo, _("Generated Submenu"));
432 putNewItem(panel, pad, PLPipeInfo, _("Generated PL Menu"));
433 putNewItem(panel, pad, DirectoryInfo, _("Directory Contents"));
434 putNewItem(panel, pad, WSMenuInfo, _("Workspace Menu"));
435 putNewItem(panel, pad, WWindowListInfo, _("Window List Menu"));
437 panel->itemPad[0] = pad;
441 WEditMenu *pad;
442 ItemData *data;
443 WMScrollView *sview;
445 sview = WMCreateScrollView(panel->box);
446 WMResizeWidget(sview, 150, 180);
447 WMMoveWidget(sview, 10, 40);
448 WMSetScrollViewHasVerticalScroller(sview, True);
450 pad = makeFactoryMenu(panel->box, 130);
452 WMSetScrollViewContentView(sview, WMWidgetView(pad));
454 data = putNewItem(panel, pad, ExecInfo, _("XTerm"));
455 data->param.exec.command = "xterm -sb -sl 2000 -bg black -fg white";
457 data = putNewItem(panel, pad, ExecInfo, _("rxvt"));
458 data->param.exec.command = "rxvt";
460 data = putNewItem(panel, pad, ExecInfo, _("ETerm"));
461 data->param.exec.command = "eterm";
463 data = putNewItem(panel, pad, ExecInfo, _("Run..."));
464 data->param.exec.command = _("%A(Run,Type command to run)");
466 data = putNewItem(panel, pad, ExecInfo, _("Firefox"));
467 data->param.exec.command = "firefox";
469 data = putNewItem(panel, pad, ExecInfo, _("gimp"));
470 data->param.exec.command = "gimp";
472 data = putNewItem(panel, pad, ExecInfo, _("epic"));
473 data->param.exec.command = "xterm -e epic";
475 data = putNewItem(panel, pad, ExecInfo, _("ee"));
476 data->param.exec.command = "ee";
478 data = putNewItem(panel, pad, ExecInfo, _("xv"));
479 data->param.exec.command = "xv";
481 data = putNewItem(panel, pad, ExecInfo, _("Evince"));
482 data->param.exec.command = "evince";
484 data = putNewItem(panel, pad, ExecInfo, _("ghostview"));
485 data->param.exec.command = "gv";
487 data = putNewItem(panel, pad, CommandInfo, _("Exit Window Maker"));
488 data->param.command.command = 3;
490 WMMapWidget(pad);
492 panel->itemPad[1] = sview;
496 WEditMenu *pad, *smenu;
497 ItemData *data;
498 WMScrollView *sview;
500 sview = WMCreateScrollView(panel->box);
501 WMResizeWidget(sview, 150, 180);
502 WMMoveWidget(sview, 10, 40);
503 WMSetScrollViewHasVerticalScroller(sview, True);
505 pad = makeFactoryMenu(panel->box, 130);
507 WMSetScrollViewContentView(sview, WMWidgetView(pad));
509 data = putNewItem(panel, pad, ExternalInfo, _("Debian Menu"));
510 data->param.pipe.command = "/etc/GNUstep/Defaults/menu.hook";
512 data = putNewItem(panel, pad, PipeInfo, _("RedHat Menu"));
513 data->param.pipe.command = "wmconfig --output wmaker";
515 data = putNewItem(panel, pad, PipeInfo, _("Menu Conectiva"));
516 data->param.pipe.command = "wmconfig --output wmaker";
518 data = putNewItem(panel, pad, DirectoryInfo, _("Themes"));
519 data->param.directory.command = "setstyle";
520 data->param.directory.directory =
521 "/usr/share/WindowMaker/Themes /usr/local/share/WindowMaker/Themes $HOME/GNUstep/Library/WindowMaker/Themes";
522 data->param.directory.stripExt = 1;
524 data = putNewItem(panel, pad, DirectoryInfo, _("Bg Images (scale)"));
525 data->param.directory.command = "wmsetbg -u -s";
526 data->param.directory.directory =
527 "/opt/kde2/share/wallpapers /usr/share/WindowMaker/Backgrounds $HOME/GNUstep/Library/WindowMaker/Backgrounds";
528 data->param.directory.stripExt = 1;
530 data = putNewItem(panel, pad, DirectoryInfo, _("Bg Images (tile)"));
531 data->param.directory.command = "wmsetbg -u -t";
532 data->param.directory.directory =
533 "/opt/kde2/share/wallpapers /usr/share/WindowMaker/Backgrounds $HOME/GNUstep/Library/WindowMaker/Backgrounds";
534 data->param.directory.stripExt = 1;
536 smenu = putNewSubmenu(pad, _("Assorted XTerms"));
538 data = putNewItem(panel, smenu, ExecInfo, _("XTerm Yellow on Blue"));
539 data->param.exec.command = "xterm -sb -sl 2000 -bg midnightblue -fg yellow";
541 data = putNewItem(panel, smenu, ExecInfo, _("XTerm White on Black"));
542 data->param.exec.command = "xterm -sb -sl 2000 -bg black -fg white";
544 data = putNewItem(panel, smenu, ExecInfo, _("XTerm Black on White"));
545 data->param.exec.command = "xterm -sb -sl 2000 -bg white -fg black";
547 data = putNewItem(panel, smenu, ExecInfo, _("XTerm Black on Beige"));
548 data->param.exec.command = "xterm -sb -sl 2000 -bg '#bbbb99' -fg black";
550 data = putNewItem(panel, smenu, ExecInfo, _("XTerm White on Green"));
551 data->param.exec.command = "xterm -sb -sl 2000 -bg '#228822' -fg white";
553 data = putNewItem(panel, smenu, ExecInfo, _("XTerm White on Olive"));
554 data->param.exec.command = "xterm -sb -sl 2000 -bg '#335533' -fg white";
556 data = putNewItem(panel, smenu, ExecInfo, _("XTerm Blue on Blue"));
557 data->param.exec.command = "xterm -sb -sl 2000 -bg '#112244' -fg '#88aabb'";
559 data = putNewItem(panel, smenu, ExecInfo, _("XTerm BIG FONTS"));
560 data->param.exec.command = "xterm -sb -sl 2000 -bg black -fg white -fn 10x20";
562 WMMapWidget(pad);
564 panel->itemPad[2] = sview;
567 width = FRAME_WIDTH - 20 - 150 - 10 - 2;
569 panel->optionsF = WMCreateFrame(panel->box);
570 WMResizeWidget(panel->optionsF, width, FRAME_HEIGHT - 15);
571 WMMoveWidget(panel->optionsF, 10 + 150 + 10, 5);
573 width -= 20;
575 /* command */
577 panel->commandF = WMCreateFrame(panel->optionsF);
578 WMResizeWidget(panel->commandF, width, 50);
579 WMMoveWidget(panel->commandF, 10, 20);
580 WMSetFrameTitle(panel->commandF, _("Program to Run"));
581 WMSetFrameTitlePosition(panel->commandF, WTPAtTop);
583 panel->commandT = WMCreateTextField(panel->commandF);
584 WMResizeWidget(panel->commandT, width - 95, 20);
585 WMMoveWidget(panel->commandT, 10, 20);
587 panel->browseB = WMCreateCommandButton(panel->commandF);
588 WMResizeWidget(panel->browseB, 70, 24);
589 WMMoveWidget(panel->browseB, width - 80, 18);
590 WMSetButtonText(panel->browseB, _("Browse"));
591 WMSetButtonAction(panel->browseB, browseForFile, panel);
593 WMAddNotificationObserver(dataChanged, panel, WMTextDidChangeNotification, panel->commandT);
595 #if 0
596 panel->xtermC = WMCreateSwitchButton(panel->commandF);
597 WMResizeWidget(panel->xtermC, width - 20, 20);
598 WMMoveWidget(panel->xtermC, 10, 50);
599 WMSetButtonText(panel->xtermC, _("Run the program inside a Xterm"));
600 #endif
601 WMMapSubwidgets(panel->commandF);
603 /* path */
605 panel->pathF = WMCreateFrame(panel->optionsF);
606 WMResizeWidget(panel->pathF, width, 150);
607 WMMoveWidget(panel->pathF, 10, 40);
608 WMSetFrameTitle(panel->pathF, _("Path for Menu"));
610 panel->pathT = WMCreateTextField(panel->pathF);
611 WMResizeWidget(panel->pathT, width - 20, 20);
612 WMMoveWidget(panel->pathT, 10, 20);
614 WMAddNotificationObserver(dataChanged, panel, WMTextDidChangeNotification, panel->pathT);
616 label = WMCreateLabel(panel->pathF);
617 WMResizeWidget(label, width - 20, 80);
618 WMMoveWidget(label, 10, 50);
619 WMSetLabelText(label, _("Enter the path for a file containing a menu\n"
620 "or a list of directories with the programs you\n"
621 "want to have listed in the menu. Ex:\n"
622 "~/GNUstep/Library/WindowMaker/menu\n" "or\n" "/usr/bin ~/xbin"));
624 WMMapSubwidgets(panel->pathF);
626 /* pipe */
628 panel->pipeF = WMCreateFrame(panel->optionsF);
629 WMResizeWidget(panel->pipeF, width, 155);
630 WMMoveWidget(panel->pipeF, 10, 30);
631 WMSetFrameTitle(panel->pipeF, _("Command"));
633 panel->pipeT = WMCreateTextField(panel->pipeF);
634 WMResizeWidget(panel->pipeT, width - 20, 20);
635 WMMoveWidget(panel->pipeT, 10, 20);
637 WMAddNotificationObserver(dataChanged, panel, WMTextDidChangeNotification, panel->pipeT);
639 label = WMCreateLabel(panel->pipeF);
640 WMResizeWidget(label, width - 20, 40);
641 WMMoveWidget(label, 10, 50);
642 WMSetLabelText(label, _("Enter a command that outputs a menu\n" "definition to stdout when invoked."));
644 panel->pipeCacheB = WMCreateSwitchButton(panel->pipeF);
645 WMResizeWidget(panel->pipeCacheB, width - 20, 40);
646 WMMoveWidget(panel->pipeCacheB, 10, 110);
647 WMSetButtonText(panel->pipeCacheB, _("Cache menu contents after opening for\n" "the first time"));
649 WMMapSubwidgets(panel->pipeF);
651 /* proplist pipe */
653 panel->plpipeF = WMCreateFrame(panel->optionsF);
654 WMResizeWidget(panel->plpipeF, width, 155);
655 WMMoveWidget(panel->plpipeF, 10, 30);
656 WMSetFrameTitle(panel->plpipeF, _("Command"));
658 panel->plpipeT = WMCreateTextField(panel->plpipeF);
659 WMResizeWidget(panel->plpipeT, width - 20, 20);
660 WMMoveWidget(panel->plpipeT, 10, 20);
662 WMAddNotificationObserver(dataChanged, panel, WMTextDidChangeNotification, panel->plpipeT);
664 label = WMCreateLabel(panel->plpipeF);
665 WMResizeWidget(label, width - 20, 40);
666 WMMoveWidget(label, 10, 50);
667 WMSetLabelText(label, _("Enter a command that outputs a proplist menu\n" "definition to stdout when invoked."));
669 panel->plpipeCacheB = WMCreateSwitchButton(panel->plpipeF);
670 WMResizeWidget(panel->plpipeCacheB, width - 20, 40);
671 WMMoveWidget(panel->plpipeCacheB, 10, 110);
672 WMSetButtonText(panel->plpipeCacheB, _("Cache menu contents after opening for\n" "the first time"));
674 WMMapSubwidgets(panel->plpipeF);
676 /* directory menu */
678 panel->dcommandF = WMCreateFrame(panel->optionsF);
679 WMResizeWidget(panel->dcommandF, width, 90);
680 WMMoveWidget(panel->dcommandF, 10, 25);
681 WMSetFrameTitle(panel->dcommandF, _("Command to Open Files"));
683 panel->dcommandT = WMCreateTextField(panel->dcommandF);
684 WMResizeWidget(panel->dcommandT, width - 20, 20);
685 WMMoveWidget(panel->dcommandT, 10, 20);
687 WMAddNotificationObserver(dataChanged, panel, WMTextDidChangeNotification, panel->dcommandT);
689 label = WMCreateLabel(panel->dcommandF);
690 WMResizeWidget(label, width - 20, 45);
691 WMMoveWidget(label, 10, 40);
692 WMSetLabelText(label, _("Enter the command you want to use to open the\n"
693 "files in the directories listed below."));
695 WMMapSubwidgets(panel->dcommandF);
697 panel->dpathF = WMCreateFrame(panel->optionsF);
698 WMResizeWidget(panel->dpathF, width, 80);
699 WMMoveWidget(panel->dpathF, 10, 125);
700 WMSetFrameTitle(panel->dpathF, _("Directories with Files"));
702 panel->dpathT = WMCreateTextField(panel->dpathF);
703 WMResizeWidget(panel->dpathT, width - 20, 20);
704 WMMoveWidget(panel->dpathT, 10, 20);
706 WMAddNotificationObserver(dataChanged, panel, WMTextDidChangeNotification, panel->dpathT);
708 panel->dstripB = WMCreateSwitchButton(panel->dpathF);
709 WMResizeWidget(panel->dstripB, width - 20, 20);
710 WMMoveWidget(panel->dstripB, 10, 50);
711 WMSetButtonText(panel->dstripB, _("Strip extensions from file names"));
713 WMSetButtonAction(panel->dstripB, buttonClicked, panel);
715 WMMapSubwidgets(panel->dpathF);
717 /* shortcut */
719 panel->shortF = WMCreateFrame(panel->optionsF);
720 WMResizeWidget(panel->shortF, width, 50);
721 WMMoveWidget(panel->shortF, 10, 160);
722 WMSetFrameTitle(panel->shortF, _("Keyboard Shortcut"));
724 panel->shortT = WMCreateTextField(panel->shortF);
725 WMResizeWidget(panel->shortT, width - 20 - 150, 20);
726 WMMoveWidget(panel->shortT, 10, 20);
728 WMAddNotificationObserver(dataChanged, panel, WMTextDidChangeNotification, panel->shortT);
730 panel->sgrabB = WMCreateCommandButton(panel->shortF);
731 WMResizeWidget(panel->sgrabB, 70, 24);
732 WMMoveWidget(panel->sgrabB, width - 80, 18);
733 WMSetButtonText(panel->sgrabB, _("Capture"));
734 WMSetButtonAction(panel->sgrabB, sgrabClicked, panel);
736 panel->sclearB = WMCreateCommandButton(panel->shortF);
737 WMResizeWidget(panel->sclearB, 70, 24);
738 WMMoveWidget(panel->sclearB, width - 155, 18);
739 WMSetButtonText(panel->sclearB, _("Clear"));
740 WMSetButtonAction(panel->sclearB, sgrabClicked, panel);
742 WMMapSubwidgets(panel->shortF);
744 /* internal command */
746 panel->icommandL = WMCreateList(panel->optionsF);
747 WMResizeWidget(panel->icommandL, width, 80);
748 WMMoveWidget(panel->icommandL, 10, 20);
750 WMSetListAction(panel->icommandL, icommandLClicked, panel);
752 WMAddNotificationObserver(dataChanged, panel, WMListSelectionDidChangeNotification, panel->icommandL);
754 WMInsertListItem(panel->icommandL, 0, _("Arrange Icons"));
755 WMInsertListItem(panel->icommandL, 1, _("Hide All Windows Except For The Focused One"));
756 WMInsertListItem(panel->icommandL, 2, _("Show All Windows"));
758 WMInsertListItem(panel->icommandL, 3, _("Exit Window Maker"));
759 WMInsertListItem(panel->icommandL, 4, _("Exit X Session"));
760 WMInsertListItem(panel->icommandL, 5, _("Restart Window Maker"));
761 WMInsertListItem(panel->icommandL, 6, _("Start Another Window Manager : ("));
763 WMInsertListItem(panel->icommandL, 7, _("Save Current Session"));
764 WMInsertListItem(panel->icommandL, 8, _("Clear Saved Session"));
765 WMInsertListItem(panel->icommandL, 9, _("Refresh Screen"));
766 WMInsertListItem(panel->icommandL, 10, _("Open Info Panel"));
767 WMInsertListItem(panel->icommandL, 11, _("Open Copyright Panel"));
769 panel->paramF = WMCreateFrame(panel->optionsF);
770 WMResizeWidget(panel->paramF, width, 50);
771 WMMoveWidget(panel->paramF, 10, 105);
772 WMSetFrameTitle(panel->paramF, _("Window Manager to Start"));
774 panel->paramT = WMCreateTextField(panel->paramF);
775 WMResizeWidget(panel->paramT, width - 20, 20);
776 WMMoveWidget(panel->paramT, 10, 20);
778 WMAddNotificationObserver(dataChanged, panel, WMTextDidChangeNotification, panel->paramT);
780 WMMapSubwidgets(panel->paramF);
782 panel->quickB = WMCreateSwitchButton(panel->optionsF);
783 WMResizeWidget(panel->quickB, width, 20);
784 WMMoveWidget(panel->quickB, 10, 120);
785 WMSetButtonText(panel->quickB, _("Do not confirm action."));
786 WMSetButtonAction(panel->quickB, buttonClicked, panel);
788 label = WMCreateLabel(panel->optionsF);
789 WMResizeWidget(label, width + 5, FRAME_HEIGHT - 50);
790 WMMoveWidget(label, 7, 20);
791 WMSetLabelText(label,
792 _("Instructions:\n\n"
793 " - drag items from the left to the menu to add new items\n"
794 " - drag items out of the menu to remove items\n"
795 " - drag items in menu to change their position\n"
796 " - drag items with Control pressed to copy them\n"
797 " - double click in a menu item to change the label\n"
798 " - click on a menu item to change related information"));
799 WMMapWidget(label);
801 WMRealizeWidget(panel->box);
802 WMMapSubwidgets(panel->box);
803 WMMapWidget(panel->box);
806 int i;
807 for (i = 0; i < wlengthof(panel->itemPad); i++)
808 WMUnmapWidget(panel->itemPad[i]);
810 changedItemPad(panel->typeP, panel);
812 panel->sections[NoInfo][0] = label;
814 panel->sections[ExecInfo][0] = panel->commandF;
815 panel->sections[ExecInfo][1] = panel->shortF;
817 panel->sections[CommandInfo][0] = panel->icommandL;
818 panel->sections[CommandInfo][1] = panel->shortF;
820 panel->sections[ExternalInfo][0] = panel->pathF;
822 panel->sections[PipeInfo][0] = panel->pipeF;
824 panel->sections[PLPipeInfo][0] = panel->plpipeF;
826 panel->sections[DirectoryInfo][0] = panel->dpathF;
827 panel->sections[DirectoryInfo][1] = panel->dcommandF;
829 panel->currentType = NoInfo;
831 showData(panel);
834 WMPoint pos;
836 pos = WMGetViewScreenPosition(WMWidgetView(panel->box));
838 if (pos.x < 200) {
839 pos.x += FRAME_WIDTH + 20;
840 } else {
841 pos.x = 10;
844 pos.y = WMAX(pos.y - 100, 0);
846 if (panel->menu)
847 WEditMenuShowAt(panel->menu, pos.x, pos.y);
851 static void freeItemData(ItemData * data)
853 #define CFREE(d) if (d) wfree(d)
855 /* TODO */
856 switch (data->type) {
857 case CommandInfo:
858 CFREE(data->param.command.parameter);
859 CFREE(data->param.command.shortcut);
860 break;
862 case ExecInfo:
863 CFREE(data->param.exec.command);
864 CFREE(data->param.exec.shortcut);
865 break;
867 case PipeInfo:
868 CFREE(data->param.pipe.command);
869 break;
871 case PLPipeInfo:
872 CFREE(data->param.pipe.command);
873 break;
875 case ExternalInfo:
876 CFREE(data->param.external.path);
877 break;
879 case DirectoryInfo:
880 CFREE(data->param.directory.command);
881 CFREE(data->param.directory.directory);
882 break;
884 default:
885 break;
888 wfree(data);
889 #undef CFREE
892 static ItemData *parseCommand(WMPropList * item)
894 ItemData *data = wmalloc(sizeof(ItemData));
895 WMPropList *p;
896 char *command = NULL;
897 char *parameter = NULL;
898 char *shortcut = NULL;
899 int i = 1;
901 p = WMGetFromPLArray(item, i++);
902 command = WMGetFromPLString(p);
903 if (strcmp(command, "SHORTCUT") == 0) {
904 p = WMGetFromPLArray(item, i++);
905 shortcut = WMGetFromPLString(p);
906 p = WMGetFromPLArray(item, i++);
907 command = WMGetFromPLString(p);
909 p = WMGetFromPLArray(item, i++);
910 if (p)
911 parameter = WMGetFromPLString(p);
913 if (strcmp(command, "EXEC") == 0 || strcmp(command, "SHEXEC") == 0) {
915 data->type = ExecInfo;
917 data->param.exec.command = wstrdup(parameter);
918 if (shortcut)
919 data->param.exec.shortcut = wstrdup(shortcut);
921 } else if (strcmp(command, "OPEN_MENU") == 0) {
922 char *p;
924 * dir menu, menu file
925 * dir WITH
926 * |pipe
928 p = parameter;
929 while (isspace(*p) && *p)
930 p++;
931 if (*p == '|') {
932 if (*(p + 1) == '|') {
933 p++;
934 data->param.pipe.cached = 0;
935 } else {
936 data->param.pipe.cached = 1;
938 data->type = PipeInfo;
939 data->param.pipe.command = wtrimspace(p + 1);
940 } else {
941 char *s;
943 p = wstrdup(p);
945 s = strstr(p, "WITH");
946 if (s) {
947 char **tokens;
948 char **ctokens;
949 int tokn;
950 int i, j;
952 data->type = DirectoryInfo;
954 *s = '\0';
955 s += 5;
956 while (*s && isspace(*s))
957 s++;
958 data->param.directory.command = wstrdup(s);
960 wtokensplit(p, &tokens, &tokn);
961 wfree(p);
963 ctokens = wmalloc(sizeof(char *) * tokn);
965 for (i = 0, j = 0; i < tokn; i++) {
966 if (strcmp(tokens[i], "-noext") == 0) {
967 data->param.directory.stripExt = 1;
968 } else {
969 ctokens[j++] = tokens[i];
972 data->param.directory.directory = wtokenjoin(ctokens, j);
973 wfree(ctokens);
975 wtokenfree(tokens, tokn);
976 } else {
977 data->type = ExternalInfo;
978 data->param.external.path = p;
981 } else if (strcmp(command, "OPEN_PLMENU") == 0) {
982 char *p;
984 p = parameter;
985 while (isspace(*p) && *p)
986 p++;
987 if (*p == '|') {
988 if (*(p + 1) == '|') {
989 p++;
990 data->param.pipe.cached = 0;
991 } else {
992 data->param.pipe.cached = 1;
994 data->type = PLPipeInfo;
995 data->param.pipe.command = wtrimspace(p + 1);
997 } else if (strcmp(command, "WORKSPACE_MENU") == 0) {
998 data->type = WSMenuInfo;
999 } else if (strcmp(command, "WINDOWS_MENU") == 0) {
1000 data->type = WWindowListInfo;
1001 } else {
1002 int cmd;
1004 if (strcmp(command, "ARRANGE_ICONS") == 0) {
1005 cmd = 0;
1006 } else if (strcmp(command, "HIDE_OTHERS") == 0) {
1007 cmd = 1;
1008 } else if (strcmp(command, "SHOW_ALL") == 0) {
1009 cmd = 2;
1010 } else if (strcmp(command, "EXIT") == 0) {
1011 cmd = 3;
1012 } else if (strcmp(command, "SHUTDOWN") == 0) {
1013 cmd = 4;
1014 } else if (strcmp(command, "RESTART") == 0) {
1015 if (parameter) {
1016 cmd = 6;
1017 } else {
1018 cmd = 5;
1020 } else if (strcmp(command, "SAVE_SESSION") == 0) {
1021 cmd = 7;
1022 } else if (strcmp(command, "CLEAR_SESSION") == 0) {
1023 cmd = 8;
1024 } else if (strcmp(command, "REFRESH") == 0) {
1025 cmd = 9;
1026 } else if (strcmp(command, "INFO_PANEL") == 0) {
1027 cmd = 10;
1028 } else if (strcmp(command, "LEGAL_PANEL") == 0) {
1029 cmd = 11;
1030 } else {
1031 wwarning(_("unknown command '%s' in menu"), command);
1032 wfree(data);
1033 return NULL;
1036 data->type = CommandInfo;
1038 data->param.command.command = cmd;
1039 if (shortcut)
1040 data->param.command.shortcut = wstrdup(shortcut);
1041 if (parameter)
1042 data->param.command.parameter = wstrdup(parameter);
1045 return data;
1048 static void updateFrameTitle(_Panel * panel, const char *title, InfoType type)
1050 if (type != NoInfo) {
1051 char *tmp;
1053 switch (type) {
1054 case ExecInfo:
1055 tmp = wstrconcat(title, _(": Execute Program"));
1056 break;
1058 case CommandInfo:
1059 tmp = wstrconcat(title, _(": Perform Internal Command"));
1060 break;
1062 case ExternalInfo:
1063 tmp = wstrconcat(title, _(": Open a Submenu"));
1064 break;
1066 case PipeInfo:
1067 tmp = wstrconcat(title, _(": Program Generated Submenu"));
1068 break;
1070 case PLPipeInfo:
1071 tmp = wstrconcat(title, _(": Program Generated Proplist Submenu"));
1072 break;
1074 case DirectoryInfo:
1075 tmp = wstrconcat(title, _(": Directory Contents Menu"));
1076 break;
1078 case WSMenuInfo:
1079 tmp = wstrconcat(title, _(": Open Workspaces Submenu"));
1080 break;
1082 case WWindowListInfo:
1083 tmp = wstrconcat(title, _(": Open Window List Submenu"));
1084 break;
1086 default:
1087 tmp = NULL;
1088 break;
1090 WMSetFrameTitle(panel->optionsF, tmp);
1091 wfree(tmp);
1092 } else {
1093 WMSetFrameTitle(panel->optionsF, NULL);
1097 static void changeInfoType(_Panel * panel, const char *title, InfoType type)
1099 WMWidget **w;
1101 if (panel->currentType != type) {
1103 w = panel->sections[panel->currentType];
1105 while (*w) {
1106 WMUnmapWidget(*w);
1107 w++;
1109 WMUnmapWidget(panel->paramF);
1110 WMUnmapWidget(panel->quickB);
1112 w = panel->sections[type];
1114 while (*w) {
1115 WMMapWidget(*w);
1116 w++;
1120 updateFrameTitle(panel, title, type);
1122 panel->currentType = type;
1125 static void updateMenuItem(_Panel * panel, WEditMenuItem * item, WMWidget * changedWidget)
1127 ItemData *data = WGetEditMenuItemData(item);
1129 assert(data != NULL);
1131 #define REPLACE(v, d) if (v) wfree(v); v = d
1133 switch (data->type) {
1134 case ExecInfo:
1135 if (changedWidget == panel->commandT) {
1136 REPLACE(data->param.exec.command, WMGetTextFieldText(panel->commandT));
1138 if (changedWidget == panel->shortT) {
1139 REPLACE(data->param.exec.shortcut, WMGetTextFieldText(panel->shortT));
1141 break;
1143 case CommandInfo:
1144 if (changedWidget == panel->icommandL) {
1145 data->param.command.command = WMGetListSelectedItemRow(panel->icommandL);
1147 switch (data->param.command.command) {
1148 case 3:
1149 case 4:
1150 if (changedWidget == panel->quickB) {
1151 REPLACE(data->param.command.parameter, WMGetButtonSelected(panel->quickB)
1152 ? wstrdup("QUICK") : NULL);
1154 break;
1156 case 6:
1157 if (changedWidget == panel->paramT) {
1158 REPLACE(data->param.command.parameter, WMGetTextFieldText(panel->paramT));
1160 break;
1162 if (changedWidget == panel->shortT) {
1163 REPLACE(data->param.command.shortcut, WMGetTextFieldText(panel->shortT));
1166 break;
1168 case PipeInfo:
1169 if (changedWidget == panel->pipeT) {
1170 REPLACE(data->param.pipe.command, WMGetTextFieldText(panel->pipeT));
1172 if (changedWidget == panel->pipeCacheB) {
1173 data->param.pipe.cached = WMGetButtonSelected(panel->pipeCacheB);
1175 break;
1177 case PLPipeInfo:
1178 if (changedWidget == panel->plpipeT) {
1179 REPLACE(data->param.pipe.command, WMGetTextFieldText(panel->plpipeT));
1181 if (changedWidget == panel->plpipeCacheB) {
1182 data->param.pipe.cached = WMGetButtonSelected(panel->plpipeCacheB);
1184 break;
1186 case ExternalInfo:
1187 if (changedWidget == panel->pathT) {
1188 REPLACE(data->param.external.path, WMGetTextFieldText(panel->pathT));
1190 break;
1192 case DirectoryInfo:
1193 if (changedWidget == panel->dpathT) {
1194 REPLACE(data->param.directory.directory, WMGetTextFieldText(panel->dpathT));
1196 if (changedWidget == panel->dcommandT) {
1197 REPLACE(data->param.directory.command, WMGetTextFieldText(panel->dcommandT));
1199 if (changedWidget == panel->dstripB) {
1200 data->param.directory.stripExt = WMGetButtonSelected(panel->dstripB);
1202 break;
1204 default:
1205 assert(0);
1206 break;
1209 #undef REPLACE
1212 static void
1213 menuItemCloned(WEditMenuDelegate * delegate, WEditMenu * menu, WEditMenuItem * origItem, WEditMenuItem * newItem)
1215 ItemData *data = WGetEditMenuItemData(origItem);
1216 ItemData *newData;
1218 /* Parameter not used, but tell the compiler that it is ok */
1219 (void) delegate;
1220 (void) menu;
1222 if (!data)
1223 return;
1225 #define DUP(s) (s) ? wstrdup(s) : NULL
1227 newData = wmalloc(sizeof(ItemData));
1229 newData->type = data->type;
1231 switch (data->type) {
1232 case ExecInfo:
1233 newData->param.exec.command = DUP(data->param.exec.command);
1234 newData->param.exec.shortcut = DUP(data->param.exec.shortcut);
1235 break;
1237 case CommandInfo:
1238 newData->param.command.command = data->param.command.command;
1239 newData->param.command.parameter = DUP(data->param.command.parameter);
1240 newData->param.command.shortcut = DUP(data->param.command.shortcut);
1241 break;
1243 case PipeInfo:
1244 newData->param.pipe.command = DUP(data->param.pipe.command);
1245 newData->param.pipe.cached = data->param.pipe.cached;
1246 break;
1248 case PLPipeInfo:
1249 newData->param.pipe.command = DUP(data->param.pipe.command);
1250 newData->param.pipe.cached = data->param.pipe.cached;
1251 break;
1253 case ExternalInfo:
1254 newData->param.external.path = DUP(data->param.external.path);
1255 break;
1257 case DirectoryInfo:
1258 newData->param.directory.directory = DUP(data->param.directory.directory);
1259 newData->param.directory.command = DUP(data->param.directory.command);
1260 newData->param.directory.stripExt = data->param.directory.stripExt;
1261 break;
1263 default:
1264 break;
1267 #undef DUP
1269 WSetEditMenuItemData(newItem, newData, (WMCallback *) freeItemData);
1272 static void menuItemEdited(struct WEditMenuDelegate *delegate, WEditMenu * menu, WEditMenuItem * item)
1274 _Panel *panel = (_Panel *) delegate->data;
1275 WEditMenu *submenu;
1277 /* Parameter not used, but tell the compiler it is ok */
1278 (void) menu;
1280 updateFrameTitle(panel, WGetEditMenuItemTitle(item), panel->currentType);
1282 submenu = WGetEditMenuSubmenu(item);
1283 if (submenu) {
1284 WSetEditMenuTitle(submenu, WGetEditMenuItemTitle(item));
1288 static Bool shouldRemoveItem(struct WEditMenuDelegate *delegate, WEditMenu * menu, WEditMenuItem * item)
1290 _Panel *panel = (_Panel *) delegate->data;
1292 if (panel->dontAsk)
1293 return True;
1295 if (WGetEditMenuSubmenu(item)) {
1296 int res;
1298 res = WMRunAlertPanel(WMWidgetScreen(menu), NULL,
1299 _("Remove Submenu"),
1300 _("Removing this item will destroy all items inside\n"
1301 "the submenu. Do you really want to do that?"),
1302 _("Yes"), _("No"), _("Yes, don't ask again"));
1303 switch (res) {
1304 case WAPRDefault:
1305 return True;
1306 case WAPRAlternate:
1307 return False;
1308 case WAPROther:
1309 panel->dontAsk = True;
1310 return True;
1313 return True;
1316 static void menuItemDeselected(WEditMenuDelegate * delegate, WEditMenu * menu, WEditMenuItem * item)
1318 _Panel *panel = (_Panel *) delegate->data;
1320 /* Parameter not used, but tell the compiler that it is ok */
1321 (void) menu;
1322 (void) item;
1324 changeInfoType(panel, NULL, NoInfo);
1327 static void menuItemSelected(WEditMenuDelegate * delegate, WEditMenu * menu, WEditMenuItem * item)
1329 ItemData *data = WGetEditMenuItemData(item);
1330 _Panel *panel = (_Panel *) delegate->data;
1332 /* Parameter not used, but tell the compiler that it is ok */
1333 (void) menu;
1335 panel->currentItem = item;
1337 if (data) {
1338 changeInfoType(panel, WGetEditMenuItemTitle(item), data->type);
1340 switch (data->type) {
1341 case NoInfo:
1342 break;
1344 case ExecInfo:
1345 WMSetTextFieldText(panel->commandT, data->param.exec.command);
1346 WMSetTextFieldText(panel->shortT, data->param.exec.shortcut);
1347 break;
1349 case CommandInfo:
1350 WMSelectListItem(panel->icommandL, data->param.command.command);
1351 WMSetListPosition(panel->icommandL, data->param.command.command - 2);
1352 WMSetTextFieldText(panel->shortT, data->param.command.shortcut);
1354 switch (data->param.command.command) {
1355 case 3:
1356 case 4:
1357 WMSetButtonSelected(panel->quickB, data->param.command.parameter != NULL);
1358 break;
1359 case 6:
1360 WMSetTextFieldText(panel->paramT, data->param.command.parameter);
1361 break;
1364 icommandLClicked(panel->icommandL, panel);
1365 break;
1367 case PipeInfo:
1368 WMSetTextFieldText(panel->pipeT, data->param.pipe.command);
1369 WMSetButtonSelected(panel->pipeCacheB, data->param.pipe.cached);
1370 break;
1372 case PLPipeInfo:
1373 WMSetTextFieldText(panel->plpipeT, data->param.pipe.command);
1374 WMSetButtonSelected(panel->plpipeCacheB, data->param.pipe.cached);
1375 break;
1377 case ExternalInfo:
1378 WMSetTextFieldText(panel->pathT, data->param.external.path);
1379 break;
1381 case DirectoryInfo:
1382 WMSetTextFieldText(panel->dpathT, data->param.directory.directory);
1383 WMSetTextFieldText(panel->dcommandT, data->param.directory.command);
1384 WMSetButtonSelected(panel->dstripB, data->param.directory.stripExt);
1385 break;
1387 case WSMenuInfo:
1388 break;
1390 default:
1391 break;
1396 static WEditMenu *buildSubmenu(_Panel * panel, WMPropList * pl)
1398 WMScreen *scr = WMWidgetScreen(panel->parent);
1399 WEditMenu *menu;
1400 WEditMenuItem *item;
1401 char *title;
1402 WMPropList *tp, *bp;
1403 int i;
1405 tp = WMGetFromPLArray(pl, 0);
1406 title = WMGetFromPLString(tp);
1408 menu = WCreateEditMenu(scr, title);
1410 for (i = 1; i < WMGetPropListItemCount(pl); i++) {
1411 WMPropList *pi;
1413 pi = WMGetFromPLArray(pl, i);
1415 tp = WMGetFromPLArray(pi, 0);
1416 bp = WMGetFromPLArray(pi, 1);
1418 title = WMGetFromPLString(tp);
1420 if (!bp || WMIsPLArray(bp)) { /* it's a submenu */
1421 WEditMenu *submenu;
1423 submenu = buildSubmenu(panel, pi);
1425 item = WAddMenuItemWithTitle(menu, title);
1427 WSetEditMenuSubmenu(menu, item, submenu);
1428 } else {
1429 ItemData *data;
1431 data = parseCommand(pi);
1433 if (data != NULL) {
1434 item = WAddMenuItemWithTitle(menu, title);
1435 if (panel->markerPix[data->type])
1436 WSetEditMenuItemImage(item, panel->markerPix[data->type]);
1437 WSetEditMenuItemData(item, data, (WMCallback *) freeItemData);
1438 } else {
1439 char *buf = wmalloc(1024);
1440 snprintf(buf, 1024, _("Invalid menu command \"%s\" with label \"%s\" cleared"),
1441 WMGetFromPLString(WMGetFromPLArray(pi, 1)),
1442 WMGetFromPLString(WMGetFromPLArray(pi, 0)));
1443 WMRunAlertPanel(scr, panel->parent, _("Warning"), buf, _("OK"), NULL, NULL);
1444 wfree(buf);
1450 WSetEditMenuAcceptsDrop(menu, True);
1451 WSetEditMenuDelegate(menu, &menuDelegate);
1453 WMRealizeWidget(menu);
1455 return menu;
1458 static void buildMenuFromPL(_Panel * panel, WMPropList * pl)
1460 panel->menu = buildSubmenu(panel, pl);
1463 static WMPropList *getDefaultMenu(_Panel * panel)
1465 WMPropList *menu;
1466 static const char menuPath[] = WMAKER_RESOURCE_PATH "/plmenu";
1468 menu = WMReadPropListFromFile(menuPath);
1469 if (!menu) {
1470 char *buffer, *msg;
1472 msg = _("Could not open default menu from '%s'");
1473 buffer = wmalloc(strlen(msg) + strlen(menuPath) + 10);
1474 sprintf(buffer, msg, menuPath);
1475 WMRunAlertPanel(WMWidgetScreen(panel->parent), panel->parent,
1476 _("Error"), buffer, _("OK"), NULL, NULL);
1477 wfree(buffer);
1480 return menu;
1483 static void showData(_Panel * panel)
1485 const char *gspath;
1486 char *menuPath, *labelText;
1487 char buf[1024];
1488 WMPropList *pmenu;
1490 gspath = wusergnusteppath();
1492 menuPath = wmalloc(strlen(gspath) + 32);
1493 strcpy(menuPath, gspath);
1494 strcat(menuPath, "/Defaults/WMRootMenu");
1496 pmenu = WMReadPropListFromFile(menuPath);
1498 /* check if WMRootMenu references another file, and if so,
1499 if that file is in proplist format */
1500 while (WMIsPLString(pmenu)) {
1501 char *path = NULL;
1503 path = wexpandpath(WMGetFromPLString(pmenu));
1505 if (access(path, F_OK) < 0)
1506 path = wfindfile(DEF_CONFIG_PATHS, path);
1508 /* TODO: if needed, concatenate locale suffix to path.
1509 See getLocalizedMenuFile() in src/rootmenu.c. */
1511 if (!path)
1512 break;
1514 if (access(path, W_OK) < 0) {
1515 snprintf(buf, 1024,
1516 _("The menu file \"%s\" referenced by "
1517 "WMRootMenu is read-only.\n"
1518 "You cannot use WPrefs to modify it."),
1519 path);
1520 WMRunAlertPanel(WMWidgetScreen(panel->parent),
1521 panel->parent,
1522 _("Warning"), buf,
1523 _("OK"), NULL, NULL);
1524 panel->dontSave = True;
1525 wfree(path);
1526 return;
1529 pmenu = WMReadPropListFromFile(path);
1530 menuPath = path;
1533 if (!pmenu || !WMIsPLArray(pmenu)) {
1534 int res;
1536 res = WMRunAlertPanel(WMWidgetScreen(panel->parent), panel->parent,
1537 _("Warning"),
1538 _("The menu file format currently in use is not supported\n"
1539 "by this tool. Do you want to discard the current menu\n"
1540 "to use this tool?"),
1541 _("Yes, Discard and Update"), _("No, Keep Current Menu"), NULL);
1543 if (res == WAPRDefault) {
1544 pmenu = getDefaultMenu(panel);
1546 if (!pmenu) {
1547 pmenu = WMCreatePLArray(WMCreatePLString("Applications"), NULL);
1549 } else {
1550 panel->dontSave = True;
1551 return;
1555 panel->menuPath = menuPath;
1557 snprintf(buf, 1024,
1558 _("\n\nWhen saved, the menu will be written to the file\n\"%s\"."),
1559 menuPath);
1560 labelText = WMGetLabelText(panel->sections[NoInfo][0]);
1561 labelText = wstrconcat(labelText, buf);
1562 WMSetLabelText(panel->sections[NoInfo][0], labelText);
1563 wfree(labelText);
1565 buildMenuFromPL(panel, pmenu);
1567 WMReleasePropList(pmenu);
1570 static Bool notblank(const char *s)
1572 if (s) {
1573 while (*s++) {
1574 if (!isspace(*s))
1575 return True;
1578 return False;
1581 static WMPropList *processData(const char *title, ItemData * data)
1583 WMPropList *item;
1584 char *s1;
1585 static WMPropList *pscut = NULL;
1586 static WMPropList *pomenu = NULL;
1587 static WMPropList *poplmenu = NULL;
1588 int i;
1590 if (data == NULL)
1591 return NULL;
1593 if (!pscut) {
1594 pscut = WMCreatePLString("SHORTCUT");
1595 pomenu = WMCreatePLString("OPEN_MENU");
1596 poplmenu = WMCreatePLString("OPEN_PLMENU");
1599 item = WMCreatePLArray(WMCreatePLString(title), NULL);
1601 switch (data->type) {
1602 case ExecInfo:
1603 if (data->param.exec.command == NULL)
1604 goto return_null;
1605 #if 1
1606 if (strpbrk(data->param.exec.command, "&$*|><?`=;")) {
1607 s1 = "SHEXEC";
1608 } else {
1609 s1 = "EXEC";
1611 #else
1612 s1 = "SHEXEC";
1613 #endif
1615 if (notblank(data->param.exec.shortcut)) {
1616 WMAddToPLArray(item, pscut);
1617 WMAddToPLArray(item, WMCreatePLString(data->param.exec.shortcut));
1620 WMAddToPLArray(item, WMCreatePLString(s1));
1621 WMAddToPLArray(item, WMCreatePLString(data->param.exec.command));
1622 break;
1624 case CommandInfo:
1625 if (notblank(data->param.command.shortcut)) {
1626 WMAddToPLArray(item, pscut);
1627 WMAddToPLArray(item, WMCreatePLString(data->param.command.shortcut));
1630 i = data->param.command.command;
1632 WMAddToPLArray(item, WMCreatePLString(commandNames[i]));
1634 switch (i) {
1635 case 3:
1636 case 4:
1637 if (data->param.command.parameter) {
1638 WMAddToPLArray(item, WMCreatePLString(data->param.command.parameter));
1640 break;
1642 case 6: /* restart */
1643 if (data->param.command.parameter) {
1644 WMAddToPLArray(item, WMCreatePLString(data->param.command.parameter));
1646 break;
1649 break;
1651 case PipeInfo:
1652 case PLPipeInfo:
1653 if (!data->param.pipe.command)
1654 goto return_null;
1655 if (data->type == PLPipeInfo)
1656 WMAddToPLArray(item, poplmenu);
1657 else
1658 WMAddToPLArray(item, pomenu);
1660 if (data->param.pipe.cached)
1661 s1 = wstrconcat("| ", data->param.pipe.command);
1662 else
1663 s1 = wstrconcat("|| ", data->param.pipe.command);
1664 WMAddToPLArray(item, WMCreatePLString(s1));
1665 wfree(s1);
1666 break;
1668 case ExternalInfo:
1669 if (!data->param.external.path)
1670 goto return_null;
1671 WMAddToPLArray(item, pomenu);
1672 WMAddToPLArray(item, WMCreatePLString(data->param.external.path));
1673 break;
1675 case DirectoryInfo:
1677 int l;
1678 char *tmp;
1680 if (!data->param.directory.directory || !data->param.directory.command)
1681 goto return_null;
1683 l = strlen(data->param.directory.directory);
1684 l += strlen(data->param.directory.command);
1685 l += 32;
1687 WMAddToPLArray(item, pomenu);
1689 tmp = wmalloc(l);
1690 sprintf(tmp, "%s%s WITH %s",
1691 data->param.directory.stripExt ? "-noext " : "",
1692 data->param.directory.directory, data->param.directory.command);
1694 WMAddToPLArray(item, WMCreatePLString(tmp));
1695 wfree(tmp);
1697 break;
1699 case WSMenuInfo:
1700 WMAddToPLArray(item, WMCreatePLString("WORKSPACE_MENU"));
1701 break;
1703 case WWindowListInfo:
1704 WMAddToPLArray(item, WMCreatePLString("WINDOWS_MENU"));
1705 break;
1707 default:
1708 assert(0);
1709 break;
1712 return item;
1714 return_null:
1715 WMReleasePropList(item);
1716 return NULL;
1719 static WMPropList *processSubmenu(WEditMenu * menu)
1721 WEditMenuItem *item;
1722 WMPropList *pmenu;
1723 WMPropList *pl;
1724 char *s;
1725 int i;
1727 s = WGetEditMenuTitle(menu);
1728 pl = WMCreatePLString(s);
1730 pmenu = WMCreatePLArray(pl, NULL);
1732 i = 0;
1733 while ((item = WGetEditMenuItem(menu, i++))) {
1734 WEditMenu *submenu;
1736 s = WGetEditMenuItemTitle(item);
1738 submenu = WGetEditMenuSubmenu(item);
1739 if (submenu) {
1740 pl = processSubmenu(submenu);
1741 } else {
1742 pl = processData(s, WGetEditMenuItemData(item));
1745 if (!pl)
1746 continue;
1748 WMAddToPLArray(pmenu, pl);
1751 return pmenu;
1754 static WMPropList *buildPLFromMenu(_Panel * panel)
1756 WMPropList *menu;
1758 menu = processSubmenu(panel->menu);
1760 return menu;
1763 static void storeData(_Panel * panel)
1765 WMPropList *menu;
1767 if (panel->dontSave)
1768 return;
1770 menu = buildPLFromMenu(panel);
1772 WMWritePropListToFile(menu, panel->menuPath);
1774 WMReleasePropList(menu);
1777 static void showMenus(_Panel * panel)
1779 if (panel->menu)
1780 WEditMenuUnhide(panel->menu);
1783 static void hideMenus(_Panel * panel)
1785 if (panel->menu)
1786 WEditMenuHide(panel->menu);
1789 Panel *InitMenu(WMWidget *parent)
1791 _Panel *panel;
1793 panel = wmalloc(sizeof(_Panel));
1795 panel->sectionName = _("Applications Menu Definition");
1797 panel->description = _("Edit the menu for launching applications.");
1799 panel->parent = parent;
1801 panel->callbacks.createWidgets = createPanel;
1802 panel->callbacks.updateDomain = storeData;
1803 panel->callbacks.showPanel = showMenus;
1804 panel->callbacks.hidePanel = hideMenus;
1806 AddSection(panel, ICON_FILE);
1808 return panel;