fixed problem with motion event compression
[wmaker-crm.git] / WPrefs.app / Menu.c
blob51edfd366cacc914eccabad1a1c00458517ec008
1 /* Menu.c- menu definition
2 *
3 * WPrefs - Window Maker Preferences Program
4 *
5 * Copyright (c) 2000 Alfredo K. Kojima
6 *
7 * This program is free software; you can redistribute it and/or modify
8 * it under the terms of the GNU General Public License as published by
9 * the Free Software Foundation; either version 2 of the License, or
10 * (at your option) any later version.
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
18 * along with this program; if not, write to the Free Software
19 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307,
20 * USA.
24 #include "WPrefs.h"
25 #include <assert.h>
26 #include <ctype.h>
28 #include <X11/keysym.h>
29 #include <X11/cursorfont.h>
32 #include "editmenu.h"
35 typedef enum {
36 NoInfo,
37 ExecInfo,
38 CommandInfo,
39 ExternalInfo,
40 PipeInfo,
41 DirectoryInfo,
42 WSMenuInfo,
43 LastInfo
44 } InfoType;
46 #define MAX_SECTION_SIZE 4
48 typedef struct _Panel {
49 WMFrame *frame;
50 char *sectionName;
52 char *description;
54 CallbackRec callbacks;
55 WMWindow *win;
58 WMFont *boldFont;
59 WMFont *normalFont;
60 WMColor *white;
61 WMColor *gray;
62 WMColor *black;
64 WMPixmap *markerPix;
66 WMPopUpButton *typeP;
68 WEditMenu *itemPad;
70 WEditMenu *menu;
71 char *menuPath;
73 WMFrame *optionsF;
75 WMFrame *commandF;
76 WMTextField *commandT; /* command to run */
77 WMButton *xtermC; /* inside xterm? */
79 WMFrame *pathF;
80 WMTextField *pathT;
82 WMFrame *pipeF;
83 WMTextField *pipeT;
85 WMFrame *dpathF;
86 WMTextField *dpathT;
88 WMFrame *dcommandF;
89 WMTextField *dcommandT;
91 WMButton *dstripB;
93 WMFrame *shortF;
94 WMTextField *shortT;
95 WMButton *sgrabB;
96 WMButton *sclearB;
98 WMList *icommandL;
100 WMFrame *paramF;
101 WMTextField *paramT;
103 Bool dontAsk; /* whether to comfirm submenu remove */
104 Bool dontSave;
106 /* about the currently selected item */
107 WEditMenuItem *currentItem;
108 InfoType currentType;
109 WMWidget *sections[LastInfo][MAX_SECTION_SIZE];
110 } _Panel;
113 typedef struct {
114 InfoType type;
115 union {
116 struct {
117 int command;
118 char *parameter;
119 char *shortcut;
120 } command;
121 struct {
122 char *command;
123 char *shortcut;
124 } exec;
125 struct {
126 char *path;
127 } external;
128 struct {
129 char *command;
130 } pipe;
131 struct {
132 char *directory;
133 char *command;
134 unsigned stripExt:1;
135 } directory;
136 } param;
137 } ItemData;
141 static char *commandNames[] = {
142 "ARRANGE_ICONS",
143 "HIDE_OTHERS",
144 "SHOW_ALL",
145 "EXIT",
146 "SHUTDOWN",
147 "RESTART",
148 "RESTART",
149 "SAVE_SESSION",
150 "CLEAR_SESSION",
151 "REFRESH",
152 "INFO_PANEL",
153 "LEGAL_PANEL"
158 #define NEW(type) memset(wmalloc(sizeof(type)), 0, sizeof(type))
161 #define ICON_FILE "menus"
165 static void showData(_Panel *panel);
168 static void updateMenuItem(_Panel *panel, WEditMenuItem *item,
169 WMWidget *changedWidget);
171 static void menuItemSelected(struct WEditMenuDelegate *delegate,
172 WEditMenu *menu, WEditMenuItem *item);
174 static void menuItemDeselected(struct WEditMenuDelegate *delegate,
175 WEditMenu *menu, WEditMenuItem *item);
177 static void menuItemCloned(struct WEditMenuDelegate *delegate, WEditMenu *menu,
178 WEditMenuItem *origItem, WEditMenuItem *newItem);
180 static void menuItemEdited(struct WEditMenuDelegate *delegate, WEditMenu *menu,
181 WEditMenuItem *item);
183 static Bool shouldRemoveItem(struct WEditMenuDelegate *delegate,
184 WEditMenu *menu, WEditMenuItem *item);
187 static void freeItemData(ItemData *data);
191 static WEditMenuDelegate menuDelegate = {
192 NULL,
193 menuItemCloned,
194 menuItemEdited,
195 menuItemSelected,
196 menuItemDeselected,
197 shouldRemoveItem
201 static void
202 dataChanged(void *self, WMNotification *notif)
204 _Panel *panel = (_Panel*)self;
205 WEditMenuItem *item = panel->currentItem;
206 WMWidget *w = (WMWidget*)WMGetNotificationObject(notif);
208 updateMenuItem(panel, item, w);
212 static void
213 stripClicked(WMWidget *w, void *data)
215 _Panel *panel = (_Panel*)data;
216 WEditMenuItem *item = panel->currentItem;
218 updateMenuItem(panel, item, w);
222 static void
223 icommandLClicked(WMWidget *w, void *data)
225 _Panel *panel = (_Panel*)data;
227 switch (WMGetListSelectedItemRow(w)) {
228 case 6:
229 WMMapWidget(panel->paramF);
230 break;
231 default:
232 WMUnmapWidget(panel->paramF);
233 break;
238 static void
239 createPanel(_Panel *p)
241 _Panel *panel = (_Panel*)p;
242 WMScreen *scr = WMWidgetScreen(panel->win);
243 WMColor *black = WMBlackColor(scr);
244 WMColor *white = WMWhiteColor(scr);
245 WMColor *gray = WMGrayColor(scr);
246 WMFont *bold = WMBoldSystemFontOfSize(scr, 12);
247 WMFont *font = WMSystemFontOfSize(scr, 12);
248 WMLabel *label;
249 int width;
252 menuDelegate.data = panel;
255 panel->boldFont = bold;
256 panel->normalFont = font;
258 panel->black = black;
259 panel->white = white;
260 panel->gray = gray;
263 Pixmap pix;
264 Display *dpy = WMScreenDisplay(scr);
265 GC gc;
267 panel->markerPix = WMCreatePixmap(scr, 7, 7, WMScreenDepth(scr), True);
269 pix = WMGetPixmapXID(panel->markerPix);
271 XDrawLine(dpy, pix, WMColorGC(black), 1, 0, 6, 3);
272 XDrawLine(dpy, pix, WMColorGC(black), 1, 6, 6, 3);
273 XDrawLine(dpy, pix, WMColorGC(black), 1, 0, 3, 3);
274 XDrawLine(dpy, pix, WMColorGC(black), 1, 6, 3, 3);
275 XDrawLine(dpy, pix, WMColorGC(black), 0, 0, 0, 6);
278 pix = WMGetPixmapMaskXID(panel->markerPix);
280 gc = XCreateGC(dpy, pix, 0, NULL);
282 XSetForeground(dpy, gc, 0);
283 XFillRectangle(dpy, pix, gc, 0, 0, 7, 7);
285 XSetForeground(dpy, gc, 1);
286 XDrawLine(dpy, pix, gc, 1, 0, 6, 3);
287 XDrawLine(dpy, pix, gc, 1, 6, 6, 3);
288 XDrawLine(dpy, pix, gc, 1, 0, 3, 3);
289 XDrawLine(dpy, pix, gc, 1, 6, 3, 3);
290 XDrawLine(dpy, pix, gc, 0, 0, 0, 6);
292 XFreeGC(dpy, gc);
296 panel->frame = WMCreateFrame(panel->win);
297 WMResizeWidget(panel->frame, FRAME_WIDTH, FRAME_HEIGHT);
298 WMMoveWidget(panel->frame, FRAME_LEFT, FRAME_TOP);
300 panel->typeP = WMCreatePopUpButton(panel->frame);
301 WMResizeWidget(panel->typeP, 150, 20);
302 WMMoveWidget(panel->typeP, 10, 10);
304 WMAddPopUpButtonItem(panel->typeP, _("Items"));
305 WMAddPopUpButtonItem(panel->typeP, _("Sample Commands"));
306 WMAddPopUpButtonItem(panel->typeP, _("Sample Submenus"));
308 WMSetPopUpButtonSelectedItem(panel->typeP, 0);
311 WEditMenu *pad;
312 WEditMenu *tmp;
313 WEditMenuItem *item;
314 ItemData *data;
316 pad = WCreateEditMenuPad(panel->frame);
317 WMResizeWidget(pad, 150, 180);
318 WMMoveWidget(pad, 10, 40);
319 WSetEditMenuMinSize(pad, wmksize(150, 180));
320 WSetEditMenuMaxSize(pad, wmksize(150, 180));
321 WSetEditMenuSelectable(pad, False);
322 WSetEditMenuEditable(pad, False);
323 WSetEditMenuIsFactory(pad, True);
324 WSetEditMenuDelegate(pad, &menuDelegate);
326 item = WInsertMenuItemWithTitle(pad, 0, "Run Program");
327 data = NEW(ItemData);
328 data->type = ExecInfo;
329 WSetEditMenuItemData(item, data, (WMCallback*)freeItemData);
331 item = WInsertMenuItemWithTitle(pad, 1, "Internal Command");
332 data = NEW(ItemData);
333 data->type = CommandInfo;
334 WSetEditMenuItemData(item, data, (WMCallback*)freeItemData);
336 item = WInsertMenuItemWithTitle(pad, 2, "Submenu");
337 tmp = WCreateEditMenu(scr, "Submenu");
338 WSetEditMenuAcceptsDrop(tmp, True);
339 WSetEditMenuDelegate(tmp, &menuDelegate);
340 WSetEditMenuSubmenu(pad, item, tmp);
342 item = WInsertMenuItemWithTitle(pad, 3, "External Submenu");
343 WSetEditMenuItemImage(item, panel->markerPix);
344 data = NEW(ItemData);
345 data->type = ExternalInfo;
346 WSetEditMenuItemData(item, data, (WMCallback*)freeItemData);
348 item = WInsertMenuItemWithTitle(pad, 4, "Generated Submenu");
349 WSetEditMenuItemImage(item, panel->markerPix);
350 data = NEW(ItemData);
351 data->type = PipeInfo;
352 WSetEditMenuItemData(item, data, (WMCallback*)freeItemData);
354 item = WInsertMenuItemWithTitle(pad, 5, "Directory Contents");
355 WSetEditMenuItemImage(item, panel->markerPix);
356 data = NEW(ItemData);
357 data->type = DirectoryInfo;
358 WSetEditMenuItemData(item, data, (WMCallback*)freeItemData);
360 item = WInsertMenuItemWithTitle(pad, 6, "Workspace Menu");
361 WSetEditMenuItemImage(item, panel->markerPix);
362 data = NEW(ItemData);
363 data->type = WSMenuInfo;
364 WSetEditMenuItemData(item, data, (WMCallback*)freeItemData);
366 panel->itemPad = pad;
369 width = FRAME_WIDTH - 20 - 150 - 10;
371 panel->optionsF = WMCreateFrame(panel->frame);
372 WMResizeWidget(panel->optionsF, width, FRAME_HEIGHT - 15);
373 WMMoveWidget(panel->optionsF, 10 + 150 + 10, 5);
375 width -= 20;
377 /* command */
379 panel->commandF = WMCreateFrame(panel->optionsF);
380 WMResizeWidget(panel->commandF, width, 50);
381 WMMoveWidget(panel->commandF, 10, 20);
382 WMSetFrameTitle(panel->commandF, _("Program to Run"));
384 panel->commandT = WMCreateTextField(panel->commandF);
385 WMResizeWidget(panel->commandT, width - 20, 20);
386 WMMoveWidget(panel->commandT, 10, 20);
388 WMAddNotificationObserver(dataChanged, panel,
389 WMTextDidChangeNotification,
390 panel->commandT);
392 #if 0
393 panel->xtermC = WMCreateSwitchButton(panel->commandF);
394 WMResizeWidget(panel->xtermC, width - 20, 20);
395 WMMoveWidget(panel->xtermC, 10, 50);
396 WMSetButtonText(panel->xtermC, _("Run the program inside a Xterm"));
397 #endif
398 WMMapSubwidgets(panel->commandF);
401 /* path */
403 panel->pathF = WMCreateFrame(panel->optionsF);
404 WMResizeWidget(panel->pathF, width, 150);
405 WMMoveWidget(panel->pathF, 10, 40);
406 WMSetFrameTitle(panel->pathF, _("Path for Menu"));
408 panel->pathT = WMCreateTextField(panel->pathF);
409 WMResizeWidget(panel->pathT, width - 20, 20);
410 WMMoveWidget(panel->pathT, 10, 20);
412 WMAddNotificationObserver(dataChanged, panel,
413 WMTextDidChangeNotification,
414 panel->pathT);
416 label = WMCreateLabel(panel->pathF);
417 WMResizeWidget(label, width - 20, 80);
418 WMMoveWidget(label, 10, 50);
419 WMSetLabelText(label, _("Enter the path for a file containing a menu\n"
420 "or a list of directories with the programs you\n"
421 "want to have listed in the menu. Ex:\n"
422 "~/GNUstep/Library/WindowMaker/menu\n"
423 "or\n"
424 "/usr/X11R6/bin ~/xbin"));
426 WMMapSubwidgets(panel->pathF);
429 /* pipe */
431 panel->pipeF = WMCreateFrame(panel->optionsF);
432 WMResizeWidget(panel->pipeF, width, 100);
433 WMMoveWidget(panel->pipeF, 10, 50);
434 WMSetFrameTitle(panel->pipeF, _("Command"));
436 panel->pipeT = WMCreateTextField(panel->pipeF);
437 WMResizeWidget(panel->pipeT, width - 20, 20);
438 WMMoveWidget(panel->pipeT, 10, 20);
440 WMAddNotificationObserver(dataChanged, panel,
441 WMTextDidChangeNotification,
442 panel->pipeT);
445 label = WMCreateLabel(panel->pipeF);
446 WMResizeWidget(label, width - 20, 40);
447 WMMoveWidget(label, 10, 50);
448 WMSetLabelText(label, _("Enter a command that outputs a menu\n"
449 "definition to stdout when invoked."));
451 WMMapSubwidgets(panel->pipeF);
454 /* directory menu */
456 panel->dcommandF = WMCreateFrame(panel->optionsF);
457 WMResizeWidget(panel->dcommandF, width, 90);
458 WMMoveWidget(panel->dcommandF, 10, 25);
459 WMSetFrameTitle(panel->dcommandF, _("Command to Open Files"));
461 panel->dcommandT = WMCreateTextField(panel->dcommandF);
462 WMResizeWidget(panel->dcommandT, width - 20, 20);
463 WMMoveWidget(panel->dcommandT, 10, 20);
465 WMAddNotificationObserver(dataChanged, panel,
466 WMTextDidChangeNotification,
467 panel->dcommandT);
470 label = WMCreateLabel(panel->dcommandF);
471 WMResizeWidget(label, width - 20, 45);
472 WMMoveWidget(label, 10, 40);
473 WMSetLabelText(label, _("Enter the command you want to use to open the\n"
474 "files in the directories listed below."));
476 WMMapSubwidgets(panel->dcommandF);
479 panel->dpathF = WMCreateFrame(panel->optionsF);
480 WMResizeWidget(panel->dpathF, width, 80);
481 WMMoveWidget(panel->dpathF, 10, 125);
482 WMSetFrameTitle(panel->dpathF, _("Directories with Files"));
484 panel->dpathT = WMCreateTextField(panel->dpathF);
485 WMResizeWidget(panel->dpathT, width - 20, 20);
486 WMMoveWidget(panel->dpathT, 10, 20);
488 WMAddNotificationObserver(dataChanged, panel,
489 WMTextDidChangeNotification,
490 panel->dpathT);
492 panel->dstripB = WMCreateSwitchButton(panel->dpathF);
493 WMResizeWidget(panel->dstripB, width - 20, 20);
494 WMMoveWidget(panel->dstripB, 10, 50);
495 WMSetButtonText(panel->dstripB, _("Strip extensions from file names"));
497 WMSetButtonAction(panel->dstripB, stripClicked, panel);
499 WMMapSubwidgets(panel->dpathF);
502 /* shortcut */
504 panel->shortF = WMCreateFrame(panel->optionsF);
505 WMResizeWidget(panel->shortF, width, 50);
506 WMMoveWidget(panel->shortF, 10, 160);
507 WMSetFrameTitle(panel->shortF, _("Keyboard Shortcut"));
509 panel->shortT = WMCreateTextField(panel->shortF);
510 WMResizeWidget(panel->shortT, width - 20 - 170, 20);
511 WMMoveWidget(panel->shortT, 10, 20);
513 WMAddNotificationObserver(dataChanged, panel,
514 WMTextDidChangeNotification,
515 panel->shortT);
517 panel->sgrabB = WMCreateCommandButton(panel->shortF);
518 WMResizeWidget(panel->sgrabB, 80, 24);
519 WMMoveWidget(panel->sgrabB, width - 90, 18);
520 WMSetButtonText(panel->sgrabB, _("Capture"));
522 panel->sclearB = WMCreateCommandButton(panel->shortF);
523 WMResizeWidget(panel->sclearB, 80, 24);
524 WMMoveWidget(panel->sclearB, width - 175, 18);
525 WMSetButtonText(panel->sclearB, _("Clear"));
527 WMMapSubwidgets(panel->shortF);
529 /* internal command */
531 panel->icommandL = WMCreateList(panel->optionsF);
532 WMResizeWidget(panel->icommandL, width, 80);
533 WMMoveWidget(panel->icommandL, 10, 20);
535 WMSetListAction(panel->icommandL, icommandLClicked, panel);
537 WMAddNotificationObserver(dataChanged, panel,
538 WMListSelectionDidChangeNotification,
539 panel->icommandL);
541 WMInsertListItem(panel->icommandL, 0, _("Arrange Icons"));
542 WMInsertListItem(panel->icommandL, 1, _("Hide All Windows Except For The Focused One"));
543 WMInsertListItem(panel->icommandL, 2, _("Show All Windows"));
545 WMInsertListItem(panel->icommandL, 3, _("Exit Window Maker"));
546 WMInsertListItem(panel->icommandL, 4, _("Exit X Session"));
547 WMInsertListItem(panel->icommandL, 5, _("Restart Window Maker"));
548 WMInsertListItem(panel->icommandL, 6, _("Start Another Window Manager : ("));
550 WMInsertListItem(panel->icommandL, 7, _("Save Current Session"));
551 WMInsertListItem(panel->icommandL, 8, _("Clear Saved Session"));
552 WMInsertListItem(panel->icommandL, 9, _("Refresh Screen"));
553 WMInsertListItem(panel->icommandL, 10, _("Open Info Panel"));
554 WMInsertListItem(panel->icommandL, 11, _("Open Copyright Panel"));
557 panel->paramF = WMCreateFrame(panel->optionsF);
558 WMResizeWidget(panel->paramF, width, 50);
559 WMMoveWidget(panel->paramF, 10, 105);
560 WMSetFrameTitle(panel->paramF, _("Window Manager to Start"));
562 panel->paramT = WMCreateTextField(panel->paramF);
563 WMResizeWidget(panel->paramT, width - 20, 20);
564 WMMoveWidget(panel->paramT, 10, 20);
566 WMMapSubwidgets(panel->paramF);
568 WMRealizeWidget(panel->frame);
569 WMMapSubwidgets(panel->frame);
570 WMMapWidget(panel->frame);
574 panel->sections[ExecInfo][0] = panel->commandF;
575 panel->sections[ExecInfo][1] = panel->shortF;
577 panel->sections[CommandInfo][0] = panel->icommandL;
578 panel->sections[CommandInfo][1] = label;
579 panel->sections[CommandInfo][2] = panel->shortF;
581 panel->sections[ExternalInfo][0] = panel->pathF;
583 panel->sections[PipeInfo][0] = panel->pipeF;
585 panel->sections[DirectoryInfo][0] = panel->dpathF;
586 panel->sections[DirectoryInfo][1] = panel->dcommandF;
588 panel->currentType = NoInfo;
590 showData(panel);
596 static void
597 freeItemData(ItemData *data)
599 #define CFREE(d) if (d) free(d)
601 /* TODO */
602 switch (data->type) {
603 case CommandInfo:
604 CFREE(data->param.command.parameter);
605 CFREE(data->param.command.shortcut);
606 break;
608 case ExecInfo:
609 CFREE(data->param.exec.command);
610 CFREE(data->param.exec.shortcut);
611 break;
613 case PipeInfo:
614 CFREE(data->param.pipe.command);
615 break;
617 case ExternalInfo:
618 CFREE(data->param.external.path);
619 break;
621 case DirectoryInfo:
622 CFREE(data->param.directory.command);
623 CFREE(data->param.directory.directory);
624 break;
626 default:
627 break;
630 free(data);
631 #undef CFREE
635 static ItemData*
636 parseCommand(proplist_t item)
638 ItemData *data = NEW(ItemData);
639 proplist_t p;
640 char *command = NULL;
641 char *parameter = NULL;
642 char *shortcut = NULL;
643 int i = 1;
646 p = PLGetArrayElement(item, i++);
647 command = PLGetString(p);
648 if (strcmp(command, "SHORTCUT") == 0) {
649 p = PLGetArrayElement(item, i++);
650 shortcut = PLGetString(p);
651 p = PLGetArrayElement(item, i++);
652 command = PLGetString(p);
654 p = PLGetArrayElement(item, i++);
655 if (p)
656 parameter = PLGetString(p);
658 if (strcmp(command, "EXEC") == 0
659 || strcmp(command, "SHEXEC") == 0) {
661 data->type = ExecInfo;
663 data->param.exec.command = wstrdup(parameter);
664 if (shortcut)
665 data->param.exec.shortcut = wstrdup(shortcut);
667 } else if (strcmp(command, "OPEN_MENU") == 0) {
668 char *p;
670 * dir menu, menu file
671 * dir WITH
672 * |pipe (TODO: ||pipe)
674 p = parameter;
675 while (isspace(*p) && *p) p++;
676 if (*p == '|') {
677 data->type = PipeInfo;
678 data->param.pipe.command = wtrimspace(p+1);
679 } else {
680 char *s;
682 p = wstrdup(p);
684 s = strstr(p, "WITH");
685 if (s) {
686 char **tokens;
687 char **ctokens;
688 int tokn;
689 int i, j;
691 data->type = DirectoryInfo;
693 *s = '\0';
694 s += 5;
695 while (*s && isspace(*s)) s++;
696 data->param.directory.command = wstrdup(s);
698 wtokensplit(p, &tokens, &tokn);
699 free(p);
701 ctokens = wmalloc(sizeof(char*)*tokn);
703 for (i = 0, j = 0; i < tokn; i++) {
704 if (strcmp(tokens[i], "-noext") == 0) {
705 free(tokens[i]);
706 data->param.directory.stripExt = 1;
707 } else {
708 ctokens[j++] = tokens[i];
711 data->param.directory.directory = wtokenjoin(ctokens, j);
712 free(ctokens);
714 wtokenfree(tokens, tokn);
715 } else {
716 data->type = ExternalInfo;
717 data->param.external.path = p;
720 } else if (strcmp(command, "WORKSPACE_MENU") == 0) {
721 data->type = WSMenuInfo;
722 } else {
723 int cmd;
725 if (strcmp(command, "ARRANGE_ICONS") == 0) {
726 cmd = 0;
727 } else if (strcmp(command, "HIDE_OTHERS") == 0) {
728 cmd = 1;
729 } else if (strcmp(command, "SHOW_ALL") == 0) {
730 cmd = 2;
731 } else if (strcmp(command, "EXIT") == 0) {
732 cmd = 3;
733 } else if (strcmp(command, "SHUTDOWN") == 0) {
734 cmd = 4;
735 } else if (strcmp(command, "RESTART") == 0) {
736 if (parameter) {
737 cmd = 6;
738 } else {
739 cmd = 5;
741 } else if (strcmp(command, "SAVE_SESSION") == 0) {
742 cmd = 7;
743 } else if (strcmp(command, "CLEAR_SESSION") == 0) {
744 cmd = 8;
745 } else if (strcmp(command, "REFRESH") == 0) {
746 cmd = 9;
747 } else if (strcmp(command, "INFO_PANEL") == 0) {
748 cmd = 10;
749 } else if (strcmp(command, "LEGAL_PANEL") == 0) {
750 cmd = 11;
751 } else {
752 wwarning(_("unknown command '%s' in menu"), command);
753 goto error;
756 data->type = CommandInfo;
758 data->param.command.command = cmd;
759 if (shortcut)
760 data->param.command.shortcut = wstrdup(shortcut);
761 if (parameter)
762 data->param.command.parameter = wstrdup(parameter);
765 return data;
767 error:
768 free(data);
770 return NULL;
776 static void
777 updateFrameTitle(_Panel *panel, char *title, InfoType type)
779 if (type != NoInfo) {
780 char *tmp;
782 switch (type) {
783 case ExecInfo:
784 tmp = wstrappend(title, _(": Execute Program"));
785 break;
787 case CommandInfo:
788 tmp = wstrappend(title, _(": Perform Internal Command"));
789 break;
791 case ExternalInfo:
792 tmp = wstrappend(title, _(": Open a Submenu"));
793 break;
795 case PipeInfo:
796 tmp = wstrappend(title, _(": Program Generated Submenu"));
797 break;
799 case DirectoryInfo:
800 tmp = wstrappend(title, _(": Directory Contents Menu"));
801 break;
803 case WSMenuInfo:
804 tmp = wstrappend(title, _(": Open Workspaces Submenu"));
805 break;
807 default:
808 tmp = NULL;
809 break;
811 WMSetFrameTitle(panel->optionsF, tmp);
812 free(tmp);
813 } else {
814 WMSetFrameTitle(panel->optionsF, NULL);
820 static void
821 changeInfoType(_Panel *panel, char *title, InfoType type)
823 WMWidget **w;
825 if (panel->currentType != NoInfo) {
826 w = panel->sections[panel->currentType];
828 while (*w) {
829 WMUnmapWidget(*w);
830 w++;
834 if (type != NoInfo) {
835 w = panel->sections[type];
837 while (*w) {
838 WMMapWidget(*w);
839 w++;
843 updateFrameTitle(panel, title, type);
845 panel->currentType = type;
851 static void
852 updateMenuItem(_Panel *panel, WEditMenuItem *item, WMWidget *changedWidget)
854 ItemData *data = WGetEditMenuItemData(item);
856 assert(data != NULL);
858 #define REPLACE(v, d) if (v) free(v); v = d
860 switch (data->type) {
861 case ExecInfo:
862 if (changedWidget == panel->commandT) {
863 REPLACE(data->param.exec.command,
864 WMGetTextFieldText(panel->commandT));
866 if (changedWidget == panel->shortT) {
867 REPLACE(data->param.exec.shortcut,
868 WMGetTextFieldText(panel->shortT));
870 break;
872 case CommandInfo:
873 if (changedWidget == panel->icommandL) {
874 data->param.command.command =
875 WMGetListSelectedItemRow(panel->icommandL);
877 switch (data->param.command.command) {
878 case 6:
879 data->param.command.parameter =
880 WMGetTextFieldText(panel->paramT);
881 break;
884 if (changedWidget == panel->shortT) {
885 REPLACE(data->param.command.shortcut,
886 WMGetTextFieldText(panel->shortT));
888 break;
890 case PipeInfo:
891 if (changedWidget == panel->pipeT) {
892 REPLACE(data->param.pipe.command,
893 WMGetTextFieldText(panel->pipeT));
895 break;
897 case ExternalInfo:
898 if (changedWidget == panel->pathT) {
899 REPLACE(data->param.external.path,
900 WMGetTextFieldText(panel->pathT));
902 break;
904 case DirectoryInfo:
905 if (changedWidget == panel->dpathT) {
906 REPLACE(data->param.directory.directory,
907 WMGetTextFieldText(panel->dpathT));
909 if (changedWidget == panel->dcommandT) {
910 REPLACE(data->param.directory.command,
911 WMGetTextFieldText(panel->dcommandT));
913 if (changedWidget == panel->dstripB) {
914 data->param.directory.stripExt =
915 WMGetButtonSelected(panel->dstripB);
917 break;
919 default:
920 assert(0);
921 break;
924 #undef REPLACE
929 static void
930 menuItemCloned(WEditMenuDelegate *delegate, WEditMenu *menu,
931 WEditMenuItem *origItem, WEditMenuItem *newItem)
933 ItemData *data = WGetEditMenuItemData(origItem);
934 ItemData *newData;
936 if (!data)
937 return;
939 #define DUP(s) (s) ? wstrdup(s) : NULL
941 newData = NEW(ItemData);
943 newData->type = data->type;
945 switch (data->type) {
946 case ExecInfo:
947 data->param.exec.command = DUP(data->param.exec.command);
948 data->param.exec.shortcut = DUP(data->param.exec.shortcut);
949 break;
951 case CommandInfo:
952 data->param.command.parameter = DUP(data->param.command.parameter);
953 data->param.command.shortcut = DUP(data->param.command.shortcut);
954 break;
956 case PipeInfo:
957 data->param.pipe.command = DUP(data->param.pipe.command);
958 break;
960 case ExternalInfo:
961 data->param.external.path = DUP(data->param.external.path);
962 break;
964 case DirectoryInfo:
965 data->param.directory.directory = DUP(data->param.directory.directory);
966 data->param.directory.command = DUP(data->param.directory.command);
967 break;
969 default:
970 break;
973 #undef DUP
975 WSetEditMenuItemData(newItem, newData, (WMCallback*)freeItemData);
981 static void menuItemEdited(struct WEditMenuDelegate *delegate, WEditMenu *menu,
982 WEditMenuItem *item)
984 _Panel *panel = (_Panel*)delegate->data;
986 updateFrameTitle(panel, WGetEditMenuItemTitle(item), panel->currentType);
993 static Bool shouldRemoveItem(struct WEditMenuDelegate *delegate,
994 WEditMenu *menu, WEditMenuItem *item)
996 _Panel *panel = (_Panel*)delegate->data;
998 if (panel->dontAsk)
999 return True;
1001 if (WGetEditMenuSubmenu(menu, item)) {
1002 int res;
1004 res = WMRunAlertPanel(WMWidgetScreen(menu), NULL,
1005 _("Remove Submenu"),
1006 _("Removing this item will destroy all items inside\n"
1007 "the submenu. Do you really want to do that?"),
1008 _("Yes"), _("No"),
1009 _("Yes, don't ask again."));
1010 switch (res) {
1011 case WAPRDefault:
1012 return True;
1013 case WAPRAlternate:
1014 return False;
1015 case WAPROther:
1016 panel->dontAsk = True;
1017 return True;
1020 return True;
1024 static void
1025 menuItemDeselected(WEditMenuDelegate *delegate, WEditMenu *menu,
1026 WEditMenuItem *item)
1028 _Panel *panel = (_Panel*)delegate->data;
1030 changeInfoType(panel, NULL, NoInfo);
1034 static void
1035 menuItemSelected(WEditMenuDelegate *delegate, WEditMenu *menu,
1036 WEditMenuItem *item)
1038 ItemData *data = WGetEditMenuItemData(item);
1039 _Panel *panel = (_Panel*)delegate->data;
1041 panel->currentItem = item;
1043 if (data) {
1044 changeInfoType(panel, WGetEditMenuItemTitle(item), data->type);
1046 switch (data->type) {
1047 case NoInfo:
1048 break;
1050 case ExecInfo:
1051 WMSetTextFieldText(panel->commandT, data->param.exec.command);
1052 WMSetTextFieldText(panel->shortT, data->param.exec.shortcut);
1053 break;
1055 case CommandInfo:
1056 WMSelectListItem(panel->icommandL,
1057 data->param.command.command);
1058 WMSetListPosition(panel->icommandL,
1059 data->param.command.command - 2);
1060 WMSetTextFieldText(panel->shortT, data->param.command.shortcut);
1062 switch (data->param.command.command) {
1063 case 6:
1064 WMSetTextFieldText(panel->paramT,
1065 data->param.command.parameter);
1066 break;
1069 icommandLClicked(panel->icommandL, panel);
1070 break;
1072 case PipeInfo:
1073 WMSetTextFieldText(panel->pipeT, data->param.pipe.command);
1074 break;
1076 case ExternalInfo:
1077 WMSetTextFieldText(panel->pathT, data->param.external.path);
1078 break;
1080 case DirectoryInfo:
1081 WMSetTextFieldText(panel->dpathT, data->param.directory.directory);
1082 WMSetTextFieldText(panel->dcommandT, data->param.directory.command);
1083 WMSetButtonSelected(panel->dstripB, data->param.directory.stripExt);
1084 break;
1086 case WSMenuInfo:
1087 break;
1089 default:
1090 break;
1097 static WEditMenu*
1098 buildSubmenu(WMScreen *scr, proplist_t pl)
1100 WEditMenu *menu;
1101 WEditMenuItem *item;
1102 char *title;
1103 proplist_t tp, bp;
1104 int i;
1106 tp = PLGetArrayElement(pl, 0);
1107 title = PLGetString(tp);
1109 menu = WCreateEditMenu(scr, title);
1111 for (i = 1; i < PLGetNumberOfElements(pl); i++) {
1112 proplist_t pi;
1114 pi = PLGetArrayElement(pl, i);
1116 tp = PLGetArrayElement(pi, 0);
1117 bp = PLGetArrayElement(pi, 1);
1119 title = PLGetString(tp);
1121 if (PLIsArray(bp)) { /* it's a submenu */
1122 WEditMenu *submenu;
1124 submenu = buildSubmenu(scr, pi);
1126 item = WAddMenuItemWithTitle(menu, title);
1128 WSetEditMenuSubmenu(menu, item, submenu);
1129 } else {
1130 ItemData *data;
1132 item = WAddMenuItemWithTitle(menu, title);
1134 data = parseCommand(pi);
1136 WSetEditMenuItemData(item, data, (WMCallback*)freeItemData);
1140 WSetEditMenuAcceptsDrop(menu, True);
1141 WSetEditMenuDelegate(menu, &menuDelegate);
1143 WMRealizeWidget(menu);
1145 return menu;
1150 static void
1151 buildMenuFromPL(_Panel *panel, proplist_t pl)
1153 panel->menu = buildSubmenu(WMWidgetScreen(panel->win), pl);
1154 WMMapWidget(panel->menu);
1159 static proplist_t
1160 getDefaultMenu(_Panel *panel)
1162 proplist_t menu, pmenu;
1163 char *menuPath, *gspath;
1165 gspath = wusergnusteppath();
1167 menuPath = wmalloc(strlen(gspath)+128);
1168 /* if there is a localized plmenu for the tongue put it's filename here */
1169 sprintf(menuPath, _("%s/Library/WindowMaker/plmenu"), gspath);
1171 menu = PLGetProplistWithPath(menuPath);
1172 if (!menu) {
1173 wwarning("%s:could not read property list menu", menuPath);
1175 if (strcmp("%s/Library/WindowMaker/plmenu",
1176 _("%s/Library/WindowMaker/plmenu"))!=0) {
1178 sprintf(menuPath, "%s/Library/WindowMaker/plmenu", gspath);
1179 menu = PLGetProplistWithPath(menuPath);
1180 wwarning("%s:could not read property list menu", menuPath);
1182 if (!menu) {
1183 char buffer[512];
1185 sprintf(buffer, _("Could not open default menu from '%s'"),
1186 menuPath);
1187 WMRunAlertPanel(WMWidgetScreen(panel->win), panel->win,
1188 _("Error"), buffer, _("OK"), NULL, NULL);
1192 free(menuPath);
1194 if (menu) {
1195 pmenu = menu;
1196 } else {
1197 pmenu = NULL;
1200 return pmenu;
1204 static void
1205 showData(_Panel *panel)
1207 char *gspath;
1208 char *menuPath;
1209 proplist_t pmenu;
1211 gspath = wusergnusteppath();
1213 menuPath = wmalloc(strlen(gspath)+32);
1214 strcpy(menuPath, gspath);
1215 strcat(menuPath, "/Defaults/WMRootMenu");
1217 pmenu = PLGetProplistWithPath(menuPath);
1219 if (!pmenu || !PLIsArray(pmenu)) {
1220 int res;
1222 res = WMRunAlertPanel(WMWidgetScreen(panel->win), panel->win,
1223 _("Warning"),
1224 _("The menu file format currently in use is not supported\n"
1225 "by this tool. Do you want to discard the current menu\n"
1226 "to use this tool?"),
1227 _("Yes, Discard and Update"),
1228 _("No, Keep Current Menu"), NULL);
1230 if (res == WAPRDefault) {
1231 pmenu = getDefaultMenu(panel);
1233 if (!pmenu) {
1234 pmenu = PLMakeArrayFromElements(PLMakeString("Applications"),
1235 NULL);
1237 } else {
1238 panel->dontSave = True;
1239 return;
1243 panel->menuPath = menuPath;
1245 buildMenuFromPL(panel, pmenu);
1247 PLRelease(pmenu);
1251 static Bool
1252 notblank(char *s)
1254 if (s) {
1255 while (*s++) {
1256 if (!isspace(*s))
1257 return True;
1260 return False;
1264 static proplist_t
1265 processData(char *title, ItemData *data)
1267 proplist_t item;
1268 char *s1;
1269 static char *pscut = NULL;
1270 static char *pomenu = NULL;
1271 int i;
1273 if (!pscut) {
1274 pscut = PLMakeString("SHORTCUT");
1275 pomenu = PLMakeString("OPEN_MENU");
1278 item = PLMakeArrayFromElements(PLMakeString(title), NULL);
1281 switch (data->type) {
1282 case ExecInfo:
1283 #if 1
1284 if (strpbrk(data->param.exec.command, "&$*|><?")) {
1285 s1 = "SHEXEC";
1286 } else {
1287 s1 = "EXEC";
1289 #else
1290 s1 = "SHEXEC";
1291 #endif
1293 if (notblank(data->param.exec.shortcut)) {
1294 PLAppendArrayElement(item, pscut);
1295 PLAppendArrayElement(item,
1296 PLMakeString(data->param.exec.shortcut));
1299 PLAppendArrayElement(item, PLMakeString(s1));
1300 PLAppendArrayElement(item, PLMakeString(data->param.exec.command));
1301 break;
1303 case CommandInfo:
1304 if (notblank(data->param.command.shortcut)) {
1305 PLAppendArrayElement(item, pscut);
1306 PLAppendArrayElement(item,
1307 PLMakeString(data->param.command.shortcut));
1310 i = data->param.command.command;
1312 PLAppendArrayElement(item, PLMakeString(commandNames[i]));
1314 switch (i) {
1315 case 7: /* restart */
1316 if (data->param.command.parameter)
1317 PLAppendArrayElement(item,
1318 PLMakeString(data->param.command.parameter));
1319 break;
1321 /* SHUTDOWN, QUIT QUICK */
1324 break;
1326 case PipeInfo:
1327 PLAppendArrayElement(item, pomenu);
1328 s1 = wstrappend("| ", data->param.pipe.command);
1329 PLAppendArrayElement(item, PLMakeString(s1));
1330 free(s1);
1331 break;
1333 case ExternalInfo:
1334 PLAppendArrayElement(item, pomenu);
1335 PLAppendArrayElement(item, PLMakeString(data->param.external.path));
1336 break;
1338 case DirectoryInfo:
1340 int l;
1341 char *tmp;
1343 l = strlen(data->param.directory.directory);
1344 l += strlen(data->param.directory.command);
1345 l += 32;
1347 PLAppendArrayElement(item, pomenu);
1349 tmp = wmalloc(l);
1350 sprintf(tmp, "%s%s WITH %s",
1351 data->param.directory.stripExt ? "-noext " : "",
1352 data->param.directory.directory,
1353 data->param.directory.command);
1355 PLAppendArrayElement(item, PLMakeString(tmp));
1356 free(tmp);
1358 break;
1360 case WSMenuInfo:
1361 PLAppendArrayElement(item, PLMakeString("WORKSPACE_MENU"));
1362 break;
1364 default:
1365 assert(0);
1366 break;
1369 return item;
1373 static proplist_t
1374 processSubmenu(WEditMenu *menu)
1376 WEditMenuItem *item;
1377 proplist_t pmenu;
1378 proplist_t pl;
1379 char *s;
1380 int i;
1383 s = WGetEditMenuTitle(menu);
1384 pl = PLMakeString(s);
1386 pmenu = PLMakeArrayFromElements(pl, NULL);
1388 i = 0;
1389 while ((item = WGetEditMenuItem(menu, i++))) {
1390 WEditMenu *submenu;
1392 s = WGetEditMenuItemTitle(item);
1394 submenu = WGetEditMenuSubmenu(menu, item);
1395 if (submenu) {
1396 pl = processSubmenu(submenu);
1397 } else {
1398 pl = processData(s, WGetEditMenuItemData(item));
1401 PLAppendArrayElement(pmenu, pl);
1404 return pmenu;
1409 static proplist_t
1410 buildPLFromMenu(_Panel *panel)
1412 proplist_t menu;
1414 menu = processSubmenu(panel->menu);
1416 return menu;
1422 static void
1423 storeData(_Panel *panel)
1425 proplist_t menu;
1427 if (panel->dontSave)
1428 return;
1430 menu = buildPLFromMenu(panel);
1432 PLSetFilename(menu, PLMakeString(panel->menuPath));
1434 PLSave(menu, YES);
1436 PLRelease(menu);
1440 Panel*
1441 InitMenu(WMScreen *scr, WMWindow *win)
1443 _Panel *panel;
1445 panel = wmalloc(sizeof(_Panel));
1446 memset(panel, 0, sizeof(_Panel));
1448 panel->sectionName = _("Applications Menu Definition");
1450 panel->description = _("Edit the menu for launching applications.");
1452 panel->win = win;
1454 panel->callbacks.createWidgets = createPanel;
1455 panel->callbacks.updateDomain = storeData;
1457 AddSection(panel, ICON_FILE);
1459 return panel;