- Slovak .po file updates from (Jan Tomka <judas@linux.sk>)
[wmaker-crm.git] / src / rootmenu.c
blobc7b3f84eda87e20da067675300777898565f9b50
1 /* rootmenu.c- user defined menu
2 *
3 * Window Maker window manager
4 *
5 * Copyright (c) 1997, 1998 Alfredo K. Kojima
6 * Copyright (c) 1998 Dan Pascu
7 *
8 * This program is free software; you can redistribute it and/or modify
9 * it under the terms of the GNU General Public License as published by
10 * the Free Software Foundation; either version 2 of the License, or
11 * (at your option) any later version.
13 * This program is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 * GNU General Public License for more details.
18 * You should have received a copy of the GNU General Public License
19 * along with this program; if not, write to the Free Software
20 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307,
21 * USA.
24 #include "wconfig.h"
26 #ifndef LITE
28 #include <stdio.h>
29 #include <stdlib.h>
30 #include <unistd.h>
31 #include <sys/stat.h>
32 #include <sys/wait.h>
33 #include <sys/types.h>
34 #include <string.h>
35 #include <ctype.h>
36 #include <time.h>
37 #include <dirent.h>
39 #include <X11/Xlib.h>
40 #include <X11/Xutil.h>
41 #include <X11/Xatom.h>
43 #include "WindowMaker.h"
44 #include "actions.h"
45 #include "menu.h"
46 #include "funcs.h"
47 #include "dialog.h"
48 #include "keybind.h"
49 #include "stacking.h"
50 #include "workspace.h"
51 #include "defaults.h"
52 #include "framewin.h"
53 #include "session.h"
54 #include "xmodifier.h"
56 #include <WINGs/WUtil.h>
60 extern char *Locale;
62 extern WDDomain *WDRootMenu;
64 extern Cursor wCursor[WCUR_LAST];
66 extern Time LastTimestamp;
68 extern WPreferences wPreferences;
70 extern int wScreenCount;
72 static WMenu *readMenuPipe(WScreen *scr, char **file_name);
73 static WMenu *readMenuFile(WScreen *scr, char *file_name);
74 static WMenu *readMenuDirectory(WScreen *scr, char *title, char **file_name,
75 char *command);
78 typedef struct Shortcut {
79 struct Shortcut *next;
81 int modifier;
82 KeyCode keycode;
83 WMenuEntry *entry;
84 WMenu *menu;
85 } Shortcut;
89 static Shortcut *shortcutList = NULL;
93 * Syntax:
94 * # main menu
95 * "Menu Name" MENU
96 * "Title" EXEC command_to_exec -params
97 * "Submenu" MENU
98 * "Title" EXEC command_to_exec -params
99 * "Submenu" END
100 * "Workspaces" WORKSPACE_MENU
101 * "Title" built_in_command
102 * "Quit" EXIT
103 * "Quick Quit" EXIT QUICK
104 * "Menu Name" END
106 * Commands may be preceded by SHORTCUT key
108 * Built-in commands:
110 * INFO_PANEL - shows the Info Panel
111 * LEGAL_PANEL - shows the Legal info panel
112 * SHUTDOWN [QUICK] - closes the X server [without confirmation]
113 * REFRESH - forces the desktop to be repainted
114 * EXIT [QUICK] - exit the window manager [without confirmation]
115 * EXEC <program> - execute an external program
116 * SHEXEC <command> - execute a shell command
117 * WORKSPACE_MENU - places the workspace submenu
118 * ARRANGE_ICONS
119 * RESTART [<window manager>] - restarts the window manager
120 * SHOW_ALL - unhide all windows on workspace
121 * HIDE_OTHERS - hides all windows excep the focused one
122 * OPEN_MENU file - read menu data from file which must be a valid menu file.
123 * OPEN_MENU /some/dir [/some/other/dir ...] [WITH command -options]
124 * - read menu data from directory(ies) and
125 * eventually precede each with a command.
126 * OPEN_MENU | command
127 * - opens command and uses its stdout to construct and insert
128 * the resulting menu in current position. The output of
129 * command must be a valid menu description.
130 * The space between '|' and command is optional.
131 * SAVE_SESSION - saves the current state of the desktop, which include
132 * all running applications, all their hints (geometry,
133 * position on screen, workspace they live on, the dock
134 * or clip from where they were launched, and
135 * if minimized, shaded or hidden. Also saves the current
136 * workspace the user is on. All will be restored on every
137 * start of windowmaker until another SAVE_SESSION or
138 * CLEAR_SESSION is used. If SaveSessionOnExit = Yes; in
139 * WindowMaker domain file, then saving is automatically
140 * done on every windowmaker exit, overwriting any
141 * SAVE_SESSION or CLEAR_SESSION (see below). Also save
142 * dock state now.
143 * CLEAR_SESSION - clears any previous saved session. This will not have
144 * any effect if SaveSessionOnExit is True.
148 #define M_QUICK 1
150 /* menu commands */
152 static void
153 execCommand(WMenu *menu, WMenuEntry *entry)
155 char *cmdline;
157 cmdline = ExpandOptions(menu->frame->screen_ptr, (char*)entry->clientdata);
159 XGrabPointer(dpy, menu->frame->screen_ptr->root_win, True, 0,
160 GrabModeAsync, GrabModeAsync, None, wCursor[WCUR_WAIT],
161 CurrentTime);
162 XSync(dpy, 0);
164 if (cmdline) {
165 ExecuteShellCommand(menu->frame->screen_ptr, cmdline);
166 wfree(cmdline);
168 XUngrabPointer(dpy, CurrentTime);
169 XSync(dpy, 0);
173 static void
174 exitCommand(WMenu *menu, WMenuEntry *entry)
176 static int inside = 0;
177 int result;
179 /* prevent reentrant calls */
180 if (inside)
181 return;
182 inside = 1;
184 #define R_CANCEL 0
185 #define R_EXIT 1
187 result = R_CANCEL;
189 if ((long)entry->clientdata==M_QUICK) {
190 result = R_EXIT;
191 } else {
192 int r, oldSaveSessionFlag;
194 oldSaveSessionFlag = wPreferences.save_session_on_exit;
195 r = wExitDialog(menu->frame->screen_ptr, _("Exit"),
196 _("Exit window manager?"),
197 _("Exit"), _("Cancel"), NULL);
199 if (r==WAPRDefault) {
200 result = R_EXIT;
201 } else if (r==WAPRAlternate) {
202 /* Don't modify the "save session on exit" flag if the
203 * user canceled the operation. */
204 wPreferences.save_session_on_exit = oldSaveSessionFlag;
207 if (result==R_EXIT) {
208 #ifdef DEBUG
209 printf("Exiting WindowMaker.\n");
210 #endif
211 Shutdown(WSExitMode);
213 #undef R_EXIT
214 #undef R_CANCEL
215 inside = 0;
219 static void
220 shutdownCommand(WMenu *menu, WMenuEntry *entry)
222 static int inside = 0;
223 int result;
225 /* prevent reentrant calls */
226 if (inside)
227 return;
228 inside = 1;
230 #define R_CANCEL 0
231 #define R_CLOSE 1
232 #define R_KILL 2
235 result = R_CANCEL;
236 if ((long)entry->clientdata==M_QUICK)
237 result = R_CLOSE;
238 else {
239 #ifdef XSMP_ENABLED
240 if (wSessionIsManaged()) {
241 int r;
243 r = wMessageDialog(menu->frame->screen_ptr,
244 _("Close X session"),
245 _("Close Window System session?\n"
246 "Kill might close applications with unsaved data."),
247 _("Close"), _("Kill"), _("Cancel"));
248 if (r==WAPRDefault)
249 result = R_CLOSE;
250 else if (r==WAPRAlternate)
251 result = R_KILL;
252 } else
253 #endif
255 int r, oldSaveSessionFlag;
257 oldSaveSessionFlag = wPreferences.save_session_on_exit;
259 r = wExitDialog(menu->frame->screen_ptr,
260 _("Kill X session"),
261 _("Kill Window System session?\n"
262 "(all applications will be closed)"),
263 _("Kill"), _("Cancel"), NULL);
264 if (r==WAPRDefault) {
265 result = R_KILL;
266 } else if (r==WAPRAlternate) {
267 /* Don't modify the "save session on exit" flag if the
268 * user canceled the operation. */
269 wPreferences.save_session_on_exit = oldSaveSessionFlag;
274 if (result!=R_CANCEL) {
275 #ifdef XSMP_ENABLED
276 if (result == R_CLOSE) {
277 Shutdown(WSLogoutMode);
278 } else
279 #endif /* XSMP_ENABLED */
281 Shutdown(WSKillMode);
284 #undef R_CLOSE
285 #undef R_CANCEL
286 #undef R_KILL
287 inside = 0;
291 static void
292 restartCommand(WMenu *menu, WMenuEntry *entry)
294 Shutdown(WSRestartPreparationMode);
295 Restart((char*)entry->clientdata, False);
296 Restart(NULL, True);
300 static void
301 refreshCommand(WMenu *menu, WMenuEntry *entry)
303 wRefreshDesktop(menu->frame->screen_ptr);
307 static void
308 arrangeIconsCommand(WMenu *menu, WMenuEntry *entry)
310 wArrangeIcons(menu->frame->screen_ptr, True);
313 static void
314 showAllCommand(WMenu *menu, WMenuEntry *entry)
316 wShowAllWindows(menu->frame->screen_ptr);
319 static void
320 hideOthersCommand(WMenu *menu, WMenuEntry *entry)
322 wHideOtherApplications(menu->frame->screen_ptr->focused_window);
326 static void
327 saveSessionCommand(WMenu *menu, WMenuEntry *entry)
329 if (!wPreferences.save_session_on_exit)
330 wSessionSaveState(menu->frame->screen_ptr);
332 wScreenSaveState(menu->frame->screen_ptr);
336 static void
337 clearSessionCommand(WMenu *menu, WMenuEntry *entry)
339 wSessionClearState(menu->frame->screen_ptr);
343 static void
344 infoPanelCommand(WMenu *menu, WMenuEntry *entry)
346 wShowInfoPanel(menu->frame->screen_ptr);
350 static void
351 legalPanelCommand(WMenu *menu, WMenuEntry *entry)
353 wShowLegalPanel(menu->frame->screen_ptr);
357 /********************************************************************/
360 static char*
361 getLocalizedMenuFile(char *menu)
363 char *buffer;
364 char *ptr;
365 int len;
367 if (!Locale)
368 return NULL;
370 len = strlen(menu)+strlen(Locale)+8;
371 buffer = wmalloc(len);
373 /* try menu.locale_name */
374 snprintf(buffer, len, "%s.%s", menu, Locale);
375 if (access(buffer, F_OK)==0) {
376 return buffer;
378 /* check if it is in the form aa_bb.encoding and check for aa_bb */
379 ptr = strchr(Locale, '.');
380 if (ptr) {
381 *ptr = 0;
382 if (access(buffer, F_OK)==0) {
383 return buffer;
386 /* now check for aa */
387 ptr = strchr(buffer, '_');
388 if (ptr) {
389 *ptr = 0;
390 if (access(buffer, F_OK)==0) {
391 return buffer;
395 return NULL;
399 static void
400 raiseMenus(WMenu *menu)
402 int i;
404 if (menu->flags.mapped) {
405 wRaiseFrame(menu->frame->core);
407 for (i=0; i<menu->cascade_no; i++) {
408 if (menu->cascades[i])
409 raiseMenus(menu->cascades[i]);
415 Bool
416 wRootMenuPerformShortcut(XEvent *event)
418 Shortcut *ptr;
419 int modifiers;
420 int done = 0;
422 /* ignore CapsLock */
423 modifiers = event->xkey.state & ValidModMask;
425 for (ptr = shortcutList; ptr!=NULL; ptr = ptr->next) {
426 if (ptr->keycode==0)
427 continue;
429 if (ptr->keycode==event->xkey.keycode && (ptr->modifier==modifiers)) {
430 (*ptr->entry->callback)(ptr->menu, ptr->entry);
431 done = True;
434 return done;
438 void
439 wRootMenuBindShortcuts(Window window)
441 Shortcut *ptr;
443 ptr = shortcutList;
444 while (ptr) {
445 if (ptr->modifier!=AnyModifier) {
446 XGrabKey(dpy, ptr->keycode, ptr->modifier|LockMask,
447 window, True, GrabModeAsync, GrabModeAsync);
448 #ifdef NUMLOCK_HACK
449 wHackedGrabKey(ptr->keycode, ptr->modifier,
450 window, True, GrabModeAsync, GrabModeAsync);
451 #endif
453 XGrabKey(dpy, ptr->keycode, ptr->modifier, window, True,
454 GrabModeAsync, GrabModeAsync);
455 ptr = ptr->next;
460 static void
461 rebindKeygrabs(WScreen *scr)
463 WWindow *wwin;
465 wwin = scr->focused_window;
467 while (wwin!=NULL) {
468 XUngrabKey(dpy, AnyKey, AnyModifier, wwin->frame->core->window);
470 if (!WFLAGP(wwin, no_bind_keys)) {
471 wWindowSetKeyGrabs(wwin);
473 wwin = wwin->prev;
478 static void
479 removeShortcutsForMenu(WMenu *menu)
481 Shortcut *ptr, *tmp;
482 Shortcut *newList = NULL;
484 ptr = shortcutList;
485 while (ptr!=NULL) {
486 tmp = ptr->next;
487 if (ptr->menu == menu) {
488 wfree(ptr);
489 } else {
490 ptr->next = newList;
491 newList = ptr;
493 ptr = tmp;
495 shortcutList = newList;
496 menu->menu->screen_ptr->flags.root_menu_changed_shortcuts = 1;
500 static Bool
501 addShortcut(char *file, char *shortcutDefinition, WMenu *menu,
502 WMenuEntry *entry)
504 Shortcut *ptr;
505 KeySym ksym;
506 char *k;
507 char buf[128], *b;
509 ptr = wmalloc(sizeof(Shortcut));
511 strcpy(buf, shortcutDefinition);
512 b = (char*)buf;
514 /* get modifiers */
515 ptr->modifier = 0;
516 while ((k = strchr(b, '+'))!=NULL) {
517 int mod;
519 *k = 0;
520 mod = wXModifierFromKey(b);
521 if (mod<0) {
522 wwarning(_("%s:invalid key modifier \"%s\""), file, b);
523 wfree(ptr);
524 return False;
526 ptr->modifier |= mod;
528 b = k+1;
531 /* get key */
532 ksym = XStringToKeysym(b);
534 if (ksym==NoSymbol) {
535 wwarning(_("%s:invalid kbd shortcut specification \"%s\" for entry %s"),
536 file, shortcutDefinition, entry->text);
537 wfree(ptr);
538 return False;
541 ptr->keycode = XKeysymToKeycode(dpy, ksym);
542 if (ptr->keycode==0) {
543 wwarning(_("%s:invalid key in shortcut \"%s\" for entry %s"), file,
544 shortcutDefinition, entry->text);
545 wfree(ptr);
546 return False;
549 ptr->menu = menu;
550 ptr->entry = entry;
552 ptr->next = shortcutList;
553 shortcutList = ptr;
555 menu->menu->screen_ptr->flags.root_menu_changed_shortcuts = 1;
557 return True;
561 /*******************************/
563 static char*
564 cropline(char *line)
566 char *end;
568 if (strlen(line)==0)
569 return line;
571 end = &(line[strlen(line)])-1;
572 while (isspace(*line) && *line!=0) line++;
573 while (end>line && isspace(*end)) {
574 *end=0;
575 end--;
577 return line;
581 static char*
582 next_token(char *line, char **next)
584 char *tmp, c;
585 char *ret;
587 *next = NULL;
588 while (*line==' ' || *line=='\t') line++;
590 tmp = line;
592 if (*tmp=='"') {
593 tmp++; line++;
594 while (*tmp!=0 && *tmp!='"') tmp++;
595 if (*tmp!='"') {
596 wwarning(_("%s: unmatched '\"' in menu file"), line);
597 return NULL;
599 } else {
600 do {
601 if (*tmp=='\\')
602 tmp++;
604 if (*tmp!=0)
605 tmp++;
607 } while (*tmp!=0 && *tmp!=' ' && *tmp!='\t');
610 c = *tmp;
611 *tmp = 0;
612 ret = wstrdup(line);
613 *tmp = c;
615 if (c==0)
616 return ret;
617 else
618 tmp++;
620 /* skip blanks */
621 while (*tmp==' ' || *tmp=='\t') tmp++;
623 if (*tmp!=0)
624 *next = tmp;
626 return ret;
630 static void
631 separateCommand(char *line, char ***file, char **command)
633 char *token, *tmp = line;
634 WMArray *array = WMCreateArray(4);
635 int count, i;
637 *file = NULL;
638 *command = NULL;
639 do {
640 token = next_token(tmp, &tmp);
641 if (token) {
642 if (strcmp(token, "WITH")==0) {
643 if (tmp!=NULL && *tmp!=0)
644 *command = wstrdup(tmp);
645 else
646 wwarning(_("%s: missing command"), line);
647 break;
649 WMAddToArray(array, token);
651 } while (token!=NULL && tmp!=NULL);
653 count = WMGetArrayItemCount(array);
654 if (count>0) {
655 *file = wmalloc(sizeof(char*)*(count+1));
656 (*file)[count] = NULL;
657 for (i = 0; i < count; i++) {
658 (*file)[i] = WMGetFromArray(array, i);
661 WMFreeArray(array);
665 static void
666 constructMenu(WMenu *menu, WMenuEntry *entry)
668 WMenu *submenu;
669 struct stat stat_buf;
670 char **path;
671 char *cmd;
672 char *lpath = NULL;
673 int i, first=-1;
674 time_t last=0;
676 separateCommand((char*)entry->clientdata, &path, &cmd);
677 if (path == NULL || *path==NULL || **path==0) {
678 wwarning(_("invalid OPEN_MENU specification: %s"),
679 (char*)entry->clientdata);
680 return;
683 if (path[0][0]=='|') {
684 /* pipe menu */
686 if (!menu->cascades[entry->cascade] ||
687 menu->cascades[entry->cascade]->timestamp == 0) {
688 /* parse pipe */
690 submenu = readMenuPipe(menu->frame->screen_ptr, path);
692 /* there's no automatic reloading */
693 if(submenu != NULL)
694 submenu->timestamp = 1;
695 } else {
696 submenu = NULL;
699 } else {
700 i=0;
701 while(path[i] != NULL) {
702 char *tmp;
704 if (strcmp(path[i], "-noext")==0) {
705 i++;
706 continue;
709 tmp = wexpandpath(path[i]);
710 wfree(path[i]);
711 lpath = getLocalizedMenuFile(tmp);
712 if (lpath) {
713 wfree(tmp);
714 path[i] = lpath;
715 lpath = NULL;
716 } else {
717 path[i] = tmp;
720 if (stat(path[i], &stat_buf)==0) {
721 if (last < stat_buf.st_mtime)
722 last = stat_buf.st_mtime;
723 if (first<0)
724 first=i;
725 } else {
726 wsyserror(_("%s:could not stat menu"), path[i]);
727 /*goto finish;*/
730 i++;
733 if (first < 0) {
734 wsyserror(_("%s:could not stat menu:%s"), "OPEN_MENU",
735 (char*)entry->clientdata);
736 goto finish;
738 stat(path[first], &stat_buf);
739 if (!menu->cascades[entry->cascade]
740 || menu->cascades[entry->cascade]->timestamp < last) {
742 if (S_ISDIR(stat_buf.st_mode)) {
743 /* menu directory */
744 submenu = readMenuDirectory(menu->frame->screen_ptr,
745 entry->text, path, cmd);
746 if (submenu)
747 submenu->timestamp = last;
748 } else if (S_ISREG(stat_buf.st_mode)) {
749 /* menu file */
751 if (cmd || path[1])
752 wwarning(_("too many parameters in OPEN_MENU: %s"),
753 (char*)entry->clientdata);
755 submenu = readMenuFile(menu->frame->screen_ptr, path[first]);
756 if (submenu)
757 submenu->timestamp = stat_buf.st_mtime;
758 } else {
759 submenu = NULL;
761 } else {
762 submenu = NULL;
766 if (submenu) {
767 wMenuEntryRemoveCascade(menu, entry);
768 wMenuEntrySetCascade(menu, entry, submenu);
771 finish:
772 i = 0;
773 while (path[i]!=NULL)
774 wfree(path[i++]);
775 wfree(path);
776 if (cmd)
777 wfree(cmd);
781 static void
782 cleanupWorkspaceMenu(WMenu *menu)
784 if (menu->frame->screen_ptr->workspace_menu == menu)
785 menu->frame->screen_ptr->workspace_menu = NULL;
789 static WMenuEntry*
790 addWorkspaceMenu(WScreen *scr, WMenu *menu, char *title)
792 WMenu *wsmenu;
793 WMenuEntry *entry;
795 if (scr->flags.added_workspace_menu) {
796 wwarning(_("There are more than one WORKSPACE_MENU commands in the applications menu. Only one is allowed."));
797 return NULL;
798 } else {
799 scr->flags.added_workspace_menu = 1;
801 wsmenu = wWorkspaceMenuMake(scr, True);
802 wsmenu->on_destroy = cleanupWorkspaceMenu;
804 scr->workspace_menu = wsmenu;
805 entry = wMenuAddCallback(menu, title, NULL, NULL);
806 wMenuEntrySetCascade(menu, entry, wsmenu);
808 wWorkspaceMenuUpdate(scr, wsmenu);
810 return entry;
814 static void
815 cleanupWindowsMenu(WMenu *menu)
817 if (menu->frame->screen_ptr->switch_menu == menu)
818 menu->frame->screen_ptr->switch_menu = NULL;
822 static WMenuEntry*
823 addWindowsMenu(WScreen *scr, WMenu *menu, char *title)
825 WMenu *wwmenu;
826 WWindow *wwin;
827 WMenuEntry *entry;
829 if (scr->flags.added_windows_menu) {
830 wwarning(_("There are more than one WINDOWS_MENU commands in the applications menu. Only one is allowed."));
831 return NULL;
832 } else {
833 scr->flags.added_windows_menu = 1;
835 wwmenu = wMenuCreate(scr, _("Window List"), False);
836 wwmenu->on_destroy = cleanupWindowsMenu;
837 scr->switch_menu = wwmenu;
838 wwin = scr->focused_window;
839 while (wwin) {
840 UpdateSwitchMenu(scr, wwin, ACTION_ADD);
842 wwin = wwin->prev;
844 entry = wMenuAddCallback(menu, title, NULL, NULL);
845 wMenuEntrySetCascade(menu, entry, wwmenu);
847 return entry;
851 static WMenuEntry*
852 addMenuEntry(WMenu *menu, char *title, char *shortcut, char *command,
853 char *params, char *file_name)
855 WScreen *scr;
856 WMenuEntry *entry = NULL;
857 Bool shortcutOk = False;
859 if (!menu)
860 return NULL;
861 scr = menu->frame->screen_ptr;
862 if (strcmp(command, "OPEN_MENU")==0) {
863 if (!params) {
864 wwarning(_("%s:missing parameter for menu command \"%s\""),
865 file_name, command);
866 } else {
867 WMenu *dummy;
868 char *path;
870 path = wfindfile(DEF_CONFIG_PATHS, params);
871 if (!path) {
872 path = wstrdup(params);
874 dummy = wMenuCreate(scr, title, False);
875 dummy->on_destroy = removeShortcutsForMenu;
876 entry = wMenuAddCallback(menu, title, constructMenu, path);
877 entry->free_cdata = free;
878 wMenuEntrySetCascade(menu, entry, dummy);
880 } else if (strcmp(command, "EXEC")==0) {
881 if (!params)
882 wwarning(_("%s:missing parameter for menu command \"%s\""),
883 file_name, command);
884 else {
885 entry = wMenuAddCallback(menu, title, execCommand,
886 wstrconcat("exec ", params));
887 entry->free_cdata = free;
888 shortcutOk = True;
890 } else if (strcmp(command, "SHEXEC")==0) {
891 if (!params)
892 wwarning(_("%s:missing parameter for menu command \"%s\""),
893 file_name, command);
894 else {
895 entry = wMenuAddCallback(menu, title, execCommand,
896 wstrdup(params));
897 entry->free_cdata = free;
898 shortcutOk = True;
900 } else if (strcmp(command, "EXIT")==0) {
902 if (params && strcmp(params, "QUICK")==0)
903 entry = wMenuAddCallback(menu, title, exitCommand, (void*)M_QUICK);
904 else
905 entry = wMenuAddCallback(menu, title, exitCommand, NULL);
907 shortcutOk = True;
908 } else if (strcmp(command, "SHUTDOWN")==0) {
910 if (params && strcmp(params, "QUICK")==0)
911 entry = wMenuAddCallback(menu, title, shutdownCommand,
912 (void*)M_QUICK);
913 else
914 entry = wMenuAddCallback(menu, title, shutdownCommand, NULL);
916 shortcutOk = True;
917 } else if (strcmp(command, "REFRESH")==0) {
918 entry = wMenuAddCallback(menu, title, refreshCommand, NULL);
920 shortcutOk = True;
921 } else if (strcmp(command, "WORKSPACE_MENU")==0) {
922 entry = addWorkspaceMenu(scr, menu, title);
924 shortcutOk = True;
925 } else if (strcmp(command, "WINDOWS_MENU")==0) {
926 entry = addWindowsMenu(scr, menu, title);
928 shortcutOk = True;
929 } else if (strcmp(command, "ARRANGE_ICONS")==0) {
930 entry = wMenuAddCallback(menu, title, arrangeIconsCommand, NULL);
932 shortcutOk = True;
933 } else if (strcmp(command, "HIDE_OTHERS")==0) {
934 entry = wMenuAddCallback(menu, title, hideOthersCommand, NULL);
936 shortcutOk = True;
937 } else if (strcmp(command, "SHOW_ALL")==0) {
938 entry = wMenuAddCallback(menu, title, showAllCommand, NULL);
940 shortcutOk = True;
941 } else if (strcmp(command, "RESTART")==0) {
942 entry = wMenuAddCallback(menu, title, restartCommand,
943 params ? wstrdup(params) : NULL);
944 entry->free_cdata = free;
945 shortcutOk = True;
946 } else if (strcmp(command, "SAVE_SESSION")==0) {
947 entry = wMenuAddCallback(menu, title, saveSessionCommand, NULL);
949 shortcutOk = True;
950 } else if (strcmp(command, "CLEAR_SESSION")==0) {
951 entry = wMenuAddCallback(menu, title, clearSessionCommand, NULL);
952 shortcutOk = True;
953 } else if (strcmp(command, "INFO_PANEL")==0) {
954 entry = wMenuAddCallback(menu, title, infoPanelCommand, NULL);
955 shortcutOk = True;
956 } else if (strcmp(command, "LEGAL_PANEL")==0) {
957 entry = wMenuAddCallback(menu, title, legalPanelCommand, NULL);
958 shortcutOk = True;
959 } else {
960 wwarning(_("%s:unknown command \"%s\" in menu config."), file_name,
961 command);
963 return NULL;
966 if (shortcut && entry) {
967 if (!shortcutOk) {
968 wwarning(_("%s:can't add shortcut for entry \"%s\""), file_name,
969 title);
970 } else {
971 if (addShortcut(file_name, shortcut, menu, entry)) {
973 entry->rtext = GetShortcutString(shortcut);
975 entry->rtext = wstrdup(shortcut);
981 return entry;
986 /******************* Menu Configuration From File *******************/
988 static void
989 separateline(char *line, char *title, char *command, char *parameter,
990 char *shortcut)
992 int l, i;
994 l = strlen(line);
996 *title = 0;
997 *command = 0;
998 *parameter = 0;
999 *shortcut = 0;
1000 /* get the title */
1001 while (isspace(*line) && (*line!=0)) line++;
1002 if (*line=='"') {
1003 line++;
1004 i=0;
1005 while (line[i]!='"' && (line[i]!=0)) i++;
1006 if (line[i]!='"')
1007 return;
1008 } else {
1009 i=0;
1010 while (!isspace(line[i]) && (line[i]!=0)) i++;
1012 strncpy(title, line, i);
1013 title[i++]=0;
1014 line+=i;
1016 /* get the command or shortcut keyword */
1017 while (isspace(*line) && (*line!=0)) line++;
1018 if (*line==0)
1019 return;
1020 i=0;
1021 while (!isspace(line[i]) && (line[i]!=0)) i++;
1022 strncpy(command, line, i);
1023 command[i++]=0;
1024 line+=i;
1026 if (strcmp(command, "SHORTCUT")==0) {
1027 /* get the shortcut key */
1028 while (isspace(*line) && (*line!=0)) line++;
1029 if (*line=='"') {
1030 line++;
1031 i=0;
1032 while (line[i]!='"' && (line[i]!=0)) i++;
1033 if (line[i]!='"')
1034 return;
1035 } else {
1036 i=0;
1037 while (!isspace(line[i]) && (line[i]!=0)) i++;
1039 strncpy(shortcut, line, i);
1040 shortcut[i++]=0;
1041 line+=i;
1043 *command=0;
1045 /* get the command */
1046 while (isspace(*line) && (*line!=0)) line++;
1047 if (*line==0)
1048 return;
1049 i=0;
1050 while (!isspace(line[i]) && (line[i]!=0)) i++;
1051 strncpy(command, line, i);
1052 command[i++]=0;
1053 line+=i;
1056 /* get the parameters */
1057 while (isspace(*line) && (*line!=0)) line++;
1058 if (*line==0)
1059 return;
1061 if (*line=='"') {
1062 line++;
1063 l = 0;
1064 while (line[l]!=0 && line[l]!='"') {
1065 parameter[l] = line[l];
1066 l++;
1068 parameter[l] = 0;
1069 return;
1072 l = strlen(line);
1073 while (isspace(line[l]) && (l>0)) l--;
1074 strncpy(parameter, line, l);
1075 parameter[l]=0;
1079 static WMenu*
1080 parseCascade(WScreen *scr, WMenu *menu, FILE *file, char *file_name)
1082 char linebuf[MAXLINE];
1083 char elinebuf[MAXLINE];
1084 char title[MAXLINE];
1085 char command[MAXLINE];
1086 char shortcut[MAXLINE];
1087 char params[MAXLINE];
1088 char *line;
1090 while (!IsEof(file)) {
1091 int lsize, ok;
1093 ok = 0;
1094 fgets(linebuf, MAXLINE, file);
1095 line = cropline(linebuf);
1096 lsize = strlen(line);
1097 do {
1098 if (line[lsize-1]=='\\') {
1099 char *line2;
1100 int lsize2;
1101 fgets(elinebuf, MAXLINE, file);
1102 line2=cropline(elinebuf);
1103 lsize2=strlen(line2);
1104 if (lsize2+lsize>MAXLINE) {
1105 wwarning(_("%s:maximal line size exceeded in menu config: %s"),
1106 file_name, line);
1107 ok=2;
1108 } else {
1109 line[lsize-1]=0;
1110 lsize+=lsize2-1;
1111 strcat(line, line2);
1113 } else {
1114 ok=1;
1116 } while (!ok && !IsEof(file));
1117 if (ok==2)
1118 continue;
1120 if (line[0]==0 || line[0]=='#' || (line[0]=='/' && line[1]=='/'))
1121 continue;
1124 separateline(line, title, command, params, shortcut);
1126 if (!command[0]) {
1127 wwarning(_("%s:missing command in menu config: %s"), file_name,
1128 line);
1129 goto error;
1132 if (strcasecmp(command, "MENU")==0) {
1133 WMenu *cascade;
1135 /* start submenu */
1137 cascade = wMenuCreate(scr, title, False);
1138 cascade->on_destroy = removeShortcutsForMenu;
1139 if (parseCascade(scr, cascade, file, file_name)==NULL) {
1140 wMenuDestroy(cascade, True);
1141 } else {
1142 wMenuEntrySetCascade(menu,
1143 wMenuAddCallback(menu, title, NULL, NULL),
1144 cascade);
1146 } else if (strcasecmp(command, "END")==0) {
1147 /* end of menu */
1148 return menu;
1150 } else {
1151 /* normal items */
1152 addMenuEntry(menu, title, shortcut[0] ? shortcut : NULL, command,
1153 params[0] ? params : NULL, file_name);
1157 wwarning(_("%s:syntax error in menu file:END declaration missing"),
1158 file_name);
1159 return menu;
1161 error:
1162 return menu;
1166 static WMenu*
1167 readMenuFile(WScreen *scr, char *file_name)
1169 WMenu *menu=NULL;
1170 FILE *file = NULL;
1171 char linebuf[MAXLINE];
1172 char title[MAXLINE];
1173 char shortcut[MAXLINE];
1174 char command[MAXLINE];
1175 char params[MAXLINE];
1176 char *line;
1177 #ifdef USECPP
1178 char *args;
1179 int cpp = 0;
1180 #endif
1182 #ifdef USECPP
1183 if (!wPreferences.flags.nocpp) {
1184 args = MakeCPPArgs(file_name);
1185 if (!args) {
1186 wwarning(_("could not make arguments for menu file preprocessor"));
1187 } else {
1188 snprintf(command, sizeof(command), "%s %s %s",
1189 CPP_PATH, args, file_name);
1190 wfree(args);
1191 file = popen(command, "r");
1192 if (!file) {
1193 wsyserror(_("%s:could not open/preprocess menu file"),
1194 file_name);
1195 } else {
1196 cpp = 1;
1200 #endif /* USECPP */
1202 if (!file) {
1203 file = fopen(file_name, "r");
1204 if (!file) {
1205 wsyserror(_("%s:could not open menu file"), file_name);
1206 return NULL;
1210 while (!IsEof(file)) {
1211 if (!fgets(linebuf, MAXLINE, file))
1212 break;
1213 line = cropline(linebuf);
1214 if (line[0]==0 || line[0]=='#' || (line[0]=='/' && line[1]=='/'))
1215 continue;
1217 separateline(line, title, command, params, shortcut);
1219 if (!command[0]) {
1220 wwarning(_("%s:missing command in menu config: %s"), file_name,
1221 line);
1222 break;
1224 if (strcasecmp(command, "MENU")==0) {
1225 menu = wMenuCreate(scr, title, True);
1226 menu->on_destroy = removeShortcutsForMenu;
1227 if (!parseCascade(scr, menu, file, file_name)) {
1228 wMenuDestroy(menu, True);
1230 break;
1231 } else {
1232 wwarning(_("%s:invalid menu file. MENU command is missing"),
1233 file_name);
1234 break;
1238 #ifdef CPP
1239 if (cpp) {
1240 if (pclose(file)==-1) {
1241 wsyserror(_("error reading preprocessed menu data"));
1243 } else {
1244 fclose(file);
1246 #else
1247 fclose(file);
1248 #endif
1250 return menu;
1253 /************ Menu Configuration From Pipe *************/
1255 static WMenu*
1256 readMenuPipe(WScreen *scr, char **file_name)
1258 WMenu *menu=NULL;
1259 FILE *file = NULL;
1260 char linebuf[MAXLINE];
1261 char title[MAXLINE];
1262 char command[MAXLINE];
1263 char params[MAXLINE];
1264 char shortcut[MAXLINE];
1265 char *line;
1266 char *filename;
1267 char flat_file[MAXLINE];
1268 int i;
1269 #ifdef USECPP
1270 char *args;
1271 int cpp = 0;
1272 #endif
1274 flat_file[0] = '\0';
1276 for(i=0; file_name[i]!=NULL; i++) {
1277 strcat(flat_file, file_name[i]);
1278 strcat(flat_file, " ");
1280 filename = flat_file+1;
1282 #ifdef USECPP
1283 if (!wPreferences.flags.nocpp) {
1284 args = MakeCPPArgs(filename);
1285 if (!args) {
1286 wwarning(_("could not make arguments for menu file preprocessor"));
1287 } else {
1288 snprintf(command, sizeof(command), "%s | %s %s",
1289 filename, CPP_PATH, args);
1291 wfree(args);
1292 file = popen(command, "r");
1293 if (!file) {
1294 wsyserror(_("%s:could not open/preprocess menu file"), filename);
1295 } else {
1296 cpp = 1;
1301 #endif /* USECPP */
1303 if (!file) {
1304 file = popen(filename, "r");
1306 if (!file) {
1307 wsyserror(_("%s:could not open menu file"), filename);
1308 return NULL;
1312 while (!IsEof(file)) {
1313 if (!fgets(linebuf, MAXLINE, file))
1314 break;
1315 line = cropline(linebuf);
1316 if (line[0]==0 || line[0]=='#' || (line[0]=='/' && line[1]=='/'))
1317 continue;
1319 separateline(line, title, command, params, shortcut);
1321 if (!command[0]) {
1322 wwarning(_("%s:missing command in menu config: %s"), file_name,
1323 line);
1324 break;
1326 if (strcasecmp(command, "MENU")==0) {
1327 menu = wMenuCreate(scr, title, True);
1328 menu->on_destroy = removeShortcutsForMenu;
1329 if (!parseCascade(scr, menu, file, filename)) {
1330 wMenuDestroy(menu, True);
1332 break;
1333 } else {
1334 wwarning(_("%s:no title given for the root menu"), filename);
1335 break;
1339 pclose(file);
1341 return menu;
1346 typedef struct {
1347 char *name;
1348 int index;
1349 } dir_data;
1352 static int
1353 myCompare(const void *d1, const void *d2)
1355 dir_data *p1 = *(dir_data**)d1;
1356 dir_data *p2 = *(dir_data**)d2;
1358 return strcmp(p1->name, p2->name);
1362 /************ Menu Configuration From Directory *************/
1364 static Bool
1365 isFilePackage(char *file)
1367 int l;
1369 /* check if the extension indicates this file is a
1370 * file package. For now, only recognize .themed */
1372 l = strlen(file);
1374 if (l > 7 && strcmp(&(file[l-7]), ".themed")==0) {
1375 return True;
1376 } else {
1377 return False;
1382 static WMenu*
1383 readMenuDirectory(WScreen *scr, char *title, char **path, char *command)
1385 DIR *dir;
1386 struct dirent *dentry;
1387 struct stat stat_buf;
1388 WMenu *menu=NULL;
1389 char *buffer;
1390 WMArray *dirs = NULL, *files = NULL;
1391 WMArrayIterator iter;
1392 int length, i, have_space=0;
1393 dir_data *data;
1394 int stripExtension = 0;
1397 dirs = WMCreateArray(16);
1398 files = WMCreateArray(16);
1400 i=0;
1401 while (path[i]!=NULL) {
1402 if (strcmp(path[i], "-noext")==0) {
1403 stripExtension = 1;
1404 i++;
1405 continue;
1408 dir = opendir(path[i]);
1409 if (!dir) {
1410 i++;
1411 continue;
1414 while ((dentry = readdir(dir))) {
1416 if (strcmp(dentry->d_name, ".")==0 ||
1417 strcmp(dentry->d_name, "..")==0)
1418 continue;
1420 if (dentry->d_name[0] == '.')
1421 continue;
1423 buffer = malloc(strlen(path[i])+strlen(dentry->d_name)+4);
1424 if (!buffer) {
1425 wsyserror(_("out of memory while constructing directory menu %s"),
1426 path[i]);
1427 break;
1430 strcpy(buffer, path[i]);
1431 strcat(buffer, "/");
1432 strcat(buffer, dentry->d_name);
1434 if (stat(buffer, &stat_buf)!=0) {
1435 wsyserror(_("%s:could not stat file \"%s\" in menu directory"),
1436 path[i], dentry->d_name);
1437 } else {
1438 Bool isFilePack = False;
1440 data = NULL;
1441 if (S_ISDIR(stat_buf.st_mode)
1442 && !(isFilePack = isFilePackage(dentry->d_name))) {
1444 /* access always returns success for user root */
1445 if (access(buffer, X_OK)==0) {
1446 /* Directory is accesible. Add to directory list */
1448 data = (dir_data*) wmalloc(sizeof(dir_data));
1449 data->name = wstrdup(dentry->d_name);
1450 data->index = i;
1452 WMAddToArray(dirs, data);
1454 } else if (S_ISREG(stat_buf.st_mode) || isFilePack) {
1455 /* Hack because access always returns X_OK success for user root */
1456 #define S_IXANY (S_IXUSR | S_IXGRP | S_IXOTH)
1457 if ((command!=NULL && access(buffer, R_OK)==0) ||
1458 (command==NULL && access(buffer, X_OK)==0 &&
1459 (stat_buf.st_mode & S_IXANY))) {
1461 data = (dir_data*) wmalloc(sizeof(dir_data));
1462 data->name = wstrdup(dentry->d_name);
1463 data->index = i;
1465 WMAddToArray(files, data);
1469 wfree(buffer);
1472 closedir(dir);
1473 i++;
1476 if (!WMGetArrayItemCount(dirs) && !WMGetArrayItemCount(files)) {
1477 WMFreeArray(dirs);
1478 WMFreeArray(files);
1479 return NULL;
1482 WMSortArray(dirs, myCompare);
1483 WMSortArray(files, myCompare);
1485 menu = wMenuCreate(scr, title, False);
1486 menu->on_destroy = removeShortcutsForMenu;
1488 WM_ITERATE_ARRAY(dirs, data, iter) {
1489 /* New directory. Use same OPEN_MENU command that was used
1490 * for the current directory. */
1491 length = strlen(path[data->index])+strlen(data->name)+6;
1492 if (stripExtension)
1493 length += 7;
1494 if (command)
1495 length += strlen(command) + 6;
1496 buffer = malloc(length);
1497 if (!buffer) {
1498 wsyserror(_("out of memory while constructing directory menu %s"),
1499 path[data->index]);
1500 break;
1503 buffer[0] = '\0';
1504 if (stripExtension)
1505 strcat(buffer, "-noext ");
1507 have_space = strchr(path[data->index], ' ')!=NULL ||
1508 strchr(data->name, ' ')!=NULL;
1510 if (have_space)
1511 strcat(buffer, "\"");
1512 strcat(buffer, path[data->index]);
1514 strcat(buffer, "/");
1515 strcat(buffer, data->name);
1516 if (have_space)
1517 strcat(buffer, "\"");
1518 if (command) {
1519 strcat(buffer, " WITH ");
1520 strcat(buffer, command);
1523 addMenuEntry(menu, data->name, NULL, "OPEN_MENU", buffer, path[data->index]);
1525 wfree(buffer);
1526 if (data->name)
1527 wfree(data->name);
1528 wfree(data);
1531 WM_ITERATE_ARRAY(files, data, iter) {
1532 /* executable: add as entry */
1533 length = strlen(path[data->index])+strlen(data->name)+6;
1534 if (command)
1535 length += strlen(command);
1537 buffer = malloc(length);
1538 if (!buffer) {
1539 wsyserror(_("out of memory while constructing directory menu %s"),
1540 path[data->index]);
1541 break;
1544 have_space = strchr(path[data->index], ' ')!=NULL ||
1545 strchr(data->name, ' ')!=NULL;
1546 if (command!=NULL) {
1547 strcpy(buffer, command);
1548 strcat(buffer, " ");
1549 if (have_space)
1550 strcat(buffer, "\"");
1551 strcat(buffer, path[data->index]);
1552 } else {
1553 if (have_space) {
1554 buffer[0] = '"';
1555 buffer[1] = 0;
1556 strcat(buffer, path[data->index]);
1557 } else {
1558 strcpy(buffer, path[data->index]);
1561 strcat(buffer, "/");
1562 strcat(buffer, data->name);
1563 if (have_space)
1564 strcat(buffer, "\"");
1566 if (stripExtension) {
1567 char *ptr = strrchr(data->name, '.');
1568 if (ptr && ptr!=data->name)
1569 *ptr = 0;
1571 addMenuEntry(menu, data->name, NULL, "SHEXEC", buffer, path[data->index]);
1573 wfree(buffer);
1574 if (data->name)
1575 wfree(data->name);
1576 wfree(data);
1579 WMFreeArray(files);
1580 WMFreeArray(dirs);
1582 return menu;
1586 /************ Menu Configuration From WMRootMenu *************/
1588 static WMenu*
1589 makeDefaultMenu(WScreen *scr)
1591 WMenu *menu=NULL;
1593 menu = wMenuCreate(scr, _("Commands"), True);
1594 wMenuAddCallback(menu, "XTerm", execCommand, "xterm");
1595 wMenuAddCallback(menu, "rxvt", execCommand, "rxvt");
1596 wMenuAddCallback(menu, _("Restart"), restartCommand, NULL);
1597 wMenuAddCallback(menu, _("Exit..."), exitCommand, NULL);
1598 return menu;
1606 *----------------------------------------------------------------------
1607 * configureMenu--
1608 * Reads root menu configuration from defaults database.
1610 *----------------------------------------------------------------------
1612 static WMenu*
1613 configureMenu(WScreen *scr, WMPropList *definition)
1615 WMenu *menu = NULL;
1616 WMPropList *elem;
1617 int i, count;
1618 WMPropList *title, *command, *params;
1619 char *tmp, *mtitle;
1622 if (WMIsPLString(definition)) {
1623 struct stat stat_buf;
1624 char *path = NULL;
1625 Bool menu_is_default = False;
1627 /* menu definition is a string. Probably a path, so parse the file */
1629 tmp = wexpandpath(WMGetFromPLString(definition));
1631 path = getLocalizedMenuFile(tmp);
1633 if (!path)
1634 path = wfindfile(DEF_CONFIG_PATHS, tmp);
1636 if (!path) {
1637 path = wfindfile(DEF_CONFIG_PATHS, DEF_MENU_FILE);
1638 menu_is_default = True;
1641 if (!path) {
1642 wsyserror(_("could not find menu file \"%s\" referenced in WMRootMenu"),
1643 tmp);
1644 wfree(tmp);
1645 return NULL;
1648 if (stat(path, &stat_buf)<0) {
1649 wsyserror(_("could not access menu \"%s\" referenced in WMRootMenu"), path);
1650 wfree(path);
1651 wfree(tmp);
1652 return NULL;
1655 if (!scr->root_menu || stat_buf.st_mtime > scr->root_menu->timestamp
1656 /* if the pointer in WMRootMenu has changed */
1657 || WDRootMenu->timestamp > scr->root_menu->timestamp) {
1659 if (menu_is_default) {
1660 wwarning(_("using default menu file \"%s\" as the menu referenced in WMRootMenu could not be found "),
1661 path);
1664 menu = readMenuFile(scr, path);
1665 if (menu)
1666 menu->timestamp = WMAX(stat_buf.st_mtime, WDRootMenu->timestamp);
1667 } else {
1668 menu = NULL;
1670 wfree(path);
1671 wfree(tmp);
1673 return menu;
1676 count = WMGetPropListItemCount(definition);
1677 if (count==0)
1678 return NULL;
1680 elem = WMGetFromPLArray(definition, 0);
1681 if (!WMIsPLString(elem)) {
1682 tmp = WMGetPropListDescription(elem, False);
1683 wwarning(_("%s:format error in root menu configuration \"%s\""),
1684 "WMRootMenu", tmp);
1685 wfree(tmp);
1686 return NULL;
1688 mtitle = WMGetFromPLString(elem);
1690 menu = wMenuCreate(scr, mtitle, False);
1691 menu->on_destroy = removeShortcutsForMenu;
1693 #ifdef GLOBAL_SUBMENU_FILE
1695 WMenu *submenu;
1696 WMenuEntry *mentry;
1698 submenu = readMenuFile(scr, GLOBAL_SUBMENU_FILE);
1700 if (submenu) {
1701 mentry = wMenuAddCallback(menu, submenu->frame->title, NULL, NULL);
1702 wMenuEntrySetCascade(menu, mentry, submenu);
1705 #endif
1707 for (i=1; i<count; i++) {
1708 elem = WMGetFromPLArray(definition, i);
1709 #if 0
1710 if (WMIsPLString(elem)) {
1711 char *file;
1713 file = WMGetFromPLString(elem);
1716 #endif
1717 if (!WMIsPLArray(elem) || WMGetPropListItemCount(elem) < 2)
1718 goto error;
1720 if (WMIsPLArray(WMGetFromPLArray(elem,1))) {
1721 WMenu *submenu;
1722 WMenuEntry *mentry;
1724 /* submenu */
1725 submenu = configureMenu(scr, elem);
1726 if (submenu) {
1727 mentry = wMenuAddCallback(menu, submenu->frame->title, NULL,
1728 NULL);
1729 wMenuEntrySetCascade(menu, mentry, submenu);
1731 } else {
1732 int idx = 0;
1733 WMPropList *shortcut;
1734 /* normal entry */
1736 title = WMGetFromPLArray(elem, idx++);
1737 shortcut = WMGetFromPLArray(elem, idx++);
1738 if (strcmp(WMGetFromPLString(shortcut), "SHORTCUT")==0) {
1739 shortcut = WMGetFromPLArray(elem, idx++);
1740 command = WMGetFromPLArray(elem, idx++);
1741 } else {
1742 command = shortcut;
1743 shortcut = NULL;
1745 params = WMGetFromPLArray(elem, idx++);
1747 if (!title || !command)
1748 goto error;
1750 addMenuEntry(menu, WMGetFromPLString(title),
1751 shortcut ? WMGetFromPLString(shortcut) : NULL,
1752 WMGetFromPLString(command),
1753 params ? WMGetFromPLString(params) : NULL, "WMRootMenu");
1755 continue;
1757 error:
1758 tmp = WMGetPropListDescription(elem, False);
1759 wwarning(_("%s:format error in root menu configuration \"%s\""),
1760 "WMRootMenu", tmp);
1761 wfree(tmp);
1764 return menu;
1775 *----------------------------------------------------------------------
1776 * OpenRootMenu--
1777 * Opens the root menu, parsing the menu configuration from the
1778 * defaults database.
1779 * If the menu is already mapped and is not sticked to the
1780 * root window, it will be unmapped.
1782 * Side effects:
1783 * The menu may be remade.
1785 * Notes:
1786 * Construction of OPEN_MENU entries are delayed to the moment the
1787 * user map's them.
1788 *----------------------------------------------------------------------
1790 void
1791 OpenRootMenu(WScreen *scr, int x, int y, int keyboard)
1793 WMenu *menu=NULL;
1794 WMPropList *definition;
1796 static WMPropList *domain=NULL;
1798 if (!domain) {
1799 domain = WMCreatePLString("WMRootMenu");
1803 scr->flags.root_menu_changed_shortcuts = 0;
1804 scr->flags.added_workspace_menu = 0;
1805 scr->flags.added_windows_menu = 0;
1807 if (scr->root_menu && scr->root_menu->flags.mapped) {
1808 menu = scr->root_menu;
1809 if (!menu->flags.buttoned) {
1810 wMenuUnmap(menu);
1811 } else {
1812 wRaiseFrame(menu->frame->core);
1814 if (keyboard)
1815 wMenuMapAt(menu, 0, 0, True);
1816 else
1817 wMenuMapCopyAt(menu, x-menu->frame->core->width/2, y);
1819 return;
1823 definition = WDRootMenu->dictionary;
1826 definition = PLGetDomain(domain);
1828 if (definition) {
1829 if (WMIsPLArray(definition)) {
1830 if (!scr->root_menu
1831 || WDRootMenu->timestamp > scr->root_menu->timestamp) {
1832 menu = configureMenu(scr, definition);
1833 if (menu)
1834 menu->timestamp = WDRootMenu->timestamp;
1836 } else
1837 menu = NULL;
1838 } else {
1839 menu = configureMenu(scr, definition);
1843 if (!menu) {
1844 /* menu hasn't changed or could not be read */
1845 if (!scr->root_menu) {
1846 wMessageDialog(scr, _("Error"),
1847 _("The applications menu could not be loaded. "
1848 "Look at the console output for a detailed "
1849 "description of the errors."),
1850 _("OK"), NULL, NULL);
1852 menu = makeDefaultMenu(scr);
1853 scr->root_menu = menu;
1855 menu = scr->root_menu;
1856 } else {
1857 /* new root menu */
1858 if (scr->root_menu) {
1859 wMenuDestroy(scr->root_menu, True);
1861 scr->root_menu = menu;
1863 if (menu) {
1864 int newx, newy;
1866 if (keyboard && x==0 && y==0) {
1867 newx = newy = 0;
1868 } else if (keyboard && x==scr->scr_width/2 && y==scr->scr_height/2) {
1869 newx = x - menu->frame->core->width/2;
1870 newy = y - menu->frame->core->height/2;
1871 } else {
1872 newx = x - menu->frame->core->width/2;
1873 newy = y;
1875 wMenuMapAt(menu, newx, newy, keyboard);
1878 if (scr->flags.root_menu_changed_shortcuts)
1879 rebindKeygrabs(scr);
1882 #endif /* !LITE */