- added WMRemoveFromArrayMatching(array, match, cdata), which will remove the
[wmaker-crm.git] / src / rootmenu.c
blob302553d64a311ffa487c06114f8b32618ffe739b
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"
55 #include <proplist.h>
59 extern char *Locale;
61 extern WDDomain *WDRootMenu;
63 extern Cursor wCursor[WCUR_LAST];
65 extern Time LastTimestamp;
67 extern WPreferences wPreferences;
69 extern int wScreenCount;
71 static WMenu *readMenuPipe(WScreen *scr, char **file_name);
72 static WMenu *readMenuFile(WScreen *scr, char *file_name);
73 static WMenu *readMenuDirectory(WScreen *scr, char *title, char **file_name,
74 char *command);
77 typedef struct Shortcut {
78 struct Shortcut *next;
80 int modifier;
81 KeyCode keycode;
82 WMenuEntry *entry;
83 WMenu *menu;
84 } Shortcut;
88 static Shortcut *shortcutList = NULL;
92 * Syntax:
93 * # main menu
94 * "Menu Name" MENU
95 * "Title" EXEC command_to_exec -params
96 * "Submenu" MENU
97 * "Title" EXEC command_to_exec -params
98 * "Submenu" END
99 * "Workspaces" WORKSPACE_MENU
100 * "Title" built_in_command
101 * "Quit" EXIT
102 * "Quick Quit" EXIT QUICK
103 * "Menu Name" END
105 * Commands may be preceded by SHORTCUT key
107 * Built-in commands:
109 * INFO_PANEL - shows the Info Panel
110 * LEGAL_PANEL - shows the Legal info panel
111 * SHUTDOWN [QUICK] - closes the X server [without confirmation]
112 * REFRESH - forces the desktop to be repainted
113 * EXIT [QUICK] - exit the window manager [without confirmation]
114 * EXEC <program> - execute an external program
115 * SHEXEC <command> - execute a shell command
116 * WORKSPACE_MENU - places the workspace submenu
117 * ARRANGE_ICONS
118 * RESTART [<window manager>] - restarts the window manager
119 * SHOW_ALL - unhide all windows on workspace
120 * HIDE_OTHERS - hides all windows excep the focused one
121 * OPEN_MENU file - read menu data from file which must be a valid menu file.
122 * OPEN_MENU /some/dir [/some/other/dir ...] [WITH command -options]
123 * - read menu data from directory(ies) and
124 * eventually precede each with a command.
125 * OPEN_MENU | command
126 * - opens command and uses its stdout to construct and insert
127 * the resulting menu in current position. The output of
128 * command must be a valid menu description.
129 * The space between '|' and command is optional.
130 * SAVE_SESSION - saves the current state of the desktop, which include
131 * all running applications, all their hints (geometry,
132 * position on screen, workspace they live on, the dock
133 * or clip from where they were launched, and
134 * if minimized, shaded or hidden. Also saves the current
135 * workspace the user is on. All will be restored on every
136 * start of windowmaker until another SAVE_SESSION or
137 * CLEAR_SESSION is used. If SaveSessionOnExit = Yes; in
138 * WindowMaker domain file, then saving is automatically
139 * done on every windowmaker exit, overwriting any
140 * SAVE_SESSION or CLEAR_SESSION (see below). Also save
141 * dock state now.
142 * CLEAR_SESSION - clears any previous saved session. This will not have
143 * any effect if SaveSessionOnExit is True.
147 #define MAX(a,b) ((a)>(b) ? (a) : (b))
150 #define M_QUICK 1
152 /* menu commands */
154 static void
155 execCommand(WMenu *menu, WMenuEntry *entry)
157 char *cmdline;
159 cmdline = ExpandOptions(menu->frame->screen_ptr, (char*)entry->clientdata);
161 XGrabPointer(dpy, menu->frame->screen_ptr->root_win, True, 0,
162 GrabModeAsync, GrabModeAsync, None, wCursor[WCUR_WAIT],
163 CurrentTime);
164 XSync(dpy, 0);
166 if (cmdline) {
167 ExecuteShellCommand(menu->frame->screen_ptr, cmdline);
168 wfree(cmdline);
170 XUngrabPointer(dpy, CurrentTime);
171 XSync(dpy, 0);
175 static void
176 exitCommand(WMenu *menu, WMenuEntry *entry)
178 static int inside = 0;
180 /* prevent reentrant calls */
181 if (inside)
182 return;
183 inside = 1;
185 if ((long)entry->clientdata==M_QUICK
186 || wMessageDialog(menu->frame->screen_ptr, _("Exit"),
187 _("Exit window manager?"),
188 _("Exit"), _("Cancel"), NULL)==WAPRDefault) {
189 #ifdef DEBUG
190 printf("Exiting WindowMaker.\n");
191 #endif
192 Shutdown(WSExitMode);
194 inside = 0;
198 static void
199 shutdownCommand(WMenu *menu, WMenuEntry *entry)
201 static int inside = 0;
202 int result;
204 /* prevent reentrant calls */
205 if (inside)
206 return;
207 inside = 1;
209 #define R_CANCEL 0
210 #define R_CLOSE 1
211 #define R_KILL 2
214 result = R_CANCEL;
215 if ((long)entry->clientdata==M_QUICK)
216 result = R_CLOSE;
217 else {
218 #ifdef XSMP_ENABLED
219 if (wSessionIsManaged()) {
220 int r;
222 r = wMessageDialog(menu->frame->screen_ptr,
223 _("Close X session"),
224 _("Close Window System session?\n"
225 "Kill might close applications with unsaved data."),
226 _("Close"), _("Kill"), _("Cancel"));
227 if (r==WAPRDefault)
228 result = R_CLOSE;
229 else if (r==WAPRAlternate)
230 result = R_KILL;
231 } else
232 #endif
234 int r;
236 r = wMessageDialog(menu->frame->screen_ptr,
237 _("Kill X session"),
238 _("Kill Window System session?\n"
239 "(all applications will be closed)"),
240 _("Kill"), _("Cancel"), NULL);
241 if (r==WAPRDefault)
242 result = R_KILL;
246 if (result!=R_CANCEL) {
247 #ifdef XSMP_ENABLED
248 if (result == R_CLOSE) {
249 Shutdown(WSLogoutMode);
250 } else
251 #endif /* XSMP_ENABLED */
253 Shutdown(WSKillMode);
256 #undef R_CLOSE
257 #undef R_CANCEL
258 #undef R_KILL
259 inside = 0;
263 static void
264 restartCommand(WMenu *menu, WMenuEntry *entry)
266 Shutdown(WSRestartPreparationMode);
267 Restart((char*)entry->clientdata, False);
268 Restart(NULL, True);
272 static void
273 refreshCommand(WMenu *menu, WMenuEntry *entry)
275 wRefreshDesktop(menu->frame->screen_ptr);
279 static void
280 arrangeIconsCommand(WMenu *menu, WMenuEntry *entry)
282 wArrangeIcons(menu->frame->screen_ptr, True);
285 static void
286 showAllCommand(WMenu *menu, WMenuEntry *entry)
288 wShowAllWindows(menu->frame->screen_ptr);
291 static void
292 hideOthersCommand(WMenu *menu, WMenuEntry *entry)
294 wHideOtherApplications(menu->frame->screen_ptr->focused_window);
298 static void
299 saveSessionCommand(WMenu *menu, WMenuEntry *entry)
301 if (!wPreferences.save_session_on_exit)
302 wSessionSaveState(menu->frame->screen_ptr);
304 wScreenSaveState(menu->frame->screen_ptr);
308 static void
309 clearSessionCommand(WMenu *menu, WMenuEntry *entry)
311 wSessionClearState(menu->frame->screen_ptr);
315 static void
316 infoPanelCommand(WMenu *menu, WMenuEntry *entry)
318 wShowInfoPanel(menu->frame->screen_ptr);
322 static void
323 legalPanelCommand(WMenu *menu, WMenuEntry *entry)
325 wShowLegalPanel(menu->frame->screen_ptr);
329 /********************************************************************/
332 static char*
333 getLocalizedMenuFile(char *menu)
335 char *buffer;
336 char *ptr;
338 if (!Locale)
339 return NULL;
341 buffer = wmalloc(strlen(menu)+32);
343 /* try menu.locale_name */
344 sprintf(buffer, "%s.%s", menu, Locale);
345 if (access(buffer, F_OK)==0) {
346 return buffer;
348 /* check if it is in the form aa_bb.encoding and check for aa_bb */
349 ptr = strchr(Locale, '.');
350 if (ptr) {
351 *ptr = 0;
352 if (access(buffer, F_OK)==0) {
353 return buffer;
356 /* now check for aa */
357 ptr = strchr(buffer, '_');
358 if (ptr) {
359 *ptr = 0;
360 if (access(buffer, F_OK)==0) {
361 return buffer;
365 return NULL;
369 static void
370 raiseMenus(WMenu *menu)
372 int i;
374 if (menu->flags.mapped) {
375 wRaiseFrame(menu->frame->core);
377 for (i=0; i<menu->cascade_no; i++) {
378 if (menu->cascades[i])
379 raiseMenus(menu->cascades[i]);
385 Bool
386 wRootMenuPerformShortcut(XEvent *event)
388 Shortcut *ptr;
389 int modifiers;
390 int done = 0;
392 /* ignore CapsLock */
393 modifiers = event->xkey.state & ValidModMask;
395 for (ptr = shortcutList; ptr!=NULL; ptr = ptr->next) {
396 if (ptr->keycode==0)
397 continue;
399 if (ptr->keycode==event->xkey.keycode && (ptr->modifier==modifiers)) {
400 (*ptr->entry->callback)(ptr->menu, ptr->entry);
401 done = True;
404 return done;
408 void
409 wRootMenuBindShortcuts(Window window)
411 Shortcut *ptr;
413 ptr = shortcutList;
414 while (ptr) {
415 if (ptr->modifier!=AnyModifier) {
416 XGrabKey(dpy, ptr->keycode, ptr->modifier|LockMask,
417 window, True, GrabModeAsync, GrabModeAsync);
418 #ifdef NUMLOCK_HACK
419 wHackedGrabKey(ptr->keycode, ptr->modifier,
420 window, True, GrabModeAsync, GrabModeAsync);
421 #endif
423 XGrabKey(dpy, ptr->keycode, ptr->modifier, window, True,
424 GrabModeAsync, GrabModeAsync);
425 ptr = ptr->next;
430 static void
431 rebindKeygrabs(WScreen *scr)
433 WWindow *wwin;
435 wwin = scr->focused_window;
437 while (wwin!=NULL) {
438 XUngrabKey(dpy, AnyKey, AnyModifier, wwin->frame->core->window);
440 if (!WFLAGP(wwin, no_bind_keys)) {
441 wWindowSetKeyGrabs(wwin);
443 wwin = wwin->prev;
448 static void
449 removeShortcutsForMenu(WMenu *menu)
451 Shortcut *ptr, *tmp;
452 Shortcut *newList = NULL;
454 ptr = shortcutList;
455 while (ptr!=NULL) {
456 tmp = ptr->next;
457 if (ptr->menu == menu) {
458 wfree(ptr);
459 } else {
460 ptr->next = newList;
461 newList = ptr;
463 ptr = tmp;
465 shortcutList = newList;
466 menu->menu->screen_ptr->flags.root_menu_changed_shortcuts = 1;
470 static Bool
471 addShortcut(char *file, char *shortcutDefinition, WMenu *menu,
472 WMenuEntry *entry)
474 Shortcut *ptr;
475 KeySym ksym;
476 char *k;
477 char buf[128], *b;
479 ptr = wmalloc(sizeof(Shortcut));
481 strcpy(buf, shortcutDefinition);
482 b = (char*)buf;
484 /* get modifiers */
485 ptr->modifier = 0;
486 while ((k = strchr(b, '+'))!=NULL) {
487 int mod;
489 *k = 0;
490 mod = wXModifierFromKey(b);
491 if (mod<0) {
492 wwarning(_("%s:invalid key modifier \"%s\""), file, b);
493 wfree(ptr);
494 return False;
496 ptr->modifier |= mod;
498 b = k+1;
501 /* get key */
502 ksym = XStringToKeysym(b);
504 if (ksym==NoSymbol) {
505 wwarning(_("%s:invalid kbd shortcut specification \"%s\" for entry %s"),
506 file, shortcutDefinition, entry->text);
507 wfree(ptr);
508 return False;
511 ptr->keycode = XKeysymToKeycode(dpy, ksym);
512 if (ptr->keycode==0) {
513 wwarning(_("%s:invalid key in shortcut \"%s\" for entry %s"), file,
514 shortcutDefinition, entry->text);
515 wfree(ptr);
516 return False;
519 ptr->menu = menu;
520 ptr->entry = entry;
522 ptr->next = shortcutList;
523 shortcutList = ptr;
525 menu->menu->screen_ptr->flags.root_menu_changed_shortcuts = 1;
527 return True;
531 /*******************************/
533 static char*
534 cropline(char *line)
536 char *end;
538 if (strlen(line)==0)
539 return line;
541 end = &(line[strlen(line)])-1;
542 while (isspace(*line) && *line!=0) line++;
543 while (end>line && isspace(*end)) {
544 *end=0;
545 end--;
547 return line;
551 static char*
552 next_token(char *line, char **next)
554 char *tmp, c;
555 char *ret;
557 *next = NULL;
558 while (*line==' ' || *line=='\t') line++;
560 tmp = line;
562 if (*tmp=='"') {
563 tmp++; line++;
564 while (*tmp!=0 && *tmp!='"') tmp++;
565 if (*tmp!='"') {
566 wwarning(_("%s: unmatched '\"' in menu file"), line);
567 return NULL;
569 } else {
570 do {
571 if (*tmp=='\\')
572 tmp++;
574 if (*tmp!=0)
575 tmp++;
577 } while (*tmp!=0 && *tmp!=' ' && *tmp!='\t');
580 c = *tmp;
581 *tmp = 0;
582 ret = wstrdup(line);
583 *tmp = c;
585 if (c==0)
586 return ret;
587 else
588 tmp++;
590 /* skip blanks */
591 while (*tmp==' ' || *tmp=='\t') tmp++;
593 if (*tmp!=0)
594 *next = tmp;
596 return ret;
600 static void
601 separateCommand(char *line, char ***file, char **command)
603 char *token, *tmp = line;
604 WMArray *array = WMCreateArray(4);
605 int count, i;
607 *file = NULL;
608 *command = NULL;
609 do {
610 token = next_token(tmp, &tmp);
611 if (token) {
612 if (strcmp(token, "WITH")==0) {
613 if (tmp!=NULL && *tmp!=0)
614 *command = wstrdup(tmp);
615 else
616 wwarning(_("%s: missing command"), line);
617 break;
619 WMAddToArray(array, token);
621 } while (token!=NULL && tmp!=NULL);
623 count = WMGetArrayItemCount(array);
624 if (count>0) {
625 *file = wmalloc(sizeof(char*)*(count+1));
626 (*file)[count] = NULL;
627 for (i = 0; i < count; i++) {
628 (*file)[i] = WMGetFromArray(array, i);
631 WMFreeArray(array);
635 static void
636 constructMenu(WMenu *menu, WMenuEntry *entry)
638 WMenu *submenu;
639 struct stat stat_buf;
640 char **path;
641 char *cmd;
642 char *lpath = NULL;
643 int i, first=-1;
644 time_t last=0;
646 separateCommand((char*)entry->clientdata, &path, &cmd);
647 if (path == NULL || *path==NULL || **path==0) {
648 wwarning(_("invalid OPEN_MENU specification: %s"),
649 (char*)entry->clientdata);
650 return;
653 if (path[0][0]=='|') {
654 /* pipe menu */
656 if (!menu->cascades[entry->cascade] ||
657 menu->cascades[entry->cascade]->timestamp == 0) {
658 /* parse pipe */
660 submenu = readMenuPipe(menu->frame->screen_ptr, path);
662 /* there's no automatic reloading */
663 if(submenu != NULL)
664 submenu->timestamp = 1;
665 } else {
666 submenu = NULL;
669 } else {
670 i=0;
671 while(path[i] != NULL) {
672 char *tmp;
674 if (strcmp(path[i], "-noext")==0) {
675 i++;
676 continue;
679 tmp = wexpandpath(path[i]);
680 wfree(path[i]);
681 lpath = getLocalizedMenuFile(tmp);
682 if (lpath) {
683 wfree(tmp);
684 path[i] = lpath;
685 lpath = NULL;
686 } else {
687 path[i] = tmp;
690 if (stat(path[i], &stat_buf)==0) {
691 if (last < stat_buf.st_mtime)
692 last = stat_buf.st_mtime;
693 if (first<0)
694 first=i;
695 } else {
696 wsyserror(_("%s:could not stat menu"), path[i]);
697 /*goto finish;*/
700 i++;
703 if (first < 0) {
704 wsyserror(_("%s:could not stat menu:%s"), "OPEN_MENU",
705 (char*)entry->clientdata);
706 goto finish;
708 stat(path[first], &stat_buf);
709 if (!menu->cascades[entry->cascade]
710 || menu->cascades[entry->cascade]->timestamp < last) {
712 if (S_ISDIR(stat_buf.st_mode)) {
713 /* menu directory */
714 submenu = readMenuDirectory(menu->frame->screen_ptr,
715 entry->text, path, cmd);
716 if (submenu)
717 submenu->timestamp = last;
718 } else if (S_ISREG(stat_buf.st_mode)) {
719 /* menu file */
721 if (cmd || path[1])
722 wwarning(_("too many parameters in OPEN_MENU: %s"),
723 (char*)entry->clientdata);
725 submenu = readMenuFile(menu->frame->screen_ptr, path[first]);
726 if (submenu)
727 submenu->timestamp = stat_buf.st_mtime;
728 } else {
729 submenu = NULL;
731 } else {
732 submenu = NULL;
736 if (submenu) {
737 wMenuEntryRemoveCascade(menu, entry);
738 wMenuEntrySetCascade(menu, entry, submenu);
741 finish:
742 i = 0;
743 while (path[i]!=NULL)
744 wfree(path[i++]);
745 wfree(path);
746 if (cmd)
747 wfree(cmd);
751 static WMenuEntry*
752 addWorkspaceMenu(WScreen *scr, WMenu *menu, char *title)
754 WMenu *wsmenu;
755 WMenuEntry *entry;
757 if (scr->flags.added_workspace_menu) {
758 wwarning(_("There are more than one WORKSPACE_MENU commands in the applications menu. Only one is allowed."));
759 return NULL;
760 } else {
761 scr->flags.added_workspace_menu = 1;
763 wsmenu = wWorkspaceMenuMake(scr, True);
764 scr->workspace_menu = wsmenu;
765 entry = wMenuAddCallback(menu, title, NULL, NULL);
766 wMenuEntrySetCascade(menu, entry, wsmenu);
768 wWorkspaceMenuUpdate(scr, wsmenu);
770 return entry;
773 static WMenuEntry*
774 addWindowsMenu(WScreen *scr, WMenu *menu, char *title)
776 WMenu *wwmenu;
777 WWindow *wwin;
778 WMenuEntry *entry;
780 if (scr->flags.added_windows_menu) {
781 wwarning(_("There are more than one WINDOWS_MENU commands in the applications menu. Only one is allowed."));
782 return NULL;
783 } else {
784 scr->flags.added_windows_menu = 1;
786 wwmenu = wMenuCreate(scr, _("Window List"), False);
787 scr->switch_menu = wwmenu;
788 wwin = scr->focused_window;
789 while (wwin) {
790 UpdateSwitchMenu(scr, wwin, ACTION_ADD);
792 wwin = wwin->prev;
794 entry = wMenuAddCallback(menu, title, NULL, NULL);
795 wMenuEntrySetCascade(menu, entry, wwmenu);
797 return entry;
800 static WMenuEntry*
801 addMenuEntry(WMenu *menu, char *title, char *shortcut, char *command,
802 char *params, char *file_name)
804 WScreen *scr;
805 WMenuEntry *entry = NULL;
806 Bool shortcutOk = False;
808 if (!menu)
809 return NULL;
810 scr = menu->frame->screen_ptr;
811 if (strcmp(command, "OPEN_MENU")==0) {
812 if (!params) {
813 wwarning(_("%s:missing parameter for menu command \"%s\""),
814 file_name, command);
815 } else {
816 WMenu *dummy;
817 char *path;
819 path = wfindfile(DEF_CONFIG_PATHS, params);
820 if (!path) {
821 path = wstrdup(params);
823 dummy = wMenuCreate(scr, title, False);
824 dummy->on_destroy = removeShortcutsForMenu;
825 entry = wMenuAddCallback(menu, title, constructMenu, path);
826 entry->free_cdata = free;
827 wMenuEntrySetCascade(menu, entry, dummy);
829 } else if (strcmp(command, "EXEC")==0) {
830 if (!params)
831 wwarning(_("%s:missing parameter for menu command \"%s\""),
832 file_name, command);
833 else {
834 entry = wMenuAddCallback(menu, title, execCommand,
835 wstrconcat("exec ", params));
836 entry->free_cdata = free;
837 shortcutOk = True;
839 } else if (strcmp(command, "SHEXEC")==0) {
840 if (!params)
841 wwarning(_("%s:missing parameter for menu command \"%s\""),
842 file_name, command);
843 else {
844 entry = wMenuAddCallback(menu, title, execCommand,
845 wstrdup(params));
846 entry->free_cdata = free;
847 shortcutOk = True;
849 } else if (strcmp(command, "EXIT")==0) {
851 if (params && strcmp(params, "QUICK")==0)
852 entry = wMenuAddCallback(menu, title, exitCommand, (void*)M_QUICK);
853 else
854 entry = wMenuAddCallback(menu, title, exitCommand, NULL);
856 shortcutOk = True;
857 } else if (strcmp(command, "SHUTDOWN")==0) {
859 if (params && strcmp(params, "QUICK")==0)
860 entry = wMenuAddCallback(menu, title, shutdownCommand,
861 (void*)M_QUICK);
862 else
863 entry = wMenuAddCallback(menu, title, shutdownCommand, NULL);
865 shortcutOk = True;
866 } else if (strcmp(command, "REFRESH")==0) {
867 entry = wMenuAddCallback(menu, title, refreshCommand, NULL);
869 shortcutOk = True;
870 } else if (strcmp(command, "WORKSPACE_MENU")==0) {
871 entry = addWorkspaceMenu(scr, menu, title);
873 shortcutOk = True;
874 } else if (strcmp(command, "WINDOWS_MENU")==0) {
875 entry = addWindowsMenu(scr, menu, title);
877 shortcutOk = True;
878 } else if (strcmp(command, "ARRANGE_ICONS")==0) {
879 entry = wMenuAddCallback(menu, title, arrangeIconsCommand, NULL);
881 shortcutOk = True;
882 } else if (strcmp(command, "HIDE_OTHERS")==0) {
883 entry = wMenuAddCallback(menu, title, hideOthersCommand, NULL);
885 shortcutOk = True;
886 } else if (strcmp(command, "SHOW_ALL")==0) {
887 entry = wMenuAddCallback(menu, title, showAllCommand, NULL);
889 shortcutOk = True;
890 } else if (strcmp(command, "RESTART")==0) {
891 entry = wMenuAddCallback(menu, title, restartCommand,
892 params ? wstrdup(params) : NULL);
893 entry->free_cdata = free;
894 shortcutOk = True;
895 } else if (strcmp(command, "SAVE_SESSION")==0) {
896 entry = wMenuAddCallback(menu, title, saveSessionCommand, NULL);
898 shortcutOk = True;
899 } else if (strcmp(command, "CLEAR_SESSION")==0) {
900 entry = wMenuAddCallback(menu, title, clearSessionCommand, NULL);
901 shortcutOk = True;
902 } else if (strcmp(command, "INFO_PANEL")==0) {
903 entry = wMenuAddCallback(menu, title, infoPanelCommand, NULL);
904 shortcutOk = True;
905 } else if (strcmp(command, "LEGAL_PANEL")==0) {
906 entry = wMenuAddCallback(menu, title, legalPanelCommand, NULL);
907 shortcutOk = True;
908 } else {
909 wwarning(_("%s:unknown command \"%s\" in menu config."), file_name,
910 command);
912 return NULL;
915 if (shortcut && entry) {
916 if (!shortcutOk) {
917 wwarning(_("%s:can't add shortcut for entry \"%s\""), file_name,
918 title);
919 } else {
920 if (addShortcut(file_name, shortcut, menu, entry)) {
922 entry->rtext = GetShortcutString(shortcut);
924 entry->rtext = wstrdup(shortcut);
930 return entry;
935 /******************* Menu Configuration From File *******************/
937 static void
938 separateline(char *line, char *title, char *command, char *parameter,
939 char *shortcut)
941 int l, i;
943 l = strlen(line);
945 *title = 0;
946 *command = 0;
947 *parameter = 0;
948 *shortcut = 0;
949 /* get the title */
950 while (isspace(*line) && (*line!=0)) line++;
951 if (*line=='"') {
952 line++;
953 i=0;
954 while (line[i]!='"' && (line[i]!=0)) i++;
955 if (line[i]!='"')
956 return;
957 } else {
958 i=0;
959 while (!isspace(line[i]) && (line[i]!=0)) i++;
961 strncpy(title, line, i);
962 title[i++]=0;
963 line+=i;
965 /* get the command or shortcut keyword */
966 while (isspace(*line) && (*line!=0)) line++;
967 if (*line==0)
968 return;
969 i=0;
970 while (!isspace(line[i]) && (line[i]!=0)) i++;
971 strncpy(command, line, i);
972 command[i++]=0;
973 line+=i;
975 if (strcmp(command, "SHORTCUT")==0) {
976 /* get the shortcut key */
977 while (isspace(*line) && (*line!=0)) line++;
978 if (*line=='"') {
979 line++;
980 i=0;
981 while (line[i]!='"' && (line[i]!=0)) i++;
982 if (line[i]!='"')
983 return;
984 } else {
985 i=0;
986 while (!isspace(line[i]) && (line[i]!=0)) i++;
988 strncpy(shortcut, line, i);
989 shortcut[i++]=0;
990 line+=i;
992 *command=0;
994 /* get the command */
995 while (isspace(*line) && (*line!=0)) line++;
996 if (*line==0)
997 return;
998 i=0;
999 while (!isspace(line[i]) && (line[i]!=0)) i++;
1000 strncpy(command, line, i);
1001 command[i++]=0;
1002 line+=i;
1005 /* get the parameters */
1006 while (isspace(*line) && (*line!=0)) line++;
1007 if (*line==0)
1008 return;
1010 if (*line=='"') {
1011 line++;
1012 l = 0;
1013 while (line[l]!=0 && line[l]!='"') {
1014 parameter[l] = line[l];
1015 l++;
1017 parameter[l] = 0;
1018 return;
1021 l = strlen(line);
1022 while (isspace(line[l]) && (l>0)) l--;
1023 strncpy(parameter, line, l);
1024 parameter[l]=0;
1028 static WMenu*
1029 parseCascade(WScreen *scr, WMenu *menu, FILE *file, char *file_name)
1031 char linebuf[MAXLINE];
1032 char elinebuf[MAXLINE];
1033 char title[MAXLINE];
1034 char command[MAXLINE];
1035 char shortcut[MAXLINE];
1036 char params[MAXLINE];
1037 char *line;
1039 while (!IsEof(file)) {
1040 int lsize, ok;
1042 ok = 0;
1043 fgets(linebuf, MAXLINE, file);
1044 line = cropline(linebuf);
1045 lsize = strlen(line);
1046 do {
1047 if (line[lsize-1]=='\\') {
1048 char *line2;
1049 int lsize2;
1050 fgets(elinebuf, MAXLINE, file);
1051 line2=cropline(elinebuf);
1052 lsize2=strlen(line2);
1053 if (lsize2+lsize>MAXLINE) {
1054 wwarning(_("%s:maximal line size exceeded in menu config: %s"),
1055 file_name, line);
1056 ok=2;
1057 } else {
1058 line[lsize-1]=0;
1059 lsize+=lsize2-1;
1060 strcat(line, line2);
1062 } else {
1063 ok=1;
1065 } while (!ok && !IsEof(file));
1066 if (ok==2)
1067 continue;
1069 if (line[0]==0 || line[0]=='#' || (line[0]=='/' && line[1]=='/'))
1070 continue;
1073 separateline(line, title, command, params, shortcut);
1075 if (!command[0]) {
1076 wwarning(_("%s:missing command in menu config: %s"), file_name,
1077 line);
1078 goto error;
1081 if (strcasecmp(command, "MENU")==0) {
1082 WMenu *cascade;
1084 /* start submenu */
1086 cascade = wMenuCreate(scr, title, False);
1087 cascade->on_destroy = removeShortcutsForMenu;
1088 if (parseCascade(scr, cascade, file, file_name)==NULL) {
1089 wMenuDestroy(cascade, True);
1090 } else {
1091 wMenuEntrySetCascade(menu,
1092 wMenuAddCallback(menu, title, NULL, NULL),
1093 cascade);
1095 } else if (strcasecmp(command, "END")==0) {
1096 /* end of menu */
1097 return menu;
1099 } else {
1100 /* normal items */
1101 addMenuEntry(menu, title, shortcut[0] ? shortcut : NULL, command,
1102 params[0] ? params : NULL, file_name);
1106 wwarning(_("%s:syntax error in menu file:END declaration missing"),
1107 file_name);
1108 return menu;
1110 error:
1111 return menu;
1115 static WMenu*
1116 readMenuFile(WScreen *scr, char *file_name)
1118 WMenu *menu=NULL;
1119 FILE *file = NULL;
1120 char linebuf[MAXLINE];
1121 char title[MAXLINE];
1122 char shortcut[MAXLINE];
1123 char command[MAXLINE];
1124 char params[MAXLINE];
1125 char *line;
1126 #ifdef USECPP
1127 char *args;
1128 int cpp = 0;
1129 #endif
1131 #ifdef USECPP
1132 if (!wPreferences.flags.nocpp) {
1133 args = MakeCPPArgs(file_name);
1134 if (!args) {
1135 wwarning(_("could not make arguments for menu file preprocessor"));
1136 } else {
1137 sprintf(command, "%s %s %s", CPP_PATH, args, file_name);
1138 wfree(args);
1139 file = popen(command, "r");
1140 if (!file) {
1141 wsyserror(_("%s:could not open/preprocess menu file"),
1142 file_name);
1143 } else {
1144 cpp = 1;
1148 #endif /* USECPP */
1150 if (!file) {
1151 file = fopen(file_name, "r");
1152 if (!file) {
1153 wsyserror(_("%s:could not open menu file"), file_name);
1154 return NULL;
1158 while (!IsEof(file)) {
1159 if (!fgets(linebuf, MAXLINE, file))
1160 break;
1161 line = cropline(linebuf);
1162 if (line[0]==0 || line[0]=='#' || (line[0]=='/' && line[1]=='/'))
1163 continue;
1165 separateline(line, title, command, params, shortcut);
1167 if (!command[0]) {
1168 wwarning(_("%s:missing command in menu config: %s"), file_name,
1169 line);
1170 break;
1172 if (strcasecmp(command, "MENU")==0) {
1173 menu = wMenuCreate(scr, title, True);
1174 menu->on_destroy = removeShortcutsForMenu;
1175 if (!parseCascade(scr, menu, file, file_name)) {
1176 wMenuDestroy(menu, True);
1178 break;
1179 } else {
1180 wwarning(_("%s:invalid menu file. MENU command is missing"),
1181 file_name);
1182 break;
1186 #ifdef CPP
1187 if (cpp) {
1188 if (pclose(file)==-1) {
1189 wsyserror(_("error reading preprocessed menu data"));
1191 } else {
1192 fclose(file);
1194 #else
1195 fclose(file);
1196 #endif
1198 return menu;
1201 /************ Menu Configuration From Pipe *************/
1203 static WMenu*
1204 readMenuPipe(WScreen *scr, char **file_name)
1206 WMenu *menu=NULL;
1207 FILE *file = NULL;
1208 char linebuf[MAXLINE];
1209 char title[MAXLINE];
1210 char command[MAXLINE];
1211 char params[MAXLINE];
1212 char shortcut[MAXLINE];
1213 char *line;
1214 char * filename;
1215 char flat_file[MAXLINE];
1216 int i;
1217 #ifdef USECPP
1218 char *args;
1219 int cpp = 0;
1220 #endif
1222 flat_file[0] = '\0';
1224 for(i = 0 ; file_name[i] != NULL ; i++) {
1225 strcat(flat_file, file_name[i]);
1226 strcat(flat_file, " ");
1228 filename = flat_file+1;
1230 #ifdef USECPP
1231 if (!wPreferences.flags.nocpp) {
1232 args = MakeCPPArgs(filename);
1233 if (!args) {
1234 wwarning(_("could not make arguments for menu file preprocessor"));
1235 } else {
1236 sprintf(command, "%s | %s %s", filename, CPP_PATH, args);
1238 wfree(args);
1239 file = popen(command, "r");
1240 if (!file) {
1241 wsyserror(_("%s:could not open/preprocess menu file"), filename);
1242 } else {
1243 cpp = 1;
1248 #endif /* USECPP */
1250 if (!file) {
1251 file = popen(filename, "r");
1253 if (!file) {
1254 wsyserror(_("%s:could not open menu file"), filename);
1255 return NULL;
1259 while (!IsEof(file)) {
1260 if (!fgets(linebuf, MAXLINE, file))
1261 break;
1262 line = cropline(linebuf);
1263 if (line[0]==0 || line[0]=='#' || (line[0]=='/' && line[1]=='/'))
1264 continue;
1266 separateline(line, title, command, params, shortcut);
1268 if (!command[0]) {
1269 wwarning(_("%s:missing command in menu config: %s"), file_name,
1270 line);
1271 break;
1273 if (strcasecmp(command, "MENU")==0) {
1274 menu = wMenuCreate(scr, title, True);
1275 menu->on_destroy = removeShortcutsForMenu;
1276 if (!parseCascade(scr, menu, file, filename)) {
1277 wMenuDestroy(menu, True);
1279 break;
1280 } else {
1281 wwarning(_("%s:no title given for the root menu"), filename);
1282 break;
1286 pclose(file);
1288 return menu;
1293 typedef struct {
1294 char *name;
1295 int index;
1296 } dir_data;
1299 static int
1300 myCompare(const void *d1, const void *d2)
1302 dir_data *p1 = *(dir_data**)d1;
1303 dir_data *p2 = *(dir_data**)d2;
1305 return strcmp(p1->name, p2->name);
1309 /************ Menu Configuration From Directory *************/
1311 static Bool
1312 isFilePackage(char *file)
1314 int l;
1316 /* check if the extension indicates this file is a
1317 * file package. For now, only recognize .themed */
1319 l = strlen(file);
1321 if (l > 7 && strcmp(&(file[l-7]), ".themed")==0) {
1322 return True;
1323 } else {
1324 return False;
1329 static WMenu*
1330 readMenuDirectory(WScreen *scr, char *title, char **path, char *command)
1332 DIR *dir;
1333 struct dirent *dentry;
1334 struct stat stat_buf;
1335 WMenu *menu=NULL;
1336 char *buffer;
1337 WMArray *dirs = NULL, *files = NULL;
1338 WMArrayIterator iter;
1339 int length, i, have_space=0;
1340 dir_data *data;
1341 int stripExtension = 0;
1344 dirs = WMCreateArray(16);
1345 files = WMCreateArray(16);
1347 i=0;
1348 while (path[i]!=NULL) {
1349 if (strcmp(path[i], "-noext")==0) {
1350 stripExtension = 1;
1351 i++;
1352 continue;
1355 dir = opendir(path[i]);
1356 if (!dir) {
1357 i++;
1358 continue;
1361 while ((dentry = readdir(dir))) {
1363 if (strcmp(dentry->d_name, ".")==0 ||
1364 strcmp(dentry->d_name, "..")==0)
1365 continue;
1367 if (dentry->d_name[0] == '.')
1368 continue;
1370 buffer = malloc(strlen(path[i])+strlen(dentry->d_name)+4);
1371 if (!buffer) {
1372 wsyserror(_("out of memory while constructing directory menu %s"),
1373 path[i]);
1374 break;
1377 strcpy(buffer, path[i]);
1378 strcat(buffer, "/");
1379 strcat(buffer, dentry->d_name);
1381 if (stat(buffer, &stat_buf)!=0) {
1382 wsyserror(_("%s:could not stat file \"%s\" in menu directory"),
1383 path[i], dentry->d_name);
1384 } else {
1385 Bool isFilePack = False;
1387 data = NULL;
1388 if (S_ISDIR(stat_buf.st_mode)
1389 && !(isFilePack = isFilePackage(dentry->d_name))) {
1391 /* access always returns success for user root */
1392 if (access(buffer, X_OK)==0) {
1393 /* Directory is accesible. Add to directory list */
1395 data = (dir_data*) wmalloc(sizeof(dir_data));
1396 data->name = wstrdup(dentry->d_name);
1397 data->index = i;
1399 WMAddToArray(dirs, data);
1401 } else if (S_ISREG(stat_buf.st_mode) || isFilePack) {
1402 /* Hack because access always returns X_OK success for user root */
1403 #define S_IXANY (S_IXUSR | S_IXGRP | S_IXOTH)
1404 if ((command!=NULL && access(buffer, R_OK)==0) ||
1405 (command==NULL && access(buffer, X_OK)==0 &&
1406 (stat_buf.st_mode & S_IXANY))) {
1408 data = (dir_data*) wmalloc(sizeof(dir_data));
1409 data->name = wstrdup(dentry->d_name);
1410 data->index = i;
1412 WMAddToArray(files, data);
1416 wfree(buffer);
1419 closedir(dir);
1420 i++;
1423 if (!WMGetArrayItemCount(dirs) && !WMGetArrayItemCount(files)) {
1424 WMFreeArray(dirs);
1425 WMFreeArray(files);
1426 return NULL;
1429 WMSortArray(dirs, myCompare);
1430 WMSortArray(files, myCompare);
1432 menu = wMenuCreate(scr, title, False);
1433 menu->on_destroy = removeShortcutsForMenu;
1435 WM_ITERATE_ARRAY(dirs, data, iter) {
1436 /* New directory. Use same OPEN_MENU command that was used
1437 * for the current directory. */
1438 length = strlen(path[data->index])+strlen(data->name)+6;
1439 if (stripExtension)
1440 length += 7;
1441 if (command)
1442 length += strlen(command) + 6;
1443 buffer = malloc(length);
1444 if (!buffer) {
1445 wsyserror(_("out of memory while constructing directory menu %s"),
1446 path[data->index]);
1447 break;
1450 buffer[0] = '\0';
1451 if (stripExtension)
1452 strcat(buffer, "-noext ");
1454 have_space = strchr(path[data->index], ' ')!=NULL ||
1455 strchr(data->name, ' ')!=NULL;
1457 if (have_space)
1458 strcat(buffer, "\"");
1459 strcat(buffer, path[data->index]);
1461 strcat(buffer, "/");
1462 strcat(buffer, data->name);
1463 if (have_space)
1464 strcat(buffer, "\"");
1465 if (command) {
1466 strcat(buffer, " WITH ");
1467 strcat(buffer, command);
1470 addMenuEntry(menu, data->name, NULL, "OPEN_MENU", buffer, path[data->index]);
1472 wfree(buffer);
1473 if (data->name)
1474 wfree(data->name);
1475 wfree(data);
1478 WM_ITERATE_ARRAY(files, data, iter) {
1479 /* executable: add as entry */
1480 length = strlen(path[data->index])+strlen(data->name)+6;
1481 if (command)
1482 length += strlen(command);
1484 buffer = malloc(length);
1485 if (!buffer) {
1486 wsyserror(_("out of memory while constructing directory menu %s"),
1487 path[data->index]);
1488 break;
1491 have_space = strchr(path[data->index], ' ')!=NULL ||
1492 strchr(data->name, ' ')!=NULL;
1493 if (command!=NULL) {
1494 strcpy(buffer, command);
1495 strcat(buffer, " ");
1496 if (have_space)
1497 strcat(buffer, "\"");
1498 strcat(buffer, path[data->index]);
1499 } else {
1500 if (have_space) {
1501 buffer[0] = '"';
1502 buffer[1] = 0;
1503 strcat(buffer, path[data->index]);
1504 } else {
1505 strcpy(buffer, path[data->index]);
1508 strcat(buffer, "/");
1509 strcat(buffer, data->name);
1510 if (have_space)
1511 strcat(buffer, "\"");
1513 if (stripExtension) {
1514 char *ptr = strrchr(data->name, '.');
1515 if (ptr && ptr!=data->name)
1516 *ptr = 0;
1518 addMenuEntry(menu, data->name, NULL, "SHEXEC", buffer, path[data->index]);
1520 wfree(buffer);
1521 if (data->name)
1522 wfree(data->name);
1523 wfree(data);
1526 WMFreeArray(files);
1527 WMFreeArray(dirs);
1529 return menu;
1533 /************ Menu Configuration From WMRootMenu *************/
1535 static WMenu*
1536 makeDefaultMenu(WScreen *scr)
1538 WMenu *menu=NULL;
1540 menu = wMenuCreate(scr, _("Commands"), True);
1541 wMenuAddCallback(menu, "XTerm", execCommand, "xterm");
1542 wMenuAddCallback(menu, "rxvt", execCommand, "rxvt");
1543 wMenuAddCallback(menu, _("Restart"), restartCommand, NULL);
1544 wMenuAddCallback(menu, _("Exit..."), exitCommand, NULL);
1545 return menu;
1553 *----------------------------------------------------------------------
1554 * configureMenu--
1555 * Reads root menu configuration from defaults database.
1557 *----------------------------------------------------------------------
1559 static WMenu*
1560 configureMenu(WScreen *scr, proplist_t definition)
1562 WMenu *menu = NULL;
1563 proplist_t elem;
1564 int i, count;
1565 proplist_t title, command, params;
1566 char *tmp, *mtitle;
1569 if (PLIsString(definition)) {
1570 struct stat stat_buf;
1571 char *path = NULL;
1572 Bool menu_is_default = False;
1574 /* menu definition is a string. Probably a path, so parse the file */
1576 tmp = wexpandpath(PLGetString(definition));
1578 path = getLocalizedMenuFile(tmp);
1580 if (!path)
1581 path = wfindfile(DEF_CONFIG_PATHS, tmp);
1583 if (!path) {
1584 path = wfindfile(DEF_CONFIG_PATHS, DEF_MENU_FILE);
1585 menu_is_default = True;
1588 if (!path) {
1589 wsyserror(_("could not find menu file \"%s\" referenced in WMRootMenu"),
1590 tmp);
1591 wfree(tmp);
1592 return NULL;
1595 if (stat(path, &stat_buf)<0) {
1596 wsyserror(_("could not access menu \"%s\" referenced in WMRootMenu"), path);
1597 wfree(path);
1598 wfree(tmp);
1599 return NULL;
1602 if (!scr->root_menu || stat_buf.st_mtime > scr->root_menu->timestamp
1603 /* if the pointer in WMRootMenu has changed */
1604 || WDRootMenu->timestamp > scr->root_menu->timestamp) {
1606 if (menu_is_default) {
1607 wwarning(_("using default menu file \"%s\" as the menu referenced in WMRootMenu could not be found "),
1608 path);
1611 menu = readMenuFile(scr, path);
1612 if (menu)
1613 menu->timestamp = MAX(stat_buf.st_mtime, WDRootMenu->timestamp);
1614 } else {
1615 menu = NULL;
1617 wfree(path);
1618 wfree(tmp);
1620 return menu;
1623 count = PLGetNumberOfElements(definition);
1624 if (count==0)
1625 return NULL;
1627 elem = PLGetArrayElement(definition, 0);
1628 if (!PLIsString(elem)) {
1629 tmp = PLGetDescription(elem);
1630 wwarning(_("%s:format error in root menu configuration \"%s\""),
1631 "WMRootMenu", tmp);
1632 wfree(tmp);
1633 return NULL;
1635 mtitle = PLGetString(elem);
1637 menu = wMenuCreate(scr, mtitle, False);
1638 menu->on_destroy = removeShortcutsForMenu;
1640 #ifdef GLOBAL_SUBMENU_FILE
1642 WMenu *submenu;
1643 WMenuEntry *mentry;
1645 submenu = readMenuFile(scr, GLOBAL_SUBMENU_FILE);
1647 if (submenu) {
1648 mentry = wMenuAddCallback(menu, submenu->frame->title, NULL, NULL);
1649 wMenuEntrySetCascade(menu, mentry, submenu);
1652 #endif
1654 for (i=1; i<count; i++) {
1655 elem = PLGetArrayElement(definition, i);
1656 #if 0
1657 if (PLIsString(elem)) {
1658 char *file;
1660 file = PLGetString(elem);
1663 #endif
1664 if (!PLIsArray(elem) || PLGetNumberOfElements(elem) < 2)
1665 goto error;
1667 if (PLIsArray(PLGetArrayElement(elem,1))) {
1668 WMenu *submenu;
1669 WMenuEntry *mentry;
1671 /* submenu */
1672 submenu = configureMenu(scr, elem);
1673 if (submenu) {
1674 mentry = wMenuAddCallback(menu, submenu->frame->title, NULL,
1675 NULL);
1676 wMenuEntrySetCascade(menu, mentry, submenu);
1678 } else {
1679 int idx = 0;
1680 char *shortcut;
1681 /* normal entry */
1683 title = PLGetArrayElement(elem, idx++);
1684 shortcut = PLGetArrayElement(elem, idx++);
1685 if (strcmp(PLGetString(shortcut), "SHORTCUT")==0) {
1686 shortcut = PLGetArrayElement(elem, idx++);
1687 command = PLGetArrayElement(elem, idx++);
1688 } else {
1689 command = shortcut;
1690 shortcut = NULL;
1692 params = PLGetArrayElement(elem, idx++);
1694 if (!title || !command)
1695 goto error;
1697 addMenuEntry(menu, PLGetString(title),
1698 shortcut ? PLGetString(shortcut) : NULL,
1699 PLGetString(command),
1700 params ? PLGetString(params) : NULL, "WMRootMenu");
1702 continue;
1704 error:
1705 tmp = PLGetDescription(elem);
1706 wwarning(_("%s:format error in root menu configuration \"%s\""),
1707 "WMRootMenu", tmp);
1708 wfree(tmp);
1711 return menu;
1722 *----------------------------------------------------------------------
1723 * OpenRootMenu--
1724 * Opens the root menu, parsing the menu configuration from the
1725 * defaults database.
1726 * If the menu is already mapped and is not sticked to the
1727 * root window, it will be unmapped.
1729 * Side effects:
1730 * The menu may be remade.
1732 * Notes:
1733 * Construction of OPEN_MENU entries are delayed to the moment the
1734 * user map's them.
1735 *----------------------------------------------------------------------
1737 void
1738 OpenRootMenu(WScreen *scr, int x, int y, int keyboard)
1740 WMenu *menu=NULL;
1741 proplist_t definition;
1743 static proplist_t domain=NULL;
1745 if (!domain) {
1746 domain = PLMakeString("WMRootMenu");
1750 scr->flags.root_menu_changed_shortcuts = 0;
1751 scr->flags.added_workspace_menu = 0;
1753 if (scr->root_menu && scr->root_menu->flags.mapped) {
1754 menu = scr->root_menu;
1755 if (!menu->flags.buttoned) {
1756 wMenuUnmap(menu);
1757 } else {
1758 wRaiseFrame(menu->frame->core);
1760 if (keyboard)
1761 wMenuMapAt(menu, 0, 0, True);
1762 else
1763 wMenuMapCopyAt(menu, x-menu->frame->core->width/2, y);
1765 return;
1769 definition = WDRootMenu->dictionary;
1772 definition = PLGetDomain(domain);
1774 if (definition) {
1775 if (PLIsArray(definition)) {
1776 if (!scr->root_menu
1777 || WDRootMenu->timestamp > scr->root_menu->timestamp) {
1778 menu = configureMenu(scr, definition);
1779 if (menu)
1780 menu->timestamp = WDRootMenu->timestamp;
1782 } else
1783 menu = NULL;
1784 } else {
1785 menu = configureMenu(scr, definition);
1789 if (!menu) {
1790 /* menu hasn't changed or could not be read */
1791 if (!scr->root_menu) {
1792 wMessageDialog(scr, _("Error"),
1793 _("The applications menu could not be loaded. "
1794 "Look at the console output for a detailed "
1795 "description of the errors."),
1796 _("OK"), NULL, NULL);
1798 menu = makeDefaultMenu(scr);
1799 scr->root_menu = menu;
1801 menu = scr->root_menu;
1802 } else {
1803 /* new root menu */
1804 if (scr->root_menu)
1805 wMenuDestroy(scr->root_menu, True);
1806 scr->root_menu = menu;
1808 if (menu) {
1809 wMenuMapAt(menu, x-menu->frame->core->width/2, y, keyboard);
1812 if (scr->flags.root_menu_changed_shortcuts)
1813 rebindKeygrabs(scr);
1816 #endif /* !LITE */