Fixed calls to hermes lib to work correctly with all depths
[wmaker-crm.git] / src / rootmenu.c
blobce1953242343acdd79ee160ff2fa136220fa254d
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 M_QUICK 1
149 /* menu commands */
151 static void
152 execCommand(WMenu *menu, WMenuEntry *entry)
154 char *cmdline;
156 cmdline = ExpandOptions(menu->frame->screen_ptr, (char*)entry->clientdata);
158 XGrabPointer(dpy, menu->frame->screen_ptr->root_win, True, 0,
159 GrabModeAsync, GrabModeAsync, None, wCursor[WCUR_WAIT],
160 CurrentTime);
161 XSync(dpy, 0);
163 if (cmdline) {
164 ExecuteShellCommand(menu->frame->screen_ptr, cmdline);
165 wfree(cmdline);
167 XUngrabPointer(dpy, CurrentTime);
168 XSync(dpy, 0);
172 static void
173 exitCommand(WMenu *menu, WMenuEntry *entry)
175 static int inside = 0;
177 /* prevent reentrant calls */
178 if (inside)
179 return;
180 inside = 1;
182 if ((long)entry->clientdata==M_QUICK
183 || wMessageDialog(menu->frame->screen_ptr, _("Exit"),
184 _("Exit window manager?"),
185 _("Exit"), _("Cancel"), NULL)==WAPRDefault) {
186 #ifdef DEBUG
187 printf("Exiting WindowMaker.\n");
188 #endif
189 Shutdown(WSExitMode);
191 inside = 0;
195 static void
196 shutdownCommand(WMenu *menu, WMenuEntry *entry)
198 static int inside = 0;
199 int result;
201 /* prevent reentrant calls */
202 if (inside)
203 return;
204 inside = 1;
206 #define R_CANCEL 0
207 #define R_CLOSE 1
208 #define R_KILL 2
211 result = R_CANCEL;
212 if ((long)entry->clientdata==M_QUICK)
213 result = R_CLOSE;
214 else {
215 #ifdef XSMP_ENABLED
216 if (wSessionIsManaged()) {
217 int r;
219 r = wMessageDialog(menu->frame->screen_ptr,
220 _("Close X session"),
221 _("Close Window System session?\n"
222 "Kill might close applications with unsaved data."),
223 _("Close"), _("Kill"), _("Cancel"));
224 if (r==WAPRDefault)
225 result = R_CLOSE;
226 else if (r==WAPRAlternate)
227 result = R_KILL;
228 } else
229 #endif
231 int r;
233 r = wMessageDialog(menu->frame->screen_ptr,
234 _("Kill X session"),
235 _("Kill Window System session?\n"
236 "(all applications will be closed)"),
237 _("Kill"), _("Cancel"), NULL);
238 if (r==WAPRDefault)
239 result = R_KILL;
243 if (result!=R_CANCEL) {
244 #ifdef XSMP_ENABLED
245 if (result == R_CLOSE) {
246 Shutdown(WSLogoutMode);
247 } else
248 #endif /* XSMP_ENABLED */
250 Shutdown(WSKillMode);
253 #undef R_CLOSE
254 #undef R_CANCEL
255 #undef R_KILL
256 inside = 0;
260 static void
261 restartCommand(WMenu *menu, WMenuEntry *entry)
263 Shutdown(WSRestartPreparationMode);
264 Restart((char*)entry->clientdata, False);
265 Restart(NULL, True);
269 static void
270 refreshCommand(WMenu *menu, WMenuEntry *entry)
272 wRefreshDesktop(menu->frame->screen_ptr);
276 static void
277 arrangeIconsCommand(WMenu *menu, WMenuEntry *entry)
279 wArrangeIcons(menu->frame->screen_ptr, True);
282 static void
283 showAllCommand(WMenu *menu, WMenuEntry *entry)
285 wShowAllWindows(menu->frame->screen_ptr);
288 static void
289 hideOthersCommand(WMenu *menu, WMenuEntry *entry)
291 wHideOtherApplications(menu->frame->screen_ptr->focused_window);
295 static void
296 saveSessionCommand(WMenu *menu, WMenuEntry *entry)
298 if (!wPreferences.save_session_on_exit)
299 wSessionSaveState(menu->frame->screen_ptr);
301 wScreenSaveState(menu->frame->screen_ptr);
305 static void
306 clearSessionCommand(WMenu *menu, WMenuEntry *entry)
308 wSessionClearState(menu->frame->screen_ptr);
312 static void
313 infoPanelCommand(WMenu *menu, WMenuEntry *entry)
315 wShowInfoPanel(menu->frame->screen_ptr);
319 static void
320 legalPanelCommand(WMenu *menu, WMenuEntry *entry)
322 wShowLegalPanel(menu->frame->screen_ptr);
326 /********************************************************************/
329 static char*
330 getLocalizedMenuFile(char *menu)
332 char *buffer;
333 char *ptr;
335 if (!Locale)
336 return NULL;
338 buffer = wmalloc(strlen(menu)+32);
340 /* try menu.locale_name */
341 sprintf(buffer, "%s.%s", menu, Locale);
342 if (access(buffer, F_OK)==0) {
343 return buffer;
345 /* check if it is in the form aa_bb.encoding and check for aa_bb */
346 ptr = strchr(Locale, '.');
347 if (ptr) {
348 *ptr = 0;
349 if (access(buffer, F_OK)==0) {
350 return buffer;
353 /* now check for aa */
354 ptr = strchr(buffer, '_');
355 if (ptr) {
356 *ptr = 0;
357 if (access(buffer, F_OK)==0) {
358 return buffer;
362 return NULL;
366 static void
367 raiseMenus(WMenu *menu)
369 int i;
371 if (menu->flags.mapped) {
372 wRaiseFrame(menu->frame->core);
374 for (i=0; i<menu->cascade_no; i++) {
375 if (menu->cascades[i])
376 raiseMenus(menu->cascades[i]);
382 Bool
383 wRootMenuPerformShortcut(XEvent *event)
385 Shortcut *ptr;
386 int modifiers;
387 int done = 0;
389 /* ignore CapsLock */
390 modifiers = event->xkey.state & ValidModMask;
392 for (ptr = shortcutList; ptr!=NULL; ptr = ptr->next) {
393 if (ptr->keycode==0)
394 continue;
396 if (ptr->keycode==event->xkey.keycode && (ptr->modifier==modifiers)) {
397 (*ptr->entry->callback)(ptr->menu, ptr->entry);
398 done = True;
401 return done;
405 void
406 wRootMenuBindShortcuts(Window window)
408 Shortcut *ptr;
410 ptr = shortcutList;
411 while (ptr) {
412 if (ptr->modifier!=AnyModifier) {
413 XGrabKey(dpy, ptr->keycode, ptr->modifier|LockMask,
414 window, True, GrabModeAsync, GrabModeAsync);
415 #ifdef NUMLOCK_HACK
416 wHackedGrabKey(ptr->keycode, ptr->modifier,
417 window, True, GrabModeAsync, GrabModeAsync);
418 #endif
420 XGrabKey(dpy, ptr->keycode, ptr->modifier, window, True,
421 GrabModeAsync, GrabModeAsync);
422 ptr = ptr->next;
427 static void
428 rebindKeygrabs(WScreen *scr)
430 WWindow *wwin;
432 wwin = scr->focused_window;
434 while (wwin!=NULL) {
435 XUngrabKey(dpy, AnyKey, AnyModifier, wwin->frame->core->window);
437 if (!WFLAGP(wwin, no_bind_keys)) {
438 wWindowSetKeyGrabs(wwin);
440 wwin = wwin->prev;
445 static void
446 removeShortcutsForMenu(WMenu *menu)
448 Shortcut *ptr, *tmp;
449 Shortcut *newList = NULL;
451 ptr = shortcutList;
452 while (ptr!=NULL) {
453 tmp = ptr->next;
454 if (ptr->menu == menu) {
455 wfree(ptr);
456 } else {
457 ptr->next = newList;
458 newList = ptr;
460 ptr = tmp;
462 shortcutList = newList;
463 menu->menu->screen_ptr->flags.root_menu_changed_shortcuts = 1;
467 static Bool
468 addShortcut(char *file, char *shortcutDefinition, WMenu *menu,
469 WMenuEntry *entry)
471 Shortcut *ptr;
472 KeySym ksym;
473 char *k;
474 char buf[128], *b;
476 ptr = wmalloc(sizeof(Shortcut));
478 strcpy(buf, shortcutDefinition);
479 b = (char*)buf;
481 /* get modifiers */
482 ptr->modifier = 0;
483 while ((k = strchr(b, '+'))!=NULL) {
484 int mod;
486 *k = 0;
487 mod = wXModifierFromKey(b);
488 if (mod<0) {
489 wwarning(_("%s:invalid key modifier \"%s\""), file, b);
490 wfree(ptr);
491 return False;
493 ptr->modifier |= mod;
495 b = k+1;
498 /* get key */
499 ksym = XStringToKeysym(b);
501 if (ksym==NoSymbol) {
502 wwarning(_("%s:invalid kbd shortcut specification \"%s\" for entry %s"),
503 file, shortcutDefinition, entry->text);
504 wfree(ptr);
505 return False;
508 ptr->keycode = XKeysymToKeycode(dpy, ksym);
509 if (ptr->keycode==0) {
510 wwarning(_("%s:invalid key in shortcut \"%s\" for entry %s"), file,
511 shortcutDefinition, entry->text);
512 wfree(ptr);
513 return False;
516 ptr->menu = menu;
517 ptr->entry = entry;
519 ptr->next = shortcutList;
520 shortcutList = ptr;
522 menu->menu->screen_ptr->flags.root_menu_changed_shortcuts = 1;
524 return True;
528 /*******************************/
530 static char*
531 cropline(char *line)
533 char *end;
535 if (strlen(line)==0)
536 return line;
538 end = &(line[strlen(line)])-1;
539 while (isspace(*line) && *line!=0) line++;
540 while (end>line && isspace(*end)) {
541 *end=0;
542 end--;
544 return line;
548 static char*
549 next_token(char *line, char **next)
551 char *tmp, c;
552 char *ret;
554 *next = NULL;
555 while (*line==' ' || *line=='\t') line++;
557 tmp = line;
559 if (*tmp=='"') {
560 tmp++; line++;
561 while (*tmp!=0 && *tmp!='"') tmp++;
562 if (*tmp!='"') {
563 wwarning(_("%s: unmatched '\"' in menu file"), line);
564 return NULL;
566 } else {
567 do {
568 if (*tmp=='\\')
569 tmp++;
571 if (*tmp!=0)
572 tmp++;
574 } while (*tmp!=0 && *tmp!=' ' && *tmp!='\t');
577 c = *tmp;
578 *tmp = 0;
579 ret = wstrdup(line);
580 *tmp = c;
582 if (c==0)
583 return ret;
584 else
585 tmp++;
587 /* skip blanks */
588 while (*tmp==' ' || *tmp=='\t') tmp++;
590 if (*tmp!=0)
591 *next = tmp;
593 return ret;
597 static void
598 separateCommand(char *line, char ***file, char **command)
600 char *token, *tmp = line;
601 WMArray *array = WMCreateArray(4);
602 int count, i;
604 *file = NULL;
605 *command = NULL;
606 do {
607 token = next_token(tmp, &tmp);
608 if (token) {
609 if (strcmp(token, "WITH")==0) {
610 if (tmp!=NULL && *tmp!=0)
611 *command = wstrdup(tmp);
612 else
613 wwarning(_("%s: missing command"), line);
614 break;
616 WMAddToArray(array, token);
618 } while (token!=NULL && tmp!=NULL);
620 count = WMGetArrayItemCount(array);
621 if (count>0) {
622 *file = wmalloc(sizeof(char*)*(count+1));
623 (*file)[count] = NULL;
624 for (i = 0; i < count; i++) {
625 (*file)[i] = WMGetFromArray(array, i);
628 WMFreeArray(array);
632 static void
633 constructMenu(WMenu *menu, WMenuEntry *entry)
635 WMenu *submenu;
636 struct stat stat_buf;
637 char **path;
638 char *cmd;
639 char *lpath = NULL;
640 int i, first=-1;
641 time_t last=0;
643 separateCommand((char*)entry->clientdata, &path, &cmd);
644 if (path == NULL || *path==NULL || **path==0) {
645 wwarning(_("invalid OPEN_MENU specification: %s"),
646 (char*)entry->clientdata);
647 return;
650 if (path[0][0]=='|') {
651 /* pipe menu */
653 if (!menu->cascades[entry->cascade] ||
654 menu->cascades[entry->cascade]->timestamp == 0) {
655 /* parse pipe */
657 submenu = readMenuPipe(menu->frame->screen_ptr, path);
659 /* there's no automatic reloading */
660 if(submenu != NULL)
661 submenu->timestamp = 1;
662 } else {
663 submenu = NULL;
666 } else {
667 i=0;
668 while(path[i] != NULL) {
669 char *tmp;
671 if (strcmp(path[i], "-noext")==0) {
672 i++;
673 continue;
676 tmp = wexpandpath(path[i]);
677 wfree(path[i]);
678 lpath = getLocalizedMenuFile(tmp);
679 if (lpath) {
680 wfree(tmp);
681 path[i] = lpath;
682 lpath = NULL;
683 } else {
684 path[i] = tmp;
687 if (stat(path[i], &stat_buf)==0) {
688 if (last < stat_buf.st_mtime)
689 last = stat_buf.st_mtime;
690 if (first<0)
691 first=i;
692 } else {
693 wsyserror(_("%s:could not stat menu"), path[i]);
694 /*goto finish;*/
697 i++;
700 if (first < 0) {
701 wsyserror(_("%s:could not stat menu:%s"), "OPEN_MENU",
702 (char*)entry->clientdata);
703 goto finish;
705 stat(path[first], &stat_buf);
706 if (!menu->cascades[entry->cascade]
707 || menu->cascades[entry->cascade]->timestamp < last) {
709 if (S_ISDIR(stat_buf.st_mode)) {
710 /* menu directory */
711 submenu = readMenuDirectory(menu->frame->screen_ptr,
712 entry->text, path, cmd);
713 if (submenu)
714 submenu->timestamp = last;
715 } else if (S_ISREG(stat_buf.st_mode)) {
716 /* menu file */
718 if (cmd || path[1])
719 wwarning(_("too many parameters in OPEN_MENU: %s"),
720 (char*)entry->clientdata);
722 submenu = readMenuFile(menu->frame->screen_ptr, path[first]);
723 if (submenu)
724 submenu->timestamp = stat_buf.st_mtime;
725 } else {
726 submenu = NULL;
728 } else {
729 submenu = NULL;
733 if (submenu) {
734 wMenuEntryRemoveCascade(menu, entry);
735 wMenuEntrySetCascade(menu, entry, submenu);
738 finish:
739 i = 0;
740 while (path[i]!=NULL)
741 wfree(path[i++]);
742 wfree(path);
743 if (cmd)
744 wfree(cmd);
748 static WMenuEntry*
749 addWorkspaceMenu(WScreen *scr, WMenu *menu, char *title)
751 WMenu *wsmenu;
752 WMenuEntry *entry;
754 if (scr->flags.added_workspace_menu) {
755 wwarning(_("There are more than one WORKSPACE_MENU commands in the applications menu. Only one is allowed."));
756 return NULL;
757 } else {
758 scr->flags.added_workspace_menu = 1;
760 wsmenu = wWorkspaceMenuMake(scr, True);
761 scr->workspace_menu = wsmenu;
762 entry = wMenuAddCallback(menu, title, NULL, NULL);
763 wMenuEntrySetCascade(menu, entry, wsmenu);
765 wWorkspaceMenuUpdate(scr, wsmenu);
767 return entry;
770 static WMenuEntry*
771 addWindowsMenu(WScreen *scr, WMenu *menu, char *title)
773 WMenu *wwmenu;
774 WWindow *wwin;
775 WMenuEntry *entry;
777 if (scr->flags.added_windows_menu) {
778 wwarning(_("There are more than one WINDOWS_MENU commands in the applications menu. Only one is allowed."));
779 return NULL;
780 } else {
781 scr->flags.added_windows_menu = 1;
783 wwmenu = wMenuCreate(scr, _("Window List"), False);
784 scr->switch_menu = wwmenu;
785 wwin = scr->focused_window;
786 while (wwin) {
787 UpdateSwitchMenu(scr, wwin, ACTION_ADD);
789 wwin = wwin->prev;
791 entry = wMenuAddCallback(menu, title, NULL, NULL);
792 wMenuEntrySetCascade(menu, entry, wwmenu);
794 return entry;
797 static WMenuEntry*
798 addMenuEntry(WMenu *menu, char *title, char *shortcut, char *command,
799 char *params, char *file_name)
801 WScreen *scr;
802 WMenuEntry *entry = NULL;
803 Bool shortcutOk = False;
805 if (!menu)
806 return NULL;
807 scr = menu->frame->screen_ptr;
808 if (strcmp(command, "OPEN_MENU")==0) {
809 if (!params) {
810 wwarning(_("%s:missing parameter for menu command \"%s\""),
811 file_name, command);
812 } else {
813 WMenu *dummy;
814 char *path;
816 path = wfindfile(DEF_CONFIG_PATHS, params);
817 if (!path) {
818 path = wstrdup(params);
820 dummy = wMenuCreate(scr, title, False);
821 dummy->on_destroy = removeShortcutsForMenu;
822 entry = wMenuAddCallback(menu, title, constructMenu, path);
823 entry->free_cdata = free;
824 wMenuEntrySetCascade(menu, entry, dummy);
826 } else if (strcmp(command, "EXEC")==0) {
827 if (!params)
828 wwarning(_("%s:missing parameter for menu command \"%s\""),
829 file_name, command);
830 else {
831 entry = wMenuAddCallback(menu, title, execCommand,
832 wstrconcat("exec ", params));
833 entry->free_cdata = free;
834 shortcutOk = True;
836 } else if (strcmp(command, "SHEXEC")==0) {
837 if (!params)
838 wwarning(_("%s:missing parameter for menu command \"%s\""),
839 file_name, command);
840 else {
841 entry = wMenuAddCallback(menu, title, execCommand,
842 wstrdup(params));
843 entry->free_cdata = free;
844 shortcutOk = True;
846 } else if (strcmp(command, "EXIT")==0) {
848 if (params && strcmp(params, "QUICK")==0)
849 entry = wMenuAddCallback(menu, title, exitCommand, (void*)M_QUICK);
850 else
851 entry = wMenuAddCallback(menu, title, exitCommand, NULL);
853 shortcutOk = True;
854 } else if (strcmp(command, "SHUTDOWN")==0) {
856 if (params && strcmp(params, "QUICK")==0)
857 entry = wMenuAddCallback(menu, title, shutdownCommand,
858 (void*)M_QUICK);
859 else
860 entry = wMenuAddCallback(menu, title, shutdownCommand, NULL);
862 shortcutOk = True;
863 } else if (strcmp(command, "REFRESH")==0) {
864 entry = wMenuAddCallback(menu, title, refreshCommand, NULL);
866 shortcutOk = True;
867 } else if (strcmp(command, "WORKSPACE_MENU")==0) {
868 entry = addWorkspaceMenu(scr, menu, title);
870 shortcutOk = True;
871 } else if (strcmp(command, "WINDOWS_MENU")==0) {
872 entry = addWindowsMenu(scr, menu, title);
874 shortcutOk = True;
875 } else if (strcmp(command, "ARRANGE_ICONS")==0) {
876 entry = wMenuAddCallback(menu, title, arrangeIconsCommand, NULL);
878 shortcutOk = True;
879 } else if (strcmp(command, "HIDE_OTHERS")==0) {
880 entry = wMenuAddCallback(menu, title, hideOthersCommand, NULL);
882 shortcutOk = True;
883 } else if (strcmp(command, "SHOW_ALL")==0) {
884 entry = wMenuAddCallback(menu, title, showAllCommand, NULL);
886 shortcutOk = True;
887 } else if (strcmp(command, "RESTART")==0) {
888 entry = wMenuAddCallback(menu, title, restartCommand,
889 params ? wstrdup(params) : NULL);
890 entry->free_cdata = free;
891 shortcutOk = True;
892 } else if (strcmp(command, "SAVE_SESSION")==0) {
893 entry = wMenuAddCallback(menu, title, saveSessionCommand, NULL);
895 shortcutOk = True;
896 } else if (strcmp(command, "CLEAR_SESSION")==0) {
897 entry = wMenuAddCallback(menu, title, clearSessionCommand, NULL);
898 shortcutOk = True;
899 } else if (strcmp(command, "INFO_PANEL")==0) {
900 entry = wMenuAddCallback(menu, title, infoPanelCommand, NULL);
901 shortcutOk = True;
902 } else if (strcmp(command, "LEGAL_PANEL")==0) {
903 entry = wMenuAddCallback(menu, title, legalPanelCommand, NULL);
904 shortcutOk = True;
905 } else {
906 wwarning(_("%s:unknown command \"%s\" in menu config."), file_name,
907 command);
909 return NULL;
912 if (shortcut && entry) {
913 if (!shortcutOk) {
914 wwarning(_("%s:can't add shortcut for entry \"%s\""), file_name,
915 title);
916 } else {
917 if (addShortcut(file_name, shortcut, menu, entry)) {
919 entry->rtext = GetShortcutString(shortcut);
921 entry->rtext = wstrdup(shortcut);
927 return entry;
932 /******************* Menu Configuration From File *******************/
934 static void
935 separateline(char *line, char *title, char *command, char *parameter,
936 char *shortcut)
938 int l, i;
940 l = strlen(line);
942 *title = 0;
943 *command = 0;
944 *parameter = 0;
945 *shortcut = 0;
946 /* get the title */
947 while (isspace(*line) && (*line!=0)) line++;
948 if (*line=='"') {
949 line++;
950 i=0;
951 while (line[i]!='"' && (line[i]!=0)) i++;
952 if (line[i]!='"')
953 return;
954 } else {
955 i=0;
956 while (!isspace(line[i]) && (line[i]!=0)) i++;
958 strncpy(title, line, i);
959 title[i++]=0;
960 line+=i;
962 /* get the command or shortcut keyword */
963 while (isspace(*line) && (*line!=0)) line++;
964 if (*line==0)
965 return;
966 i=0;
967 while (!isspace(line[i]) && (line[i]!=0)) i++;
968 strncpy(command, line, i);
969 command[i++]=0;
970 line+=i;
972 if (strcmp(command, "SHORTCUT")==0) {
973 /* get the shortcut key */
974 while (isspace(*line) && (*line!=0)) line++;
975 if (*line=='"') {
976 line++;
977 i=0;
978 while (line[i]!='"' && (line[i]!=0)) i++;
979 if (line[i]!='"')
980 return;
981 } else {
982 i=0;
983 while (!isspace(line[i]) && (line[i]!=0)) i++;
985 strncpy(shortcut, line, i);
986 shortcut[i++]=0;
987 line+=i;
989 *command=0;
991 /* get the command */
992 while (isspace(*line) && (*line!=0)) line++;
993 if (*line==0)
994 return;
995 i=0;
996 while (!isspace(line[i]) && (line[i]!=0)) i++;
997 strncpy(command, line, i);
998 command[i++]=0;
999 line+=i;
1002 /* get the parameters */
1003 while (isspace(*line) && (*line!=0)) line++;
1004 if (*line==0)
1005 return;
1007 if (*line=='"') {
1008 line++;
1009 l = 0;
1010 while (line[l]!=0 && line[l]!='"') {
1011 parameter[l] = line[l];
1012 l++;
1014 parameter[l] = 0;
1015 return;
1018 l = strlen(line);
1019 while (isspace(line[l]) && (l>0)) l--;
1020 strncpy(parameter, line, l);
1021 parameter[l]=0;
1025 static WMenu*
1026 parseCascade(WScreen *scr, WMenu *menu, FILE *file, char *file_name)
1028 char linebuf[MAXLINE];
1029 char elinebuf[MAXLINE];
1030 char title[MAXLINE];
1031 char command[MAXLINE];
1032 char shortcut[MAXLINE];
1033 char params[MAXLINE];
1034 char *line;
1036 while (!IsEof(file)) {
1037 int lsize, ok;
1039 ok = 0;
1040 fgets(linebuf, MAXLINE, file);
1041 line = cropline(linebuf);
1042 lsize = strlen(line);
1043 do {
1044 if (line[lsize-1]=='\\') {
1045 char *line2;
1046 int lsize2;
1047 fgets(elinebuf, MAXLINE, file);
1048 line2=cropline(elinebuf);
1049 lsize2=strlen(line2);
1050 if (lsize2+lsize>MAXLINE) {
1051 wwarning(_("%s:maximal line size exceeded in menu config: %s"),
1052 file_name, line);
1053 ok=2;
1054 } else {
1055 line[lsize-1]=0;
1056 lsize+=lsize2-1;
1057 strcat(line, line2);
1059 } else {
1060 ok=1;
1062 } while (!ok && !IsEof(file));
1063 if (ok==2)
1064 continue;
1066 if (line[0]==0 || line[0]=='#' || (line[0]=='/' && line[1]=='/'))
1067 continue;
1070 separateline(line, title, command, params, shortcut);
1072 if (!command[0]) {
1073 wwarning(_("%s:missing command in menu config: %s"), file_name,
1074 line);
1075 goto error;
1078 if (strcasecmp(command, "MENU")==0) {
1079 WMenu *cascade;
1081 /* start submenu */
1083 cascade = wMenuCreate(scr, title, False);
1084 cascade->on_destroy = removeShortcutsForMenu;
1085 if (parseCascade(scr, cascade, file, file_name)==NULL) {
1086 wMenuDestroy(cascade, True);
1087 } else {
1088 wMenuEntrySetCascade(menu,
1089 wMenuAddCallback(menu, title, NULL, NULL),
1090 cascade);
1092 } else if (strcasecmp(command, "END")==0) {
1093 /* end of menu */
1094 return menu;
1096 } else {
1097 /* normal items */
1098 addMenuEntry(menu, title, shortcut[0] ? shortcut : NULL, command,
1099 params[0] ? params : NULL, file_name);
1103 wwarning(_("%s:syntax error in menu file:END declaration missing"),
1104 file_name);
1105 return menu;
1107 error:
1108 return menu;
1112 static WMenu*
1113 readMenuFile(WScreen *scr, char *file_name)
1115 WMenu *menu=NULL;
1116 FILE *file = NULL;
1117 char linebuf[MAXLINE];
1118 char title[MAXLINE];
1119 char shortcut[MAXLINE];
1120 char command[MAXLINE];
1121 char params[MAXLINE];
1122 char *line;
1123 #ifdef USECPP
1124 char *args;
1125 int cpp = 0;
1126 #endif
1128 #ifdef USECPP
1129 if (!wPreferences.flags.nocpp) {
1130 args = MakeCPPArgs(file_name);
1131 if (!args) {
1132 wwarning(_("could not make arguments for menu file preprocessor"));
1133 } else {
1134 sprintf(command, "%s %s %s", CPP_PATH, args, file_name);
1135 wfree(args);
1136 file = popen(command, "r");
1137 if (!file) {
1138 wsyserror(_("%s:could not open/preprocess menu file"),
1139 file_name);
1140 } else {
1141 cpp = 1;
1145 #endif /* USECPP */
1147 if (!file) {
1148 file = fopen(file_name, "r");
1149 if (!file) {
1150 wsyserror(_("%s:could not open menu file"), file_name);
1151 return NULL;
1155 while (!IsEof(file)) {
1156 if (!fgets(linebuf, MAXLINE, file))
1157 break;
1158 line = cropline(linebuf);
1159 if (line[0]==0 || line[0]=='#' || (line[0]=='/' && line[1]=='/'))
1160 continue;
1162 separateline(line, title, command, params, shortcut);
1164 if (!command[0]) {
1165 wwarning(_("%s:missing command in menu config: %s"), file_name,
1166 line);
1167 break;
1169 if (strcasecmp(command, "MENU")==0) {
1170 menu = wMenuCreate(scr, title, True);
1171 menu->on_destroy = removeShortcutsForMenu;
1172 if (!parseCascade(scr, menu, file, file_name)) {
1173 wMenuDestroy(menu, True);
1175 break;
1176 } else {
1177 wwarning(_("%s:invalid menu file. MENU command is missing"),
1178 file_name);
1179 break;
1183 #ifdef CPP
1184 if (cpp) {
1185 if (pclose(file)==-1) {
1186 wsyserror(_("error reading preprocessed menu data"));
1188 } else {
1189 fclose(file);
1191 #else
1192 fclose(file);
1193 #endif
1195 return menu;
1198 /************ Menu Configuration From Pipe *************/
1200 static WMenu*
1201 readMenuPipe(WScreen *scr, char **file_name)
1203 WMenu *menu=NULL;
1204 FILE *file = NULL;
1205 char linebuf[MAXLINE];
1206 char title[MAXLINE];
1207 char command[MAXLINE];
1208 char params[MAXLINE];
1209 char shortcut[MAXLINE];
1210 char *line;
1211 char * filename;
1212 char flat_file[MAXLINE];
1213 int i;
1214 #ifdef USECPP
1215 char *args;
1216 int cpp = 0;
1217 #endif
1219 flat_file[0] = '\0';
1221 for(i = 0 ; file_name[i] != NULL ; i++) {
1222 strcat(flat_file, file_name[i]);
1223 strcat(flat_file, " ");
1225 filename = flat_file+1;
1227 #ifdef USECPP
1228 if (!wPreferences.flags.nocpp) {
1229 args = MakeCPPArgs(filename);
1230 if (!args) {
1231 wwarning(_("could not make arguments for menu file preprocessor"));
1232 } else {
1233 sprintf(command, "%s | %s %s", filename, CPP_PATH, args);
1235 wfree(args);
1236 file = popen(command, "r");
1237 if (!file) {
1238 wsyserror(_("%s:could not open/preprocess menu file"), filename);
1239 } else {
1240 cpp = 1;
1245 #endif /* USECPP */
1247 if (!file) {
1248 file = popen(filename, "r");
1250 if (!file) {
1251 wsyserror(_("%s:could not open menu file"), filename);
1252 return NULL;
1256 while (!IsEof(file)) {
1257 if (!fgets(linebuf, MAXLINE, file))
1258 break;
1259 line = cropline(linebuf);
1260 if (line[0]==0 || line[0]=='#' || (line[0]=='/' && line[1]=='/'))
1261 continue;
1263 separateline(line, title, command, params, shortcut);
1265 if (!command[0]) {
1266 wwarning(_("%s:missing command in menu config: %s"), file_name,
1267 line);
1268 break;
1270 if (strcasecmp(command, "MENU")==0) {
1271 menu = wMenuCreate(scr, title, True);
1272 menu->on_destroy = removeShortcutsForMenu;
1273 if (!parseCascade(scr, menu, file, filename)) {
1274 wMenuDestroy(menu, True);
1276 break;
1277 } else {
1278 wwarning(_("%s:no title given for the root menu"), filename);
1279 break;
1283 pclose(file);
1285 return menu;
1290 typedef struct {
1291 char *name;
1292 int index;
1293 } dir_data;
1296 static int
1297 myCompare(const void *d1, const void *d2)
1299 dir_data *p1 = *(dir_data**)d1;
1300 dir_data *p2 = *(dir_data**)d2;
1302 return strcmp(p1->name, p2->name);
1306 /************ Menu Configuration From Directory *************/
1308 static Bool
1309 isFilePackage(char *file)
1311 int l;
1313 /* check if the extension indicates this file is a
1314 * file package. For now, only recognize .themed */
1316 l = strlen(file);
1318 if (l > 7 && strcmp(&(file[l-7]), ".themed")==0) {
1319 return True;
1320 } else {
1321 return False;
1326 static WMenu*
1327 readMenuDirectory(WScreen *scr, char *title, char **path, char *command)
1329 DIR *dir;
1330 struct dirent *dentry;
1331 struct stat stat_buf;
1332 WMenu *menu=NULL;
1333 char *buffer;
1334 WMArray *dirs = NULL, *files = NULL;
1335 WMArrayIterator iter;
1336 int length, i, have_space=0;
1337 dir_data *data;
1338 int stripExtension = 0;
1341 dirs = WMCreateArray(16);
1342 files = WMCreateArray(16);
1344 i=0;
1345 while (path[i]!=NULL) {
1346 if (strcmp(path[i], "-noext")==0) {
1347 stripExtension = 1;
1348 i++;
1349 continue;
1352 dir = opendir(path[i]);
1353 if (!dir) {
1354 i++;
1355 continue;
1358 while ((dentry = readdir(dir))) {
1360 if (strcmp(dentry->d_name, ".")==0 ||
1361 strcmp(dentry->d_name, "..")==0)
1362 continue;
1364 if (dentry->d_name[0] == '.')
1365 continue;
1367 buffer = malloc(strlen(path[i])+strlen(dentry->d_name)+4);
1368 if (!buffer) {
1369 wsyserror(_("out of memory while constructing directory menu %s"),
1370 path[i]);
1371 break;
1374 strcpy(buffer, path[i]);
1375 strcat(buffer, "/");
1376 strcat(buffer, dentry->d_name);
1378 if (stat(buffer, &stat_buf)!=0) {
1379 wsyserror(_("%s:could not stat file \"%s\" in menu directory"),
1380 path[i], dentry->d_name);
1381 } else {
1382 Bool isFilePack = False;
1384 data = NULL;
1385 if (S_ISDIR(stat_buf.st_mode)
1386 && !(isFilePack = isFilePackage(dentry->d_name))) {
1388 /* access always returns success for user root */
1389 if (access(buffer, X_OK)==0) {
1390 /* Directory is accesible. Add to directory list */
1392 data = (dir_data*) wmalloc(sizeof(dir_data));
1393 data->name = wstrdup(dentry->d_name);
1394 data->index = i;
1396 WMAddToArray(dirs, data);
1398 } else if (S_ISREG(stat_buf.st_mode) || isFilePack) {
1399 /* Hack because access always returns X_OK success for user root */
1400 #define S_IXANY (S_IXUSR | S_IXGRP | S_IXOTH)
1401 if ((command!=NULL && access(buffer, R_OK)==0) ||
1402 (command==NULL && access(buffer, X_OK)==0 &&
1403 (stat_buf.st_mode & S_IXANY))) {
1405 data = (dir_data*) wmalloc(sizeof(dir_data));
1406 data->name = wstrdup(dentry->d_name);
1407 data->index = i;
1409 WMAddToArray(files, data);
1413 wfree(buffer);
1416 closedir(dir);
1417 i++;
1420 if (!WMGetArrayItemCount(dirs) && !WMGetArrayItemCount(files)) {
1421 WMFreeArray(dirs);
1422 WMFreeArray(files);
1423 return NULL;
1426 WMSortArray(dirs, myCompare);
1427 WMSortArray(files, myCompare);
1429 menu = wMenuCreate(scr, title, False);
1430 menu->on_destroy = removeShortcutsForMenu;
1432 WM_ITERATE_ARRAY(dirs, data, iter) {
1433 /* New directory. Use same OPEN_MENU command that was used
1434 * for the current directory. */
1435 length = strlen(path[data->index])+strlen(data->name)+6;
1436 if (stripExtension)
1437 length += 7;
1438 if (command)
1439 length += strlen(command) + 6;
1440 buffer = malloc(length);
1441 if (!buffer) {
1442 wsyserror(_("out of memory while constructing directory menu %s"),
1443 path[data->index]);
1444 break;
1447 buffer[0] = '\0';
1448 if (stripExtension)
1449 strcat(buffer, "-noext ");
1451 have_space = strchr(path[data->index], ' ')!=NULL ||
1452 strchr(data->name, ' ')!=NULL;
1454 if (have_space)
1455 strcat(buffer, "\"");
1456 strcat(buffer, path[data->index]);
1458 strcat(buffer, "/");
1459 strcat(buffer, data->name);
1460 if (have_space)
1461 strcat(buffer, "\"");
1462 if (command) {
1463 strcat(buffer, " WITH ");
1464 strcat(buffer, command);
1467 addMenuEntry(menu, data->name, NULL, "OPEN_MENU", buffer, path[data->index]);
1469 wfree(buffer);
1470 if (data->name)
1471 wfree(data->name);
1472 wfree(data);
1475 WM_ITERATE_ARRAY(files, data, iter) {
1476 /* executable: add as entry */
1477 length = strlen(path[data->index])+strlen(data->name)+6;
1478 if (command)
1479 length += strlen(command);
1481 buffer = malloc(length);
1482 if (!buffer) {
1483 wsyserror(_("out of memory while constructing directory menu %s"),
1484 path[data->index]);
1485 break;
1488 have_space = strchr(path[data->index], ' ')!=NULL ||
1489 strchr(data->name, ' ')!=NULL;
1490 if (command!=NULL) {
1491 strcpy(buffer, command);
1492 strcat(buffer, " ");
1493 if (have_space)
1494 strcat(buffer, "\"");
1495 strcat(buffer, path[data->index]);
1496 } else {
1497 if (have_space) {
1498 buffer[0] = '"';
1499 buffer[1] = 0;
1500 strcat(buffer, path[data->index]);
1501 } else {
1502 strcpy(buffer, path[data->index]);
1505 strcat(buffer, "/");
1506 strcat(buffer, data->name);
1507 if (have_space)
1508 strcat(buffer, "\"");
1510 if (stripExtension) {
1511 char *ptr = strrchr(data->name, '.');
1512 if (ptr && ptr!=data->name)
1513 *ptr = 0;
1515 addMenuEntry(menu, data->name, NULL, "SHEXEC", buffer, path[data->index]);
1517 wfree(buffer);
1518 if (data->name)
1519 wfree(data->name);
1520 wfree(data);
1523 WMFreeArray(files);
1524 WMFreeArray(dirs);
1526 return menu;
1530 /************ Menu Configuration From WMRootMenu *************/
1532 static WMenu*
1533 makeDefaultMenu(WScreen *scr)
1535 WMenu *menu=NULL;
1537 menu = wMenuCreate(scr, _("Commands"), True);
1538 wMenuAddCallback(menu, "XTerm", execCommand, "xterm");
1539 wMenuAddCallback(menu, "rxvt", execCommand, "rxvt");
1540 wMenuAddCallback(menu, _("Restart"), restartCommand, NULL);
1541 wMenuAddCallback(menu, _("Exit..."), exitCommand, NULL);
1542 return menu;
1550 *----------------------------------------------------------------------
1551 * configureMenu--
1552 * Reads root menu configuration from defaults database.
1554 *----------------------------------------------------------------------
1556 static WMenu*
1557 configureMenu(WScreen *scr, proplist_t definition)
1559 WMenu *menu = NULL;
1560 proplist_t elem;
1561 int i, count;
1562 proplist_t title, command, params;
1563 char *tmp, *mtitle;
1566 if (PLIsString(definition)) {
1567 struct stat stat_buf;
1568 char *path = NULL;
1569 Bool menu_is_default = False;
1571 /* menu definition is a string. Probably a path, so parse the file */
1573 tmp = wexpandpath(PLGetString(definition));
1575 path = getLocalizedMenuFile(tmp);
1577 if (!path)
1578 path = wfindfile(DEF_CONFIG_PATHS, tmp);
1580 if (!path) {
1581 path = wfindfile(DEF_CONFIG_PATHS, DEF_MENU_FILE);
1582 menu_is_default = True;
1585 if (!path) {
1586 wsyserror(_("could not find menu file \"%s\" referenced in WMRootMenu"),
1587 tmp);
1588 wfree(tmp);
1589 return NULL;
1592 if (stat(path, &stat_buf)<0) {
1593 wsyserror(_("could not access menu \"%s\" referenced in WMRootMenu"), path);
1594 wfree(path);
1595 wfree(tmp);
1596 return NULL;
1599 if (!scr->root_menu || stat_buf.st_mtime > scr->root_menu->timestamp
1600 /* if the pointer in WMRootMenu has changed */
1601 || WDRootMenu->timestamp > scr->root_menu->timestamp) {
1603 if (menu_is_default) {
1604 wwarning(_("using default menu file \"%s\" as the menu referenced in WMRootMenu could not be found "),
1605 path);
1608 menu = readMenuFile(scr, path);
1609 if (menu)
1610 menu->timestamp = WMAX(stat_buf.st_mtime, WDRootMenu->timestamp);
1611 } else {
1612 menu = NULL;
1614 wfree(path);
1615 wfree(tmp);
1617 return menu;
1620 count = PLGetNumberOfElements(definition);
1621 if (count==0)
1622 return NULL;
1624 elem = PLGetArrayElement(definition, 0);
1625 if (!PLIsString(elem)) {
1626 tmp = PLGetDescription(elem);
1627 wwarning(_("%s:format error in root menu configuration \"%s\""),
1628 "WMRootMenu", tmp);
1629 wfree(tmp);
1630 return NULL;
1632 mtitle = PLGetString(elem);
1634 menu = wMenuCreate(scr, mtitle, False);
1635 menu->on_destroy = removeShortcutsForMenu;
1637 #ifdef GLOBAL_SUBMENU_FILE
1639 WMenu *submenu;
1640 WMenuEntry *mentry;
1642 submenu = readMenuFile(scr, GLOBAL_SUBMENU_FILE);
1644 if (submenu) {
1645 mentry = wMenuAddCallback(menu, submenu->frame->title, NULL, NULL);
1646 wMenuEntrySetCascade(menu, mentry, submenu);
1649 #endif
1651 for (i=1; i<count; i++) {
1652 elem = PLGetArrayElement(definition, i);
1653 #if 0
1654 if (PLIsString(elem)) {
1655 char *file;
1657 file = PLGetString(elem);
1660 #endif
1661 if (!PLIsArray(elem) || PLGetNumberOfElements(elem) < 2)
1662 goto error;
1664 if (PLIsArray(PLGetArrayElement(elem,1))) {
1665 WMenu *submenu;
1666 WMenuEntry *mentry;
1668 /* submenu */
1669 submenu = configureMenu(scr, elem);
1670 if (submenu) {
1671 mentry = wMenuAddCallback(menu, submenu->frame->title, NULL,
1672 NULL);
1673 wMenuEntrySetCascade(menu, mentry, submenu);
1675 } else {
1676 int idx = 0;
1677 char *shortcut;
1678 /* normal entry */
1680 title = PLGetArrayElement(elem, idx++);
1681 shortcut = PLGetArrayElement(elem, idx++);
1682 if (strcmp(PLGetString(shortcut), "SHORTCUT")==0) {
1683 shortcut = PLGetArrayElement(elem, idx++);
1684 command = PLGetArrayElement(elem, idx++);
1685 } else {
1686 command = shortcut;
1687 shortcut = NULL;
1689 params = PLGetArrayElement(elem, idx++);
1691 if (!title || !command)
1692 goto error;
1694 addMenuEntry(menu, PLGetString(title),
1695 shortcut ? PLGetString(shortcut) : NULL,
1696 PLGetString(command),
1697 params ? PLGetString(params) : NULL, "WMRootMenu");
1699 continue;
1701 error:
1702 tmp = PLGetDescription(elem);
1703 wwarning(_("%s:format error in root menu configuration \"%s\""),
1704 "WMRootMenu", tmp);
1705 wfree(tmp);
1708 return menu;
1719 *----------------------------------------------------------------------
1720 * OpenRootMenu--
1721 * Opens the root menu, parsing the menu configuration from the
1722 * defaults database.
1723 * If the menu is already mapped and is not sticked to the
1724 * root window, it will be unmapped.
1726 * Side effects:
1727 * The menu may be remade.
1729 * Notes:
1730 * Construction of OPEN_MENU entries are delayed to the moment the
1731 * user map's them.
1732 *----------------------------------------------------------------------
1734 void
1735 OpenRootMenu(WScreen *scr, int x, int y, int keyboard)
1737 WMenu *menu=NULL;
1738 proplist_t definition;
1740 static proplist_t domain=NULL;
1742 if (!domain) {
1743 domain = PLMakeString("WMRootMenu");
1747 scr->flags.root_menu_changed_shortcuts = 0;
1748 scr->flags.added_workspace_menu = 0;
1750 if (scr->root_menu && scr->root_menu->flags.mapped) {
1751 menu = scr->root_menu;
1752 if (!menu->flags.buttoned) {
1753 wMenuUnmap(menu);
1754 } else {
1755 wRaiseFrame(menu->frame->core);
1757 if (keyboard)
1758 wMenuMapAt(menu, 0, 0, True);
1759 else
1760 wMenuMapCopyAt(menu, x-menu->frame->core->width/2, y);
1762 return;
1766 definition = WDRootMenu->dictionary;
1769 definition = PLGetDomain(domain);
1771 if (definition) {
1772 if (PLIsArray(definition)) {
1773 if (!scr->root_menu
1774 || WDRootMenu->timestamp > scr->root_menu->timestamp) {
1775 menu = configureMenu(scr, definition);
1776 if (menu)
1777 menu->timestamp = WDRootMenu->timestamp;
1779 } else
1780 menu = NULL;
1781 } else {
1782 menu = configureMenu(scr, definition);
1786 if (!menu) {
1787 /* menu hasn't changed or could not be read */
1788 if (!scr->root_menu) {
1789 wMessageDialog(scr, _("Error"),
1790 _("The applications menu could not be loaded. "
1791 "Look at the console output for a detailed "
1792 "description of the errors."),
1793 _("OK"), NULL, NULL);
1795 menu = makeDefaultMenu(scr);
1796 scr->root_menu = menu;
1798 menu = scr->root_menu;
1799 } else {
1800 /* new root menu */
1801 if (scr->root_menu)
1802 wMenuDestroy(scr->root_menu, True);
1803 scr->root_menu = menu;
1805 if (menu) {
1806 int newx, newy;
1808 if (keyboard && x==0 && y==0) {
1809 newx = newy = 0;
1810 } else if (keyboard && x==scr->scr_width/2 && y==scr->scr_height/2) {
1811 newx = x - menu->frame->core->width/2;
1812 newy = y - menu->frame->core->height/2;
1813 } else {
1814 newx = x - menu->frame->core->width/2;
1815 newy = y;
1817 wMenuMapAt(menu, newx, newy, keyboard);
1820 if (scr->flags.root_menu_changed_shortcuts)
1821 rebindKeygrabs(scr);
1824 #endif /* !LITE */