Update Serbian translation from master branch
[wmaker-crm.git] / WPrefs.app / Menu.c
blob20b992ce6547f43254ab7382d232b5470bee0f01
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 if (padn < 0)
295 return;
296 WMUnmapWidget(panel->itemPad[panel->currentPad]);
297 WMMapWidget(panel->itemPad[padn]);
299 panel->currentPad = padn;
302 static WEditMenu *putNewSubmenu(WEditMenu * menu, const char *title)
304 WEditMenu *tmp;
305 WEditMenuItem *item;
307 item = WAddMenuItemWithTitle(menu, title);
309 tmp = WCreateEditMenu(WMWidgetScreen(menu), title);
310 WSetEditMenuAcceptsDrop(tmp, True);
311 WSetEditMenuDelegate(tmp, &menuDelegate);
312 WSetEditMenuSubmenu(menu, item, tmp);
314 return tmp;
317 static ItemData *putNewItem(_Panel * panel, WEditMenu * menu, int type, const char *title)
319 WEditMenuItem *item;
320 ItemData *data;
322 item = WAddMenuItemWithTitle(menu, title);
324 data = wmalloc(sizeof(ItemData));
325 data->type = type;
326 WSetEditMenuItemData(item, data, (WMCallback *) freeItemData);
327 WSetEditMenuItemImage(item, panel->markerPix[type]);
329 return data;
332 static WEditMenu *makeFactoryMenu(WMWidget * parent, int width)
334 WEditMenu *pad;
336 pad = WCreateEditMenuPad(parent);
337 WMResizeWidget(pad, width, 10);
338 WSetEditMenuMinSize(pad, wmksize(width, 0));
339 WSetEditMenuMaxSize(pad, wmksize(width, 0));
340 WSetEditMenuSelectable(pad, False);
341 WSetEditMenuEditable(pad, False);
342 WSetEditMenuIsFactory(pad, True);
343 WSetEditMenuDelegate(pad, &menuDelegate);
345 return pad;
348 static void createPanel(_Panel * p)
350 _Panel *panel = (_Panel *) p;
351 WMScreen *scr = WMWidgetScreen(panel->parent);
352 WMColor *black = WMBlackColor(scr);
353 WMColor *white = WMWhiteColor(scr);
354 WMColor *gray = WMGrayColor(scr);
355 WMFont *bold = WMBoldSystemFontOfSize(scr, 12);
356 WMFont *font = WMSystemFontOfSize(scr, 12);
357 WMLabel *label;
358 int width;
360 menuDelegate.data = panel;
362 panel->boldFont = bold;
363 panel->normalFont = font;
365 panel->black = black;
366 panel->white = white;
367 panel->gray = gray;
370 Pixmap pix;
371 Display *dpy = WMScreenDisplay(scr);
372 GC gc;
373 WMPixmap *pixm;
375 pixm = WMCreatePixmap(scr, 7, 7, WMScreenDepth(scr), True);
377 pix = WMGetPixmapXID(pixm);
379 XDrawLine(dpy, pix, WMColorGC(black), 0, 3, 6, 3);
380 XDrawLine(dpy, pix, WMColorGC(black), 3, 0, 3, 6);
382 XDrawLine(dpy, pix, WMColorGC(black), 1, 0, 3, 3);
383 XDrawLine(dpy, pix, WMColorGC(black), 1, 6, 3, 3);
384 XDrawLine(dpy, pix, WMColorGC(black), 0, 0, 0, 6);
387 pix = WMGetPixmapMaskXID(pixm);
389 gc = XCreateGC(dpy, pix, 0, NULL);
391 XSetForeground(dpy, gc, 0);
392 XFillRectangle(dpy, pix, gc, 0, 0, 7, 7);
394 XSetForeground(dpy, gc, 1);
395 XDrawLine(dpy, pix, gc, 0, 3, 6, 3);
396 XDrawLine(dpy, pix, gc, 3, 0, 3, 6);
398 panel->markerPix[ExternalInfo] = pixm;
399 panel->markerPix[PipeInfo] = pixm;
400 panel->markerPix[PLPipeInfo] = pixm;
401 panel->markerPix[DirectoryInfo] = pixm;
402 panel->markerPix[WSMenuInfo] = pixm;
403 panel->markerPix[WWindowListInfo] = pixm;
405 XFreeGC(dpy, gc);
408 panel->box = WMCreateBox(panel->parent);
409 WMSetViewExpandsToParent(WMWidgetView(panel->box), 2, 2, 2, 2);
411 panel->typeP = WMCreatePopUpButton(panel->box);
412 WMResizeWidget(panel->typeP, 150, 20);
413 WMMoveWidget(panel->typeP, 10, 10);
415 WMAddPopUpButtonItem(panel->typeP, _("New Items"));
416 WMAddPopUpButtonItem(panel->typeP, _("Sample Commands"));
417 WMAddPopUpButtonItem(panel->typeP, _("Sample Submenus"));
419 WMSetPopUpButtonAction(panel->typeP, changedItemPad, panel);
421 WMSetPopUpButtonSelectedItem(panel->typeP, 0);
424 WEditMenu *pad;
426 pad = makeFactoryMenu(panel->box, 150);
427 WMMoveWidget(pad, 10, 40);
429 putNewItem(panel, pad, ExecInfo, _("Run Program"));
430 putNewItem(panel, pad, CommandInfo, _("Internal Command"));
431 putNewSubmenu(pad, _("Submenu"));
432 putNewItem(panel, pad, ExternalInfo, _("External Submenu"));
433 putNewItem(panel, pad, PipeInfo, _("Generated Submenu"));
434 putNewItem(panel, pad, PLPipeInfo, _("Generated PL Menu"));
435 putNewItem(panel, pad, DirectoryInfo, _("Directory Contents"));
436 putNewItem(panel, pad, WSMenuInfo, _("Workspace Menu"));
437 putNewItem(panel, pad, WWindowListInfo, _("Window List Menu"));
439 panel->itemPad[0] = pad;
443 WEditMenu *pad;
444 ItemData *data;
445 WMScrollView *sview;
447 sview = WMCreateScrollView(panel->box);
448 WMResizeWidget(sview, 150, 180);
449 WMMoveWidget(sview, 10, 40);
450 WMSetScrollViewHasVerticalScroller(sview, True);
452 pad = makeFactoryMenu(panel->box, 130);
454 WMSetScrollViewContentView(sview, WMWidgetView(pad));
456 data = putNewItem(panel, pad, ExecInfo, _("XTerm"));
457 data->param.exec.command = "xterm -sb -sl 2000 -bg black -fg white";
459 data = putNewItem(panel, pad, ExecInfo, _("rxvt"));
460 data->param.exec.command = "rxvt";
462 data = putNewItem(panel, pad, ExecInfo, _("ETerm"));
463 data->param.exec.command = "eterm";
465 data = putNewItem(panel, pad, ExecInfo, _("Run..."));
466 data->param.exec.command = _("%A(Run,Type command to run)");
468 data = putNewItem(panel, pad, ExecInfo, _("Firefox"));
469 data->param.exec.command = "firefox";
471 data = putNewItem(panel, pad, ExecInfo, _("gimp"));
472 data->param.exec.command = "gimp";
474 data = putNewItem(panel, pad, ExecInfo, _("epic"));
475 data->param.exec.command = "xterm -e epic";
477 data = putNewItem(panel, pad, ExecInfo, _("ee"));
478 data->param.exec.command = "ee";
480 data = putNewItem(panel, pad, ExecInfo, _("xv"));
481 data->param.exec.command = "xv";
483 data = putNewItem(panel, pad, ExecInfo, _("Evince"));
484 data->param.exec.command = "evince";
486 data = putNewItem(panel, pad, ExecInfo, _("ghostview"));
487 data->param.exec.command = "gv";
489 data = putNewItem(panel, pad, CommandInfo, _("Exit Window Maker"));
490 data->param.command.command = 3;
492 WMMapWidget(pad);
494 panel->itemPad[1] = sview;
498 WEditMenu *pad, *smenu;
499 ItemData *data;
500 WMScrollView *sview;
502 sview = WMCreateScrollView(panel->box);
503 WMResizeWidget(sview, 150, 180);
504 WMMoveWidget(sview, 10, 40);
505 WMSetScrollViewHasVerticalScroller(sview, True);
507 pad = makeFactoryMenu(panel->box, 130);
509 WMSetScrollViewContentView(sview, WMWidgetView(pad));
511 data = putNewItem(panel, pad, ExternalInfo, _("Debian Menu"));
512 data->param.pipe.command = "/etc/" GSUSER_SUBDIR "/" DEFAULTS_SUBDIR "/menu.hook";
514 data = putNewItem(panel, pad, PipeInfo, _("RedHat Menu"));
515 data->param.pipe.command = "wmconfig --output wmaker";
517 data = putNewItem(panel, pad, PipeInfo, _("Menu Conectiva"));
518 data->param.pipe.command = "wmconfig --output wmaker";
520 data = putNewItem(panel, pad, DirectoryInfo, _("Themes"));
521 data->param.directory.command = "setstyle";
522 data->param.directory.directory =
523 "/usr/share/" PACKAGE_TARNAME "/Themes"
524 " /usr/local/share/" PACKAGE_TARNAME "/Themes"
525 " $HOME/" GSUSER_SUBDIR "/" USERDATA_SUBDIR "/" PACKAGE_TARNAME "/Themes";
526 data->param.directory.stripExt = 1;
528 data = putNewItem(panel, pad, DirectoryInfo, _("Bg Images (scale)"));
529 data->param.directory.command = "wmsetbg -u -s";
530 data->param.directory.directory =
531 "/opt/kde2/share/wallpapers"
532 " /usr/share/" PACKAGE_TARNAME "/Backgrounds"
533 " $HOME/" GSUSER_SUBDIR "/" USERDATA_SUBDIR "/" PACKAGE_TARNAME "/Backgrounds";
534 data->param.directory.stripExt = 1;
536 data = putNewItem(panel, pad, DirectoryInfo, _("Bg Images (tile)"));
537 data->param.directory.command = "wmsetbg -u -t";
538 data->param.directory.directory =
539 "/opt/kde2/share/wallpapers"
540 " /usr/share/" PACKAGE_TARNAME "/Backgrounds"
541 " $HOME/" GSUSER_SUBDIR "/" USERDATA_SUBDIR "/" PACKAGE_TARNAME "/Backgrounds";
542 data->param.directory.stripExt = 1;
544 smenu = putNewSubmenu(pad, _("Assorted XTerms"));
546 data = putNewItem(panel, smenu, ExecInfo, _("XTerm Yellow on Blue"));
547 data->param.exec.command = "xterm -sb -sl 2000 -bg midnightblue -fg yellow";
549 data = putNewItem(panel, smenu, ExecInfo, _("XTerm White on Black"));
550 data->param.exec.command = "xterm -sb -sl 2000 -bg black -fg white";
552 data = putNewItem(panel, smenu, ExecInfo, _("XTerm Black on White"));
553 data->param.exec.command = "xterm -sb -sl 2000 -bg white -fg black";
555 data = putNewItem(panel, smenu, ExecInfo, _("XTerm Black on Beige"));
556 data->param.exec.command = "xterm -sb -sl 2000 -bg '#bbbb99' -fg black";
558 data = putNewItem(panel, smenu, ExecInfo, _("XTerm White on Green"));
559 data->param.exec.command = "xterm -sb -sl 2000 -bg '#228822' -fg white";
561 data = putNewItem(panel, smenu, ExecInfo, _("XTerm White on Olive"));
562 data->param.exec.command = "xterm -sb -sl 2000 -bg '#335533' -fg white";
564 data = putNewItem(panel, smenu, ExecInfo, _("XTerm Blue on Blue"));
565 data->param.exec.command = "xterm -sb -sl 2000 -bg '#112244' -fg '#88aabb'";
567 data = putNewItem(panel, smenu, ExecInfo, _("XTerm BIG FONTS"));
568 data->param.exec.command = "xterm -sb -sl 2000 -bg black -fg white -fn 10x20";
570 WMMapWidget(pad);
572 panel->itemPad[2] = sview;
575 width = FRAME_WIDTH - 20 - 150 - 10 - 2;
577 panel->optionsF = WMCreateFrame(panel->box);
578 WMResizeWidget(panel->optionsF, width, FRAME_HEIGHT - 15);
579 WMMoveWidget(panel->optionsF, 10 + 150 + 10, 5);
581 width -= 20;
583 /* command */
585 panel->commandF = WMCreateFrame(panel->optionsF);
586 WMResizeWidget(panel->commandF, width, 50);
587 WMMoveWidget(panel->commandF, 10, 20);
588 WMSetFrameTitle(panel->commandF, _("Program to Run"));
589 WMSetFrameTitlePosition(panel->commandF, WTPAtTop);
591 panel->commandT = WMCreateTextField(panel->commandF);
592 WMResizeWidget(panel->commandT, width - 95, 20);
593 WMMoveWidget(panel->commandT, 10, 20);
595 panel->browseB = WMCreateCommandButton(panel->commandF);
596 WMResizeWidget(panel->browseB, 70, 24);
597 WMMoveWidget(panel->browseB, width - 80, 18);
598 WMSetButtonText(panel->browseB, _("Browse"));
599 WMSetButtonAction(panel->browseB, browseForFile, panel);
601 WMAddNotificationObserver(dataChanged, panel, WMTextDidChangeNotification, panel->commandT);
603 #if 0
604 panel->xtermC = WMCreateSwitchButton(panel->commandF);
605 WMResizeWidget(panel->xtermC, width - 20, 20);
606 WMMoveWidget(panel->xtermC, 10, 50);
607 WMSetButtonText(panel->xtermC, _("Run the program inside a Xterm"));
608 #endif
609 WMMapSubwidgets(panel->commandF);
611 /* path */
613 panel->pathF = WMCreateFrame(panel->optionsF);
614 WMResizeWidget(panel->pathF, width, 150);
615 WMMoveWidget(panel->pathF, 10, 40);
616 WMSetFrameTitle(panel->pathF, _("Path for Menu"));
618 panel->pathT = WMCreateTextField(panel->pathF);
619 WMResizeWidget(panel->pathT, width - 20, 20);
620 WMMoveWidget(panel->pathT, 10, 20);
622 WMAddNotificationObserver(dataChanged, panel, WMTextDidChangeNotification, panel->pathT);
624 label = WMCreateLabel(panel->pathF);
625 WMResizeWidget(label, width - 20, 90);
626 WMMoveWidget(label, 10, 50);
627 WMSetLabelText(label, _("Enter the path for a file containing a menu\n"
628 "or a list of directories with the programs you\n"
629 "want to have listed in the menu. Ex:\n"
630 "~/" GSUSER_SUBDIR "/" USERDATA_SUBDIR "/" PACKAGE_TARNAME "/menu\n"
631 "or\n" "/usr/bin ~/xbin"));
633 WMMapSubwidgets(panel->pathF);
635 /* pipe */
637 panel->pipeF = WMCreateFrame(panel->optionsF);
638 WMResizeWidget(panel->pipeF, width, 155);
639 WMMoveWidget(panel->pipeF, 10, 30);
640 WMSetFrameTitle(panel->pipeF, _("Command"));
642 panel->pipeT = WMCreateTextField(panel->pipeF);
643 WMResizeWidget(panel->pipeT, width - 20, 20);
644 WMMoveWidget(panel->pipeT, 10, 20);
646 WMAddNotificationObserver(dataChanged, panel, WMTextDidChangeNotification, panel->pipeT);
648 label = WMCreateLabel(panel->pipeF);
649 WMResizeWidget(label, width - 20, 40);
650 WMMoveWidget(label, 10, 50);
651 WMSetLabelText(label, _("Enter a command that outputs a menu\n" "definition to stdout when invoked."));
653 panel->pipeCacheB = WMCreateSwitchButton(panel->pipeF);
654 WMResizeWidget(panel->pipeCacheB, width - 20, 40);
655 WMMoveWidget(panel->pipeCacheB, 10, 110);
656 WMSetButtonText(panel->pipeCacheB, _("Cache menu contents after opening for\n" "the first time"));
658 WMMapSubwidgets(panel->pipeF);
660 /* proplist pipe */
662 panel->plpipeF = WMCreateFrame(panel->optionsF);
663 WMResizeWidget(panel->plpipeF, width, 155);
664 WMMoveWidget(panel->plpipeF, 10, 30);
665 WMSetFrameTitle(panel->plpipeF, _("Command"));
667 panel->plpipeT = WMCreateTextField(panel->plpipeF);
668 WMResizeWidget(panel->plpipeT, width - 20, 20);
669 WMMoveWidget(panel->plpipeT, 10, 20);
671 WMAddNotificationObserver(dataChanged, panel, WMTextDidChangeNotification, panel->plpipeT);
673 label = WMCreateLabel(panel->plpipeF);
674 WMResizeWidget(label, width - 20, 40);
675 WMMoveWidget(label, 10, 50);
676 WMSetLabelText(label, _("Enter a command that outputs a proplist menu\n" "definition to stdout when invoked."));
678 panel->plpipeCacheB = WMCreateSwitchButton(panel->plpipeF);
679 WMResizeWidget(panel->plpipeCacheB, width - 20, 40);
680 WMMoveWidget(panel->plpipeCacheB, 10, 110);
681 WMSetButtonText(panel->plpipeCacheB, _("Cache menu contents after opening for\n" "the first time"));
683 WMMapSubwidgets(panel->plpipeF);
685 /* directory menu */
687 panel->dcommandF = WMCreateFrame(panel->optionsF);
688 WMResizeWidget(panel->dcommandF, width, 90);
689 WMMoveWidget(panel->dcommandF, 10, 25);
690 WMSetFrameTitle(panel->dcommandF, _("Command to Open Files"));
692 panel->dcommandT = WMCreateTextField(panel->dcommandF);
693 WMResizeWidget(panel->dcommandT, width - 20, 20);
694 WMMoveWidget(panel->dcommandT, 10, 20);
696 WMAddNotificationObserver(dataChanged, panel, WMTextDidChangeNotification, panel->dcommandT);
698 label = WMCreateLabel(panel->dcommandF);
699 WMResizeWidget(label, width - 20, 45);
700 WMMoveWidget(label, 10, 40);
701 WMSetLabelText(label, _("Enter the command you want to use to open the\n"
702 "files in the directories listed below."));
704 WMMapSubwidgets(panel->dcommandF);
706 panel->dpathF = WMCreateFrame(panel->optionsF);
707 WMResizeWidget(panel->dpathF, width, 80);
708 WMMoveWidget(panel->dpathF, 10, 125);
709 WMSetFrameTitle(panel->dpathF, _("Directories with Files"));
711 panel->dpathT = WMCreateTextField(panel->dpathF);
712 WMResizeWidget(panel->dpathT, width - 20, 20);
713 WMMoveWidget(panel->dpathT, 10, 20);
715 WMAddNotificationObserver(dataChanged, panel, WMTextDidChangeNotification, panel->dpathT);
717 panel->dstripB = WMCreateSwitchButton(panel->dpathF);
718 WMResizeWidget(panel->dstripB, width - 20, 20);
719 WMMoveWidget(panel->dstripB, 10, 50);
720 WMSetButtonText(panel->dstripB, _("Strip extensions from file names"));
722 WMSetButtonAction(panel->dstripB, buttonClicked, panel);
724 WMMapSubwidgets(panel->dpathF);
726 /* shortcut */
728 panel->shortF = WMCreateFrame(panel->optionsF);
729 WMResizeWidget(panel->shortF, width, 50);
730 WMMoveWidget(panel->shortF, 10, 160);
731 WMSetFrameTitle(panel->shortF, _("Keyboard Shortcut"));
733 panel->shortT = WMCreateTextField(panel->shortF);
734 WMResizeWidget(panel->shortT, width - 20 - 150, 20);
735 WMMoveWidget(panel->shortT, 10, 20);
737 WMAddNotificationObserver(dataChanged, panel, WMTextDidChangeNotification, panel->shortT);
739 panel->sgrabB = WMCreateCommandButton(panel->shortF);
740 WMResizeWidget(panel->sgrabB, 70, 24);
741 WMMoveWidget(panel->sgrabB, width - 80, 18);
742 WMSetButtonText(panel->sgrabB, _("Capture"));
743 WMSetButtonAction(panel->sgrabB, sgrabClicked, panel);
745 panel->sclearB = WMCreateCommandButton(panel->shortF);
746 WMResizeWidget(panel->sclearB, 70, 24);
747 WMMoveWidget(panel->sclearB, width - 155, 18);
748 WMSetButtonText(panel->sclearB, _("Clear"));
749 WMSetButtonAction(panel->sclearB, sgrabClicked, panel);
751 WMMapSubwidgets(panel->shortF);
753 /* internal command */
755 panel->icommandL = WMCreateList(panel->optionsF);
756 WMResizeWidget(panel->icommandL, width, 80);
757 WMMoveWidget(panel->icommandL, 10, 20);
759 WMSetListAction(panel->icommandL, icommandLClicked, panel);
761 WMAddNotificationObserver(dataChanged, panel, WMListSelectionDidChangeNotification, panel->icommandL);
763 WMInsertListItem(panel->icommandL, 0, _("Arrange Icons"));
764 WMInsertListItem(panel->icommandL, 1, _("Hide All Windows Except For The Focused One"));
765 WMInsertListItem(panel->icommandL, 2, _("Show All Windows"));
767 WMInsertListItem(panel->icommandL, 3, _("Exit Window Maker"));
768 WMInsertListItem(panel->icommandL, 4, _("Exit X Session"));
769 WMInsertListItem(panel->icommandL, 5, _("Restart Window Maker"));
770 WMInsertListItem(panel->icommandL, 6, _("Start Another Window Manager : ("));
772 WMInsertListItem(panel->icommandL, 7, _("Save Current Session"));
773 WMInsertListItem(panel->icommandL, 8, _("Clear Saved Session"));
774 WMInsertListItem(panel->icommandL, 9, _("Refresh Screen"));
775 WMInsertListItem(panel->icommandL, 10, _("Open Info Panel"));
776 WMInsertListItem(panel->icommandL, 11, _("Open Copyright Panel"));
778 panel->paramF = WMCreateFrame(panel->optionsF);
779 WMResizeWidget(panel->paramF, width, 50);
780 WMMoveWidget(panel->paramF, 10, 105);
781 WMSetFrameTitle(panel->paramF, _("Window Manager to Start"));
783 panel->paramT = WMCreateTextField(panel->paramF);
784 WMResizeWidget(panel->paramT, width - 20, 20);
785 WMMoveWidget(panel->paramT, 10, 20);
787 WMAddNotificationObserver(dataChanged, panel, WMTextDidChangeNotification, panel->paramT);
789 WMMapSubwidgets(panel->paramF);
791 panel->quickB = WMCreateSwitchButton(panel->optionsF);
792 WMResizeWidget(panel->quickB, width, 20);
793 WMMoveWidget(panel->quickB, 10, 120);
794 WMSetButtonText(panel->quickB, _("Do not confirm action."));
795 WMSetButtonAction(panel->quickB, buttonClicked, panel);
797 label = WMCreateLabel(panel->optionsF);
798 WMResizeWidget(label, width + 5, FRAME_HEIGHT - 50);
799 WMMoveWidget(label, 7, 20);
800 WMSetLabelText(label,
801 _("Instructions:\n\n"
802 " - drag items from the left to the menu to add new items\n"
803 " - drag items out of the menu to remove items\n"
804 " - drag items in menu to change their position\n"
805 " - drag items with Control pressed to copy them\n"
806 " - double click in a menu item to change the label\n"
807 " - click on a menu item to change related information"));
808 WMMapWidget(label);
810 WMRealizeWidget(panel->box);
811 WMMapSubwidgets(panel->box);
812 WMMapWidget(panel->box);
815 int i;
816 for (i = 0; i < wlengthof(panel->itemPad); i++)
817 WMUnmapWidget(panel->itemPad[i]);
819 changedItemPad(panel->typeP, panel);
821 panel->sections[NoInfo][0] = label;
823 panel->sections[ExecInfo][0] = panel->commandF;
824 panel->sections[ExecInfo][1] = panel->shortF;
826 panel->sections[CommandInfo][0] = panel->icommandL;
827 panel->sections[CommandInfo][1] = panel->shortF;
829 panel->sections[ExternalInfo][0] = panel->pathF;
831 panel->sections[PipeInfo][0] = panel->pipeF;
833 panel->sections[PLPipeInfo][0] = panel->plpipeF;
835 panel->sections[DirectoryInfo][0] = panel->dpathF;
836 panel->sections[DirectoryInfo][1] = panel->dcommandF;
838 panel->currentType = NoInfo;
840 showData(panel);
843 WMPoint pos;
845 pos = WMGetViewScreenPosition(WMWidgetView(panel->box));
847 if (pos.x < 200) {
848 pos.x += FRAME_WIDTH + 20;
849 } else {
850 pos.x = 10;
853 pos.y = WMAX(pos.y - 100, 0);
855 if (panel->menu)
856 WEditMenuShowAt(panel->menu, pos.x, pos.y);
860 static void freeItemData(ItemData * data)
862 #define CFREE(d) if (d) wfree(d)
864 /* TODO */
865 switch (data->type) {
866 case CommandInfo:
867 CFREE(data->param.command.parameter);
868 CFREE(data->param.command.shortcut);
869 break;
871 case ExecInfo:
872 CFREE(data->param.exec.command);
873 CFREE(data->param.exec.shortcut);
874 break;
876 case PipeInfo:
877 CFREE(data->param.pipe.command);
878 break;
880 case PLPipeInfo:
881 CFREE(data->param.pipe.command);
882 break;
884 case ExternalInfo:
885 CFREE(data->param.external.path);
886 break;
888 case DirectoryInfo:
889 CFREE(data->param.directory.command);
890 CFREE(data->param.directory.directory);
891 break;
893 default:
894 break;
897 wfree(data);
898 #undef CFREE
901 static ItemData *parseCommand(WMPropList * item)
903 ItemData *data = wmalloc(sizeof(ItemData));
904 WMPropList *p;
905 char *command = NULL;
906 char *parameter = NULL;
907 char *shortcut = NULL;
908 int i = 1;
910 p = WMGetFromPLArray(item, i++);
911 command = WMGetFromPLString(p);
912 if (strcmp(command, "SHORTCUT") == 0) {
913 p = WMGetFromPLArray(item, i++);
914 shortcut = WMGetFromPLString(p);
915 p = WMGetFromPLArray(item, i++);
916 command = WMGetFromPLString(p);
918 p = WMGetFromPLArray(item, i++);
919 if (p)
920 parameter = WMGetFromPLString(p);
922 if (strcmp(command, "EXEC") == 0 || strcmp(command, "SHEXEC") == 0) {
924 data->type = ExecInfo;
926 if (parameter == NULL) {
927 wfree(data);
928 return NULL;
931 data->param.exec.command = wstrdup(parameter);
932 if (shortcut)
933 data->param.exec.shortcut = wstrdup(shortcut);
935 } else if (strcmp(command, "OPEN_MENU") == 0) {
936 char *p;
938 * dir menu, menu file
939 * dir WITH
940 * |pipe
942 p = parameter;
944 if (p == NULL) {
945 wfree(data);
946 return NULL;
949 while (isspace(*p) && *p)
950 p++;
951 if (*p == '|') {
952 if (*(p + 1) == '|') {
953 p++;
954 data->param.pipe.cached = 0;
955 } else {
956 data->param.pipe.cached = 1;
958 data->type = PipeInfo;
959 data->param.pipe.command = wtrimspace(p + 1);
960 } else {
961 char *s;
963 p = wstrdup(p);
965 s = strstr(p, "WITH");
966 if (s) {
967 char **tokens;
968 char **ctokens;
969 int tokn;
970 int i, j;
972 data->type = DirectoryInfo;
974 *s = '\0';
975 s += 5;
976 while (*s && isspace(*s))
977 s++;
978 data->param.directory.command = wstrdup(s);
980 wtokensplit(p, &tokens, &tokn);
981 wfree(p);
983 ctokens = wmalloc(sizeof(char *) * tokn);
985 for (i = 0, j = 0; i < tokn; i++) {
986 if (strcmp(tokens[i], "-noext") == 0) {
987 data->param.directory.stripExt = 1;
988 } else {
989 ctokens[j++] = tokens[i];
992 data->param.directory.directory = wtokenjoin(ctokens, j);
993 wfree(ctokens);
995 wtokenfree(tokens, tokn);
996 } else {
997 data->type = ExternalInfo;
998 data->param.external.path = p;
1001 } else if (strcmp(command, "OPEN_PLMENU") == 0) {
1002 char *p;
1004 p = parameter;
1005 while (isspace(*p) && *p)
1006 p++;
1007 if (*p == '|') {
1008 if (*(p + 1) == '|') {
1009 p++;
1010 data->param.pipe.cached = 0;
1011 } else {
1012 data->param.pipe.cached = 1;
1014 data->type = PLPipeInfo;
1015 data->param.pipe.command = wtrimspace(p + 1);
1017 } else if (strcmp(command, "WORKSPACE_MENU") == 0) {
1018 data->type = WSMenuInfo;
1019 } else if (strcmp(command, "WINDOWS_MENU") == 0) {
1020 data->type = WWindowListInfo;
1021 } else {
1022 int cmd;
1024 if (strcmp(command, "ARRANGE_ICONS") == 0) {
1025 cmd = 0;
1026 } else if (strcmp(command, "HIDE_OTHERS") == 0) {
1027 cmd = 1;
1028 } else if (strcmp(command, "SHOW_ALL") == 0) {
1029 cmd = 2;
1030 } else if (strcmp(command, "EXIT") == 0) {
1031 cmd = 3;
1032 } else if (strcmp(command, "SHUTDOWN") == 0) {
1033 cmd = 4;
1034 } else if (strcmp(command, "RESTART") == 0) {
1035 if (parameter) {
1036 cmd = 6;
1037 } else {
1038 cmd = 5;
1040 } else if (strcmp(command, "SAVE_SESSION") == 0) {
1041 cmd = 7;
1042 } else if (strcmp(command, "CLEAR_SESSION") == 0) {
1043 cmd = 8;
1044 } else if (strcmp(command, "REFRESH") == 0) {
1045 cmd = 9;
1046 } else if (strcmp(command, "INFO_PANEL") == 0) {
1047 cmd = 10;
1048 } else if (strcmp(command, "LEGAL_PANEL") == 0) {
1049 cmd = 11;
1050 } else {
1051 wwarning(_("unknown command '%s' in menu"), command);
1052 wfree(data);
1053 return NULL;
1056 data->type = CommandInfo;
1058 data->param.command.command = cmd;
1059 if (shortcut)
1060 data->param.command.shortcut = wstrdup(shortcut);
1061 if (parameter)
1062 data->param.command.parameter = wstrdup(parameter);
1065 return data;
1068 static void updateFrameTitle(_Panel * panel, const char *title, InfoType type)
1070 if (type != NoInfo) {
1071 char *tmp;
1073 switch (type) {
1074 case ExecInfo:
1075 tmp = wstrconcat(title, _(": Execute Program"));
1076 break;
1078 case CommandInfo:
1079 tmp = wstrconcat(title, _(": Perform Internal Command"));
1080 break;
1082 case ExternalInfo:
1083 tmp = wstrconcat(title, _(": Open a Submenu"));
1084 break;
1086 case PipeInfo:
1087 tmp = wstrconcat(title, _(": Program Generated Submenu"));
1088 break;
1090 case PLPipeInfo:
1091 tmp = wstrconcat(title, _(": Program Generated Proplist Submenu"));
1092 break;
1094 case DirectoryInfo:
1095 tmp = wstrconcat(title, _(": Directory Contents Menu"));
1096 break;
1098 case WSMenuInfo:
1099 tmp = wstrconcat(title, _(": Open Workspaces Submenu"));
1100 break;
1102 case WWindowListInfo:
1103 tmp = wstrconcat(title, _(": Open Window List Submenu"));
1104 break;
1106 default:
1107 tmp = NULL;
1108 break;
1110 WMSetFrameTitle(panel->optionsF, tmp);
1111 wfree(tmp);
1112 } else {
1113 WMSetFrameTitle(panel->optionsF, NULL);
1117 static void changeInfoType(_Panel * panel, const char *title, InfoType type)
1119 WMWidget **w;
1121 if (panel->currentType != type) {
1123 w = panel->sections[panel->currentType];
1125 while (*w) {
1126 WMUnmapWidget(*w);
1127 w++;
1129 WMUnmapWidget(panel->paramF);
1130 WMUnmapWidget(panel->quickB);
1132 w = panel->sections[type];
1134 while (*w) {
1135 WMMapWidget(*w);
1136 w++;
1140 updateFrameTitle(panel, title, type);
1142 panel->currentType = type;
1145 static void updateMenuItem(_Panel * panel, WEditMenuItem * item, WMWidget * changedWidget)
1147 ItemData *data = WGetEditMenuItemData(item);
1149 assert(data != NULL);
1151 #define REPLACE(v, d) if (v) wfree(v); v = d
1153 switch (data->type) {
1154 case ExecInfo:
1155 if (changedWidget == panel->commandT) {
1156 REPLACE(data->param.exec.command, WMGetTextFieldText(panel->commandT));
1158 if (changedWidget == panel->shortT) {
1159 REPLACE(data->param.exec.shortcut, WMGetTextFieldText(panel->shortT));
1161 break;
1163 case CommandInfo:
1164 if (changedWidget == panel->icommandL) {
1165 data->param.command.command = WMGetListSelectedItemRow(panel->icommandL);
1167 switch (data->param.command.command) {
1168 case 3:
1169 case 4:
1170 if (changedWidget == panel->quickB) {
1171 REPLACE(data->param.command.parameter, WMGetButtonSelected(panel->quickB)
1172 ? wstrdup("QUICK") : NULL);
1174 break;
1176 case 6:
1177 if (changedWidget == panel->paramT) {
1178 REPLACE(data->param.command.parameter, WMGetTextFieldText(panel->paramT));
1180 break;
1182 if (changedWidget == panel->shortT) {
1183 REPLACE(data->param.command.shortcut, WMGetTextFieldText(panel->shortT));
1186 break;
1188 case PipeInfo:
1189 if (changedWidget == panel->pipeT) {
1190 REPLACE(data->param.pipe.command, WMGetTextFieldText(panel->pipeT));
1192 if (changedWidget == panel->pipeCacheB) {
1193 data->param.pipe.cached = WMGetButtonSelected(panel->pipeCacheB);
1195 break;
1197 case PLPipeInfo:
1198 if (changedWidget == panel->plpipeT) {
1199 REPLACE(data->param.pipe.command, WMGetTextFieldText(panel->plpipeT));
1201 if (changedWidget == panel->plpipeCacheB) {
1202 data->param.pipe.cached = WMGetButtonSelected(panel->plpipeCacheB);
1204 break;
1206 case ExternalInfo:
1207 if (changedWidget == panel->pathT) {
1208 REPLACE(data->param.external.path, WMGetTextFieldText(panel->pathT));
1210 break;
1212 case DirectoryInfo:
1213 if (changedWidget == panel->dpathT) {
1214 REPLACE(data->param.directory.directory, WMGetTextFieldText(panel->dpathT));
1216 if (changedWidget == panel->dcommandT) {
1217 REPLACE(data->param.directory.command, WMGetTextFieldText(panel->dcommandT));
1219 if (changedWidget == panel->dstripB) {
1220 data->param.directory.stripExt = WMGetButtonSelected(panel->dstripB);
1222 break;
1224 default:
1225 assert(0);
1226 break;
1229 #undef REPLACE
1232 static void
1233 menuItemCloned(WEditMenuDelegate * delegate, WEditMenu * menu, WEditMenuItem * origItem, WEditMenuItem * newItem)
1235 ItemData *data = WGetEditMenuItemData(origItem);
1236 ItemData *newData;
1238 /* Parameter not used, but tell the compiler that it is ok */
1239 (void) delegate;
1240 (void) menu;
1242 if (!data)
1243 return;
1245 #define DUP(s) (s) ? wstrdup(s) : NULL
1247 newData = wmalloc(sizeof(ItemData));
1249 newData->type = data->type;
1251 switch (data->type) {
1252 case ExecInfo:
1253 newData->param.exec.command = DUP(data->param.exec.command);
1254 newData->param.exec.shortcut = DUP(data->param.exec.shortcut);
1255 break;
1257 case CommandInfo:
1258 newData->param.command.command = data->param.command.command;
1259 newData->param.command.parameter = DUP(data->param.command.parameter);
1260 newData->param.command.shortcut = DUP(data->param.command.shortcut);
1261 break;
1263 case PipeInfo:
1264 newData->param.pipe.command = DUP(data->param.pipe.command);
1265 newData->param.pipe.cached = data->param.pipe.cached;
1266 break;
1268 case PLPipeInfo:
1269 newData->param.pipe.command = DUP(data->param.pipe.command);
1270 newData->param.pipe.cached = data->param.pipe.cached;
1271 break;
1273 case ExternalInfo:
1274 newData->param.external.path = DUP(data->param.external.path);
1275 break;
1277 case DirectoryInfo:
1278 newData->param.directory.directory = DUP(data->param.directory.directory);
1279 newData->param.directory.command = DUP(data->param.directory.command);
1280 newData->param.directory.stripExt = data->param.directory.stripExt;
1281 break;
1283 default:
1284 break;
1287 #undef DUP
1289 WSetEditMenuItemData(newItem, newData, (WMCallback *) freeItemData);
1292 static void menuItemEdited(struct WEditMenuDelegate *delegate, WEditMenu * menu, WEditMenuItem * item)
1294 _Panel *panel = (_Panel *) delegate->data;
1295 WEditMenu *submenu;
1297 /* Parameter not used, but tell the compiler it is ok */
1298 (void) menu;
1300 updateFrameTitle(panel, WGetEditMenuItemTitle(item), panel->currentType);
1302 submenu = WGetEditMenuSubmenu(item);
1303 if (submenu) {
1304 WSetEditMenuTitle(submenu, WGetEditMenuItemTitle(item));
1308 static Bool shouldRemoveItem(struct WEditMenuDelegate *delegate, WEditMenu * menu, WEditMenuItem * item)
1310 _Panel *panel = (_Panel *) delegate->data;
1312 if (panel->dontAsk)
1313 return True;
1315 if (WGetEditMenuSubmenu(item)) {
1316 int res;
1318 res = WMRunAlertPanel(WMWidgetScreen(menu), NULL,
1319 _("Remove Submenu"),
1320 _("Removing this item will destroy all items inside\n"
1321 "the submenu. Do you really want to do that?"),
1322 _("Yes"), _("No"), _("Yes, don't ask again"));
1323 switch (res) {
1324 case WAPRDefault:
1325 return True;
1326 case WAPRAlternate:
1327 return False;
1328 case WAPROther:
1329 panel->dontAsk = True;
1330 return True;
1333 return True;
1336 static void menuItemDeselected(WEditMenuDelegate * delegate, WEditMenu * menu, WEditMenuItem * item)
1338 _Panel *panel = (_Panel *) delegate->data;
1340 /* Parameter not used, but tell the compiler that it is ok */
1341 (void) menu;
1342 (void) item;
1344 changeInfoType(panel, NULL, NoInfo);
1347 static void menuItemSelected(WEditMenuDelegate * delegate, WEditMenu * menu, WEditMenuItem * item)
1349 ItemData *data = WGetEditMenuItemData(item);
1350 _Panel *panel = (_Panel *) delegate->data;
1352 /* Parameter not used, but tell the compiler that it is ok */
1353 (void) menu;
1355 panel->currentItem = item;
1357 if (data) {
1358 changeInfoType(panel, WGetEditMenuItemTitle(item), data->type);
1360 switch (data->type) {
1361 case NoInfo:
1362 break;
1364 case ExecInfo:
1365 WMSetTextFieldText(panel->commandT, data->param.exec.command);
1366 WMSetTextFieldText(panel->shortT, data->param.exec.shortcut);
1367 break;
1369 case CommandInfo:
1370 WMSelectListItem(panel->icommandL, data->param.command.command);
1371 WMSetListPosition(panel->icommandL, data->param.command.command - 2);
1372 WMSetTextFieldText(panel->shortT, data->param.command.shortcut);
1374 switch (data->param.command.command) {
1375 case 3:
1376 case 4:
1377 WMSetButtonSelected(panel->quickB, data->param.command.parameter != NULL);
1378 break;
1379 case 6:
1380 WMSetTextFieldText(panel->paramT, data->param.command.parameter);
1381 break;
1384 icommandLClicked(panel->icommandL, panel);
1385 break;
1387 case PipeInfo:
1388 WMSetTextFieldText(panel->pipeT, data->param.pipe.command);
1389 WMSetButtonSelected(panel->pipeCacheB, data->param.pipe.cached);
1390 break;
1392 case PLPipeInfo:
1393 WMSetTextFieldText(panel->plpipeT, data->param.pipe.command);
1394 WMSetButtonSelected(panel->plpipeCacheB, data->param.pipe.cached);
1395 break;
1397 case ExternalInfo:
1398 WMSetTextFieldText(panel->pathT, data->param.external.path);
1399 break;
1401 case DirectoryInfo:
1402 WMSetTextFieldText(panel->dpathT, data->param.directory.directory);
1403 WMSetTextFieldText(panel->dcommandT, data->param.directory.command);
1404 WMSetButtonSelected(panel->dstripB, data->param.directory.stripExt);
1405 break;
1407 case WSMenuInfo:
1408 break;
1410 default:
1411 break;
1416 static WEditMenu *buildSubmenu(_Panel * panel, WMPropList * pl)
1418 WMScreen *scr = WMWidgetScreen(panel->parent);
1419 WEditMenu *menu;
1420 WEditMenuItem *item;
1421 char *title;
1422 WMPropList *tp, *bp;
1423 int i;
1425 tp = WMGetFromPLArray(pl, 0);
1426 title = WMGetFromPLString(tp);
1428 menu = WCreateEditMenu(scr, title);
1430 for (i = 1; i < WMGetPropListItemCount(pl); i++) {
1431 WMPropList *pi;
1433 pi = WMGetFromPLArray(pl, i);
1435 tp = WMGetFromPLArray(pi, 0);
1436 bp = WMGetFromPLArray(pi, 1);
1438 title = WMGetFromPLString(tp);
1440 if (!bp || WMIsPLArray(bp)) { /* it's a submenu */
1441 WEditMenu *submenu;
1443 submenu = buildSubmenu(panel, pi);
1445 item = WAddMenuItemWithTitle(menu, title);
1447 WSetEditMenuSubmenu(menu, item, submenu);
1448 } else {
1449 ItemData *data;
1451 data = parseCommand(pi);
1453 if (data != NULL) {
1454 item = WAddMenuItemWithTitle(menu, title);
1455 if (panel->markerPix[data->type])
1456 WSetEditMenuItemImage(item, panel->markerPix[data->type]);
1457 WSetEditMenuItemData(item, data, (WMCallback *) freeItemData);
1458 } else {
1459 char buf[256];
1461 snprintf(buf, sizeof(buf), _("Invalid menu command \"%s\" with label \"%s\" cleared"),
1462 WMGetFromPLString(WMGetFromPLArray(pi, 1)),
1463 WMGetFromPLString(WMGetFromPLArray(pi, 0)));
1464 WMRunAlertPanel(scr, panel->parent, _("Warning"), buf, _("OK"), NULL, NULL);
1470 WSetEditMenuAcceptsDrop(menu, True);
1471 WSetEditMenuDelegate(menu, &menuDelegate);
1473 WMRealizeWidget(menu);
1475 return menu;
1478 static void buildMenuFromPL(_Panel * panel, WMPropList * pl)
1480 panel->menu = buildSubmenu(panel, pl);
1483 static WMPropList *getDefaultMenu(_Panel * panel)
1485 WMPropList *menu;
1486 static const char menuPath[] = WMAKER_RESOURCE_PATH "/plmenu";
1488 menu = WMReadPropListFromFile(menuPath);
1489 if (!menu) {
1490 char *buffer, *msg;
1492 msg = _("Could not open default menu from '%s'");
1493 buffer = wmalloc(strlen(msg) + strlen(menuPath) + 10);
1494 sprintf(buffer, msg, menuPath);
1495 WMRunAlertPanel(WMWidgetScreen(panel->parent), panel->parent,
1496 _("Error"), buffer, _("OK"), NULL, NULL);
1497 wfree(buffer);
1500 return menu;
1503 static void showData(_Panel * panel)
1505 char *menuPath, *labelText;
1506 char buf[1024];
1507 WMPropList *pmenu;
1509 menuPath = wdefaultspathfordomain("WMRootMenu");
1511 pmenu = WMReadPropListFromFile(menuPath);
1513 /* check if WMRootMenu references another file, and if so,
1514 if that file is in proplist format */
1515 while (WMIsPLString(pmenu)) {
1516 char *path = NULL;
1518 path = wexpandpath(WMGetFromPLString(pmenu));
1520 if (access(path, F_OK) < 0) {
1521 char *old_path = path;
1523 path = wfindfile(DEF_CONFIG_PATHS, path);
1524 wfree(old_path);
1527 /* TODO: if needed, concatenate locale suffix to path.
1528 See getLocalizedMenuFile() in src/rootmenu.c. */
1530 if (!path)
1531 break;
1533 if (access(path, W_OK) < 0) {
1534 snprintf(buf, sizeof(buf),
1535 _("The menu file \"%s\" referenced by "
1536 "WMRootMenu is read-only.\n"
1537 "You cannot use WPrefs to modify it."),
1538 path);
1539 WMRunAlertPanel(WMWidgetScreen(panel->parent),
1540 panel->parent,
1541 _("Warning"), buf,
1542 _("OK"), NULL, NULL);
1543 panel->dontSave = True;
1544 wfree(path);
1545 return;
1548 pmenu = WMReadPropListFromFile(path);
1549 menuPath = path;
1552 if (!pmenu || !WMIsPLArray(pmenu)) {
1553 int res;
1555 res = WMRunAlertPanel(WMWidgetScreen(panel->parent), panel->parent,
1556 _("Warning"),
1557 _("The menu file format currently in use is not supported\n"
1558 "by this tool. Do you want to discard the current menu\n"
1559 "to use this tool?"),
1560 _("Yes, Discard and Update"), _("No, Keep Current Menu"), NULL);
1562 if (res == WAPRDefault) {
1563 pmenu = getDefaultMenu(panel);
1565 if (!pmenu) {
1566 pmenu = WMCreatePLArray(WMCreatePLString("Applications"), NULL);
1568 } else {
1569 panel->dontSave = True;
1570 return;
1574 panel->menuPath = menuPath;
1576 snprintf(buf, sizeof(buf),
1577 _("\n\nWhen saved, the menu will be written to the file\n\"%s\"."),
1578 menuPath);
1579 labelText = WMGetLabelText(panel->sections[NoInfo][0]);
1580 labelText = wstrconcat(labelText, buf);
1581 WMSetLabelText(panel->sections[NoInfo][0], labelText);
1582 wfree(labelText);
1584 buildMenuFromPL(panel, pmenu);
1586 WMReleasePropList(pmenu);
1589 static Bool notblank(const char *s)
1591 if (s) {
1592 while (*s++) {
1593 if (!isspace(*s))
1594 return True;
1597 return False;
1600 static WMPropList *processData(const char *title, ItemData * data)
1602 WMPropList *item;
1603 char *s1;
1604 static WMPropList *pscut = NULL;
1605 static WMPropList *pomenu = NULL;
1606 static WMPropList *poplmenu = NULL;
1607 int i;
1609 if (data == NULL)
1610 return NULL;
1612 if (!pscut) {
1613 pscut = WMCreatePLString("SHORTCUT");
1614 pomenu = WMCreatePLString("OPEN_MENU");
1615 poplmenu = WMCreatePLString("OPEN_PLMENU");
1618 item = WMCreatePLArray(WMCreatePLString(title), NULL);
1620 switch (data->type) {
1621 case ExecInfo:
1622 if (data->param.exec.command == NULL)
1623 goto return_null;
1625 if (strpbrk(data->param.exec.command, "&$*|><?`=;")) {
1626 s1 = "SHEXEC";
1627 } else {
1628 s1 = "EXEC";
1631 if (notblank(data->param.exec.shortcut)) {
1632 WMAddToPLArray(item, pscut);
1633 WMAddToPLArray(item, WMCreatePLString(data->param.exec.shortcut));
1636 WMAddToPLArray(item, WMCreatePLString(s1));
1637 WMAddToPLArray(item, WMCreatePLString(data->param.exec.command));
1638 break;
1640 case CommandInfo:
1641 if (notblank(data->param.command.shortcut)) {
1642 WMAddToPLArray(item, pscut);
1643 WMAddToPLArray(item, WMCreatePLString(data->param.command.shortcut));
1646 i = data->param.command.command;
1648 WMAddToPLArray(item, WMCreatePLString(commandNames[i]));
1650 switch (i) {
1651 case 3:
1652 case 4:
1653 if (data->param.command.parameter) {
1654 WMAddToPLArray(item, WMCreatePLString(data->param.command.parameter));
1656 break;
1658 case 6: /* restart */
1659 if (data->param.command.parameter) {
1660 WMAddToPLArray(item, WMCreatePLString(data->param.command.parameter));
1662 break;
1665 break;
1667 case PipeInfo:
1668 case PLPipeInfo:
1669 if (!data->param.pipe.command)
1670 goto return_null;
1671 if (data->type == PLPipeInfo)
1672 WMAddToPLArray(item, poplmenu);
1673 else
1674 WMAddToPLArray(item, pomenu);
1676 if (data->param.pipe.cached)
1677 s1 = wstrconcat("| ", data->param.pipe.command);
1678 else
1679 s1 = wstrconcat("|| ", data->param.pipe.command);
1680 WMAddToPLArray(item, WMCreatePLString(s1));
1681 wfree(s1);
1682 break;
1684 case ExternalInfo:
1685 if (!data->param.external.path)
1686 goto return_null;
1687 WMAddToPLArray(item, pomenu);
1688 WMAddToPLArray(item, WMCreatePLString(data->param.external.path));
1689 break;
1691 case DirectoryInfo:
1693 int l;
1694 char *tmp;
1696 if (!data->param.directory.directory || !data->param.directory.command)
1697 goto return_null;
1699 l = strlen(data->param.directory.directory);
1700 l += strlen(data->param.directory.command);
1701 l += 32;
1703 WMAddToPLArray(item, pomenu);
1705 tmp = wmalloc(l);
1706 sprintf(tmp, "%s%s WITH %s",
1707 data->param.directory.stripExt ? "-noext " : "",
1708 data->param.directory.directory, data->param.directory.command);
1710 WMAddToPLArray(item, WMCreatePLString(tmp));
1711 wfree(tmp);
1713 break;
1715 case WSMenuInfo:
1716 WMAddToPLArray(item, WMCreatePLString("WORKSPACE_MENU"));
1717 break;
1719 case WWindowListInfo:
1720 WMAddToPLArray(item, WMCreatePLString("WINDOWS_MENU"));
1721 break;
1723 default:
1724 assert(0);
1725 break;
1728 return item;
1730 return_null:
1731 WMReleasePropList(item);
1732 return NULL;
1735 static WMPropList *processSubmenu(WEditMenu * menu)
1737 WEditMenuItem *item;
1738 WMPropList *pmenu;
1739 WMPropList *pl;
1740 char *s;
1741 int i;
1743 s = WGetEditMenuTitle(menu);
1744 pl = WMCreatePLString(s);
1746 pmenu = WMCreatePLArray(pl, NULL);
1748 i = 0;
1749 while ((item = WGetEditMenuItem(menu, i++))) {
1750 WEditMenu *submenu;
1752 s = WGetEditMenuItemTitle(item);
1754 submenu = WGetEditMenuSubmenu(item);
1755 if (submenu) {
1756 pl = processSubmenu(submenu);
1757 } else {
1758 pl = processData(s, WGetEditMenuItemData(item));
1761 if (!pl)
1762 continue;
1764 WMAddToPLArray(pmenu, pl);
1767 return pmenu;
1770 static WMPropList *buildPLFromMenu(_Panel * panel)
1772 WMPropList *menu;
1774 menu = processSubmenu(panel->menu);
1776 return menu;
1779 static void storeData(_Panel * panel)
1781 WMPropList *menu;
1783 if (panel->dontSave)
1784 return;
1786 menu = buildPLFromMenu(panel);
1788 WMWritePropListToFile(menu, panel->menuPath);
1790 WMReleasePropList(menu);
1793 static void showMenus(_Panel * panel)
1795 if (panel->menu)
1796 WEditMenuUnhide(panel->menu);
1799 static void hideMenus(_Panel * panel)
1801 if (panel->menu)
1802 WEditMenuHide(panel->menu);
1805 Panel *InitMenu(WMWidget *parent)
1807 _Panel *panel;
1809 panel = wmalloc(sizeof(_Panel));
1811 panel->sectionName = _("Applications Menu Definition");
1813 panel->description = _("Edit the menu for launching applications.");
1815 panel->parent = parent;
1817 panel->callbacks.createWidgets = createPanel;
1818 panel->callbacks.updateDomain = storeData;
1819 panel->callbacks.showPanel = showMenus;
1820 panel->callbacks.hidePanel = hideMenus;
1822 AddSection(panel, ICON_FILE);
1824 return panel;