- Finished moving to the new proplist handling code in WINGs.
[wmaker-crm.git] / src / rootmenu.c
blob8896767173ca39bb26e0eef742035943e28011d6
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;
178 /* prevent reentrant calls */
179 if (inside)
180 return;
181 inside = 1;
183 if ((long)entry->clientdata==M_QUICK
184 || wMessageDialog(menu->frame->screen_ptr, _("Exit"),
185 _("Exit window manager?"),
186 _("Exit"), _("Cancel"), NULL)==WAPRDefault) {
187 #ifdef DEBUG
188 printf("Exiting WindowMaker.\n");
189 #endif
190 Shutdown(WSExitMode);
192 inside = 0;
196 static void
197 shutdownCommand(WMenu *menu, WMenuEntry *entry)
199 static int inside = 0;
200 int result;
202 /* prevent reentrant calls */
203 if (inside)
204 return;
205 inside = 1;
207 #define R_CANCEL 0
208 #define R_CLOSE 1
209 #define R_KILL 2
212 result = R_CANCEL;
213 if ((long)entry->clientdata==M_QUICK)
214 result = R_CLOSE;
215 else {
216 #ifdef XSMP_ENABLED
217 if (wSessionIsManaged()) {
218 int r;
220 r = wMessageDialog(menu->frame->screen_ptr,
221 _("Close X session"),
222 _("Close Window System session?\n"
223 "Kill might close applications with unsaved data."),
224 _("Close"), _("Kill"), _("Cancel"));
225 if (r==WAPRDefault)
226 result = R_CLOSE;
227 else if (r==WAPRAlternate)
228 result = R_KILL;
229 } else
230 #endif
232 int r;
234 r = wMessageDialog(menu->frame->screen_ptr,
235 _("Kill X session"),
236 _("Kill Window System session?\n"
237 "(all applications will be closed)"),
238 _("Kill"), _("Cancel"), NULL);
239 if (r==WAPRDefault)
240 result = R_KILL;
244 if (result!=R_CANCEL) {
245 #ifdef XSMP_ENABLED
246 if (result == R_CLOSE) {
247 Shutdown(WSLogoutMode);
248 } else
249 #endif /* XSMP_ENABLED */
251 Shutdown(WSKillMode);
254 #undef R_CLOSE
255 #undef R_CANCEL
256 #undef R_KILL
257 inside = 0;
261 static void
262 restartCommand(WMenu *menu, WMenuEntry *entry)
264 Shutdown(WSRestartPreparationMode);
265 Restart((char*)entry->clientdata, False);
266 Restart(NULL, True);
270 static void
271 refreshCommand(WMenu *menu, WMenuEntry *entry)
273 wRefreshDesktop(menu->frame->screen_ptr);
277 static void
278 arrangeIconsCommand(WMenu *menu, WMenuEntry *entry)
280 wArrangeIcons(menu->frame->screen_ptr, True);
283 static void
284 showAllCommand(WMenu *menu, WMenuEntry *entry)
286 wShowAllWindows(menu->frame->screen_ptr);
289 static void
290 hideOthersCommand(WMenu *menu, WMenuEntry *entry)
292 wHideOtherApplications(menu->frame->screen_ptr->focused_window);
296 static void
297 saveSessionCommand(WMenu *menu, WMenuEntry *entry)
299 if (!wPreferences.save_session_on_exit)
300 wSessionSaveState(menu->frame->screen_ptr);
302 wScreenSaveState(menu->frame->screen_ptr);
306 static void
307 clearSessionCommand(WMenu *menu, WMenuEntry *entry)
309 wSessionClearState(menu->frame->screen_ptr);
313 static void
314 infoPanelCommand(WMenu *menu, WMenuEntry *entry)
316 wShowInfoPanel(menu->frame->screen_ptr);
320 static void
321 legalPanelCommand(WMenu *menu, WMenuEntry *entry)
323 wShowLegalPanel(menu->frame->screen_ptr);
327 /********************************************************************/
330 static char*
331 getLocalizedMenuFile(char *menu)
333 char *buffer;
334 char *ptr;
335 int len;
337 if (!Locale)
338 return NULL;
340 len = strlen(menu)+strlen(Locale)+8;
341 buffer = wmalloc(len);
343 /* try menu.locale_name */
344 snprintf(buffer, len, "%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 void
752 cleanupWorkspaceMenu(WMenu *menu)
754 if (menu->frame->screen_ptr->workspace_menu == menu)
755 menu->frame->screen_ptr->workspace_menu = NULL;
759 static WMenuEntry*
760 addWorkspaceMenu(WScreen *scr, WMenu *menu, char *title)
762 WMenu *wsmenu;
763 WMenuEntry *entry;
765 if (scr->flags.added_workspace_menu) {
766 wwarning(_("There are more than one WORKSPACE_MENU commands in the applications menu. Only one is allowed."));
767 return NULL;
768 } else {
769 scr->flags.added_workspace_menu = 1;
771 wsmenu = wWorkspaceMenuMake(scr, True);
772 wsmenu->on_destroy = cleanupWorkspaceMenu;
774 scr->workspace_menu = wsmenu;
775 entry = wMenuAddCallback(menu, title, NULL, NULL);
776 wMenuEntrySetCascade(menu, entry, wsmenu);
778 wWorkspaceMenuUpdate(scr, wsmenu);
780 return entry;
784 static void
785 cleanupWindowsMenu(WMenu *menu)
787 if (menu->frame->screen_ptr->switch_menu == menu)
788 menu->frame->screen_ptr->switch_menu = NULL;
792 static WMenuEntry*
793 addWindowsMenu(WScreen *scr, WMenu *menu, char *title)
795 WMenu *wwmenu;
796 WWindow *wwin;
797 WMenuEntry *entry;
799 if (scr->flags.added_windows_menu) {
800 wwarning(_("There are more than one WINDOWS_MENU commands in the applications menu. Only one is allowed."));
801 return NULL;
802 } else {
803 scr->flags.added_windows_menu = 1;
805 wwmenu = wMenuCreate(scr, _("Window List"), False);
806 wwmenu->on_destroy = cleanupWindowsMenu;
807 scr->switch_menu = wwmenu;
808 wwin = scr->focused_window;
809 while (wwin) {
810 UpdateSwitchMenu(scr, wwin, ACTION_ADD);
812 wwin = wwin->prev;
814 entry = wMenuAddCallback(menu, title, NULL, NULL);
815 wMenuEntrySetCascade(menu, entry, wwmenu);
817 return entry;
821 static WMenuEntry*
822 addMenuEntry(WMenu *menu, char *title, char *shortcut, char *command,
823 char *params, char *file_name)
825 WScreen *scr;
826 WMenuEntry *entry = NULL;
827 Bool shortcutOk = False;
829 if (!menu)
830 return NULL;
831 scr = menu->frame->screen_ptr;
832 if (strcmp(command, "OPEN_MENU")==0) {
833 if (!params) {
834 wwarning(_("%s:missing parameter for menu command \"%s\""),
835 file_name, command);
836 } else {
837 WMenu *dummy;
838 char *path;
840 path = wfindfile(DEF_CONFIG_PATHS, params);
841 if (!path) {
842 path = wstrdup(params);
844 dummy = wMenuCreate(scr, title, False);
845 dummy->on_destroy = removeShortcutsForMenu;
846 entry = wMenuAddCallback(menu, title, constructMenu, path);
847 entry->free_cdata = free;
848 wMenuEntrySetCascade(menu, entry, dummy);
850 } else if (strcmp(command, "EXEC")==0) {
851 if (!params)
852 wwarning(_("%s:missing parameter for menu command \"%s\""),
853 file_name, command);
854 else {
855 entry = wMenuAddCallback(menu, title, execCommand,
856 wstrconcat("exec ", params));
857 entry->free_cdata = free;
858 shortcutOk = True;
860 } else if (strcmp(command, "SHEXEC")==0) {
861 if (!params)
862 wwarning(_("%s:missing parameter for menu command \"%s\""),
863 file_name, command);
864 else {
865 entry = wMenuAddCallback(menu, title, execCommand,
866 wstrdup(params));
867 entry->free_cdata = free;
868 shortcutOk = True;
870 } else if (strcmp(command, "EXIT")==0) {
872 if (params && strcmp(params, "QUICK")==0)
873 entry = wMenuAddCallback(menu, title, exitCommand, (void*)M_QUICK);
874 else
875 entry = wMenuAddCallback(menu, title, exitCommand, NULL);
877 shortcutOk = True;
878 } else if (strcmp(command, "SHUTDOWN")==0) {
880 if (params && strcmp(params, "QUICK")==0)
881 entry = wMenuAddCallback(menu, title, shutdownCommand,
882 (void*)M_QUICK);
883 else
884 entry = wMenuAddCallback(menu, title, shutdownCommand, NULL);
886 shortcutOk = True;
887 } else if (strcmp(command, "REFRESH")==0) {
888 entry = wMenuAddCallback(menu, title, refreshCommand, NULL);
890 shortcutOk = True;
891 } else if (strcmp(command, "WORKSPACE_MENU")==0) {
892 entry = addWorkspaceMenu(scr, menu, title);
894 shortcutOk = True;
895 } else if (strcmp(command, "WINDOWS_MENU")==0) {
896 entry = addWindowsMenu(scr, menu, title);
898 shortcutOk = True;
899 } else if (strcmp(command, "ARRANGE_ICONS")==0) {
900 entry = wMenuAddCallback(menu, title, arrangeIconsCommand, NULL);
902 shortcutOk = True;
903 } else if (strcmp(command, "HIDE_OTHERS")==0) {
904 entry = wMenuAddCallback(menu, title, hideOthersCommand, NULL);
906 shortcutOk = True;
907 } else if (strcmp(command, "SHOW_ALL")==0) {
908 entry = wMenuAddCallback(menu, title, showAllCommand, NULL);
910 shortcutOk = True;
911 } else if (strcmp(command, "RESTART")==0) {
912 entry = wMenuAddCallback(menu, title, restartCommand,
913 params ? wstrdup(params) : NULL);
914 entry->free_cdata = free;
915 shortcutOk = True;
916 } else if (strcmp(command, "SAVE_SESSION")==0) {
917 entry = wMenuAddCallback(menu, title, saveSessionCommand, NULL);
919 shortcutOk = True;
920 } else if (strcmp(command, "CLEAR_SESSION")==0) {
921 entry = wMenuAddCallback(menu, title, clearSessionCommand, NULL);
922 shortcutOk = True;
923 } else if (strcmp(command, "INFO_PANEL")==0) {
924 entry = wMenuAddCallback(menu, title, infoPanelCommand, NULL);
925 shortcutOk = True;
926 } else if (strcmp(command, "LEGAL_PANEL")==0) {
927 entry = wMenuAddCallback(menu, title, legalPanelCommand, NULL);
928 shortcutOk = True;
929 } else {
930 wwarning(_("%s:unknown command \"%s\" in menu config."), file_name,
931 command);
933 return NULL;
936 if (shortcut && entry) {
937 if (!shortcutOk) {
938 wwarning(_("%s:can't add shortcut for entry \"%s\""), file_name,
939 title);
940 } else {
941 if (addShortcut(file_name, shortcut, menu, entry)) {
943 entry->rtext = GetShortcutString(shortcut);
945 entry->rtext = wstrdup(shortcut);
951 return entry;
956 /******************* Menu Configuration From File *******************/
958 static void
959 separateline(char *line, char *title, char *command, char *parameter,
960 char *shortcut)
962 int l, i;
964 l = strlen(line);
966 *title = 0;
967 *command = 0;
968 *parameter = 0;
969 *shortcut = 0;
970 /* get the title */
971 while (isspace(*line) && (*line!=0)) line++;
972 if (*line=='"') {
973 line++;
974 i=0;
975 while (line[i]!='"' && (line[i]!=0)) i++;
976 if (line[i]!='"')
977 return;
978 } else {
979 i=0;
980 while (!isspace(line[i]) && (line[i]!=0)) i++;
982 strncpy(title, line, i);
983 title[i++]=0;
984 line+=i;
986 /* get the command or shortcut keyword */
987 while (isspace(*line) && (*line!=0)) line++;
988 if (*line==0)
989 return;
990 i=0;
991 while (!isspace(line[i]) && (line[i]!=0)) i++;
992 strncpy(command, line, i);
993 command[i++]=0;
994 line+=i;
996 if (strcmp(command, "SHORTCUT")==0) {
997 /* get the shortcut key */
998 while (isspace(*line) && (*line!=0)) line++;
999 if (*line=='"') {
1000 line++;
1001 i=0;
1002 while (line[i]!='"' && (line[i]!=0)) i++;
1003 if (line[i]!='"')
1004 return;
1005 } else {
1006 i=0;
1007 while (!isspace(line[i]) && (line[i]!=0)) i++;
1009 strncpy(shortcut, line, i);
1010 shortcut[i++]=0;
1011 line+=i;
1013 *command=0;
1015 /* get the command */
1016 while (isspace(*line) && (*line!=0)) line++;
1017 if (*line==0)
1018 return;
1019 i=0;
1020 while (!isspace(line[i]) && (line[i]!=0)) i++;
1021 strncpy(command, line, i);
1022 command[i++]=0;
1023 line+=i;
1026 /* get the parameters */
1027 while (isspace(*line) && (*line!=0)) line++;
1028 if (*line==0)
1029 return;
1031 if (*line=='"') {
1032 line++;
1033 l = 0;
1034 while (line[l]!=0 && line[l]!='"') {
1035 parameter[l] = line[l];
1036 l++;
1038 parameter[l] = 0;
1039 return;
1042 l = strlen(line);
1043 while (isspace(line[l]) && (l>0)) l--;
1044 strncpy(parameter, line, l);
1045 parameter[l]=0;
1049 static WMenu*
1050 parseCascade(WScreen *scr, WMenu *menu, FILE *file, char *file_name)
1052 char linebuf[MAXLINE];
1053 char elinebuf[MAXLINE];
1054 char title[MAXLINE];
1055 char command[MAXLINE];
1056 char shortcut[MAXLINE];
1057 char params[MAXLINE];
1058 char *line;
1060 while (!IsEof(file)) {
1061 int lsize, ok;
1063 ok = 0;
1064 fgets(linebuf, MAXLINE, file);
1065 line = cropline(linebuf);
1066 lsize = strlen(line);
1067 do {
1068 if (line[lsize-1]=='\\') {
1069 char *line2;
1070 int lsize2;
1071 fgets(elinebuf, MAXLINE, file);
1072 line2=cropline(elinebuf);
1073 lsize2=strlen(line2);
1074 if (lsize2+lsize>MAXLINE) {
1075 wwarning(_("%s:maximal line size exceeded in menu config: %s"),
1076 file_name, line);
1077 ok=2;
1078 } else {
1079 line[lsize-1]=0;
1080 lsize+=lsize2-1;
1081 strcat(line, line2);
1083 } else {
1084 ok=1;
1086 } while (!ok && !IsEof(file));
1087 if (ok==2)
1088 continue;
1090 if (line[0]==0 || line[0]=='#' || (line[0]=='/' && line[1]=='/'))
1091 continue;
1094 separateline(line, title, command, params, shortcut);
1096 if (!command[0]) {
1097 wwarning(_("%s:missing command in menu config: %s"), file_name,
1098 line);
1099 goto error;
1102 if (strcasecmp(command, "MENU")==0) {
1103 WMenu *cascade;
1105 /* start submenu */
1107 cascade = wMenuCreate(scr, title, False);
1108 cascade->on_destroy = removeShortcutsForMenu;
1109 if (parseCascade(scr, cascade, file, file_name)==NULL) {
1110 wMenuDestroy(cascade, True);
1111 } else {
1112 wMenuEntrySetCascade(menu,
1113 wMenuAddCallback(menu, title, NULL, NULL),
1114 cascade);
1116 } else if (strcasecmp(command, "END")==0) {
1117 /* end of menu */
1118 return menu;
1120 } else {
1121 /* normal items */
1122 addMenuEntry(menu, title, shortcut[0] ? shortcut : NULL, command,
1123 params[0] ? params : NULL, file_name);
1127 wwarning(_("%s:syntax error in menu file:END declaration missing"),
1128 file_name);
1129 return menu;
1131 error:
1132 return menu;
1136 static WMenu*
1137 readMenuFile(WScreen *scr, char *file_name)
1139 WMenu *menu=NULL;
1140 FILE *file = NULL;
1141 char linebuf[MAXLINE];
1142 char title[MAXLINE];
1143 char shortcut[MAXLINE];
1144 char command[MAXLINE];
1145 char params[MAXLINE];
1146 char *line;
1147 #ifdef USECPP
1148 char *args;
1149 int cpp = 0;
1150 #endif
1152 #ifdef USECPP
1153 if (!wPreferences.flags.nocpp) {
1154 args = MakeCPPArgs(file_name);
1155 if (!args) {
1156 wwarning(_("could not make arguments for menu file preprocessor"));
1157 } else {
1158 snprintf(command, sizeof(command), "%s %s %s",
1159 CPP_PATH, args, file_name);
1160 wfree(args);
1161 file = popen(command, "r");
1162 if (!file) {
1163 wsyserror(_("%s:could not open/preprocess menu file"),
1164 file_name);
1165 } else {
1166 cpp = 1;
1170 #endif /* USECPP */
1172 if (!file) {
1173 file = fopen(file_name, "r");
1174 if (!file) {
1175 wsyserror(_("%s:could not open menu file"), file_name);
1176 return NULL;
1180 while (!IsEof(file)) {
1181 if (!fgets(linebuf, MAXLINE, file))
1182 break;
1183 line = cropline(linebuf);
1184 if (line[0]==0 || line[0]=='#' || (line[0]=='/' && line[1]=='/'))
1185 continue;
1187 separateline(line, title, command, params, shortcut);
1189 if (!command[0]) {
1190 wwarning(_("%s:missing command in menu config: %s"), file_name,
1191 line);
1192 break;
1194 if (strcasecmp(command, "MENU")==0) {
1195 menu = wMenuCreate(scr, title, True);
1196 menu->on_destroy = removeShortcutsForMenu;
1197 if (!parseCascade(scr, menu, file, file_name)) {
1198 wMenuDestroy(menu, True);
1200 break;
1201 } else {
1202 wwarning(_("%s:invalid menu file. MENU command is missing"),
1203 file_name);
1204 break;
1208 #ifdef CPP
1209 if (cpp) {
1210 if (pclose(file)==-1) {
1211 wsyserror(_("error reading preprocessed menu data"));
1213 } else {
1214 fclose(file);
1216 #else
1217 fclose(file);
1218 #endif
1220 return menu;
1223 /************ Menu Configuration From Pipe *************/
1225 static WMenu*
1226 readMenuPipe(WScreen *scr, char **file_name)
1228 WMenu *menu=NULL;
1229 FILE *file = NULL;
1230 char linebuf[MAXLINE];
1231 char title[MAXLINE];
1232 char command[MAXLINE];
1233 char params[MAXLINE];
1234 char shortcut[MAXLINE];
1235 char *line;
1236 char *filename;
1237 char flat_file[MAXLINE];
1238 int i;
1239 #ifdef USECPP
1240 char *args;
1241 int cpp = 0;
1242 #endif
1244 flat_file[0] = '\0';
1246 for(i=0; file_name[i]!=NULL; i++) {
1247 strcat(flat_file, file_name[i]);
1248 strcat(flat_file, " ");
1250 filename = flat_file+1;
1252 #ifdef USECPP
1253 if (!wPreferences.flags.nocpp) {
1254 args = MakeCPPArgs(filename);
1255 if (!args) {
1256 wwarning(_("could not make arguments for menu file preprocessor"));
1257 } else {
1258 snprintf(command, sizeof(command), "%s | %s %s",
1259 filename, CPP_PATH, args);
1261 wfree(args);
1262 file = popen(command, "r");
1263 if (!file) {
1264 wsyserror(_("%s:could not open/preprocess menu file"), filename);
1265 } else {
1266 cpp = 1;
1271 #endif /* USECPP */
1273 if (!file) {
1274 file = popen(filename, "r");
1276 if (!file) {
1277 wsyserror(_("%s:could not open menu file"), filename);
1278 return NULL;
1282 while (!IsEof(file)) {
1283 if (!fgets(linebuf, MAXLINE, file))
1284 break;
1285 line = cropline(linebuf);
1286 if (line[0]==0 || line[0]=='#' || (line[0]=='/' && line[1]=='/'))
1287 continue;
1289 separateline(line, title, command, params, shortcut);
1291 if (!command[0]) {
1292 wwarning(_("%s:missing command in menu config: %s"), file_name,
1293 line);
1294 break;
1296 if (strcasecmp(command, "MENU")==0) {
1297 menu = wMenuCreate(scr, title, True);
1298 menu->on_destroy = removeShortcutsForMenu;
1299 if (!parseCascade(scr, menu, file, filename)) {
1300 wMenuDestroy(menu, True);
1302 break;
1303 } else {
1304 wwarning(_("%s:no title given for the root menu"), filename);
1305 break;
1309 pclose(file);
1311 return menu;
1316 typedef struct {
1317 char *name;
1318 int index;
1319 } dir_data;
1322 static int
1323 myCompare(const void *d1, const void *d2)
1325 dir_data *p1 = *(dir_data**)d1;
1326 dir_data *p2 = *(dir_data**)d2;
1328 return strcmp(p1->name, p2->name);
1332 /************ Menu Configuration From Directory *************/
1334 static Bool
1335 isFilePackage(char *file)
1337 int l;
1339 /* check if the extension indicates this file is a
1340 * file package. For now, only recognize .themed */
1342 l = strlen(file);
1344 if (l > 7 && strcmp(&(file[l-7]), ".themed")==0) {
1345 return True;
1346 } else {
1347 return False;
1352 static WMenu*
1353 readMenuDirectory(WScreen *scr, char *title, char **path, char *command)
1355 DIR *dir;
1356 struct dirent *dentry;
1357 struct stat stat_buf;
1358 WMenu *menu=NULL;
1359 char *buffer;
1360 WMArray *dirs = NULL, *files = NULL;
1361 WMArrayIterator iter;
1362 int length, i, have_space=0;
1363 dir_data *data;
1364 int stripExtension = 0;
1367 dirs = WMCreateArray(16);
1368 files = WMCreateArray(16);
1370 i=0;
1371 while (path[i]!=NULL) {
1372 if (strcmp(path[i], "-noext")==0) {
1373 stripExtension = 1;
1374 i++;
1375 continue;
1378 dir = opendir(path[i]);
1379 if (!dir) {
1380 i++;
1381 continue;
1384 while ((dentry = readdir(dir))) {
1386 if (strcmp(dentry->d_name, ".")==0 ||
1387 strcmp(dentry->d_name, "..")==0)
1388 continue;
1390 if (dentry->d_name[0] == '.')
1391 continue;
1393 buffer = malloc(strlen(path[i])+strlen(dentry->d_name)+4);
1394 if (!buffer) {
1395 wsyserror(_("out of memory while constructing directory menu %s"),
1396 path[i]);
1397 break;
1400 strcpy(buffer, path[i]);
1401 strcat(buffer, "/");
1402 strcat(buffer, dentry->d_name);
1404 if (stat(buffer, &stat_buf)!=0) {
1405 wsyserror(_("%s:could not stat file \"%s\" in menu directory"),
1406 path[i], dentry->d_name);
1407 } else {
1408 Bool isFilePack = False;
1410 data = NULL;
1411 if (S_ISDIR(stat_buf.st_mode)
1412 && !(isFilePack = isFilePackage(dentry->d_name))) {
1414 /* access always returns success for user root */
1415 if (access(buffer, X_OK)==0) {
1416 /* Directory is accesible. Add to directory list */
1418 data = (dir_data*) wmalloc(sizeof(dir_data));
1419 data->name = wstrdup(dentry->d_name);
1420 data->index = i;
1422 WMAddToArray(dirs, data);
1424 } else if (S_ISREG(stat_buf.st_mode) || isFilePack) {
1425 /* Hack because access always returns X_OK success for user root */
1426 #define S_IXANY (S_IXUSR | S_IXGRP | S_IXOTH)
1427 if ((command!=NULL && access(buffer, R_OK)==0) ||
1428 (command==NULL && access(buffer, X_OK)==0 &&
1429 (stat_buf.st_mode & S_IXANY))) {
1431 data = (dir_data*) wmalloc(sizeof(dir_data));
1432 data->name = wstrdup(dentry->d_name);
1433 data->index = i;
1435 WMAddToArray(files, data);
1439 wfree(buffer);
1442 closedir(dir);
1443 i++;
1446 if (!WMGetArrayItemCount(dirs) && !WMGetArrayItemCount(files)) {
1447 WMFreeArray(dirs);
1448 WMFreeArray(files);
1449 return NULL;
1452 WMSortArray(dirs, myCompare);
1453 WMSortArray(files, myCompare);
1455 menu = wMenuCreate(scr, title, False);
1456 menu->on_destroy = removeShortcutsForMenu;
1458 WM_ITERATE_ARRAY(dirs, data, iter) {
1459 /* New directory. Use same OPEN_MENU command that was used
1460 * for the current directory. */
1461 length = strlen(path[data->index])+strlen(data->name)+6;
1462 if (stripExtension)
1463 length += 7;
1464 if (command)
1465 length += strlen(command) + 6;
1466 buffer = malloc(length);
1467 if (!buffer) {
1468 wsyserror(_("out of memory while constructing directory menu %s"),
1469 path[data->index]);
1470 break;
1473 buffer[0] = '\0';
1474 if (stripExtension)
1475 strcat(buffer, "-noext ");
1477 have_space = strchr(path[data->index], ' ')!=NULL ||
1478 strchr(data->name, ' ')!=NULL;
1480 if (have_space)
1481 strcat(buffer, "\"");
1482 strcat(buffer, path[data->index]);
1484 strcat(buffer, "/");
1485 strcat(buffer, data->name);
1486 if (have_space)
1487 strcat(buffer, "\"");
1488 if (command) {
1489 strcat(buffer, " WITH ");
1490 strcat(buffer, command);
1493 addMenuEntry(menu, data->name, NULL, "OPEN_MENU", buffer, path[data->index]);
1495 wfree(buffer);
1496 if (data->name)
1497 wfree(data->name);
1498 wfree(data);
1501 WM_ITERATE_ARRAY(files, data, iter) {
1502 /* executable: add as entry */
1503 length = strlen(path[data->index])+strlen(data->name)+6;
1504 if (command)
1505 length += strlen(command);
1507 buffer = malloc(length);
1508 if (!buffer) {
1509 wsyserror(_("out of memory while constructing directory menu %s"),
1510 path[data->index]);
1511 break;
1514 have_space = strchr(path[data->index], ' ')!=NULL ||
1515 strchr(data->name, ' ')!=NULL;
1516 if (command!=NULL) {
1517 strcpy(buffer, command);
1518 strcat(buffer, " ");
1519 if (have_space)
1520 strcat(buffer, "\"");
1521 strcat(buffer, path[data->index]);
1522 } else {
1523 if (have_space) {
1524 buffer[0] = '"';
1525 buffer[1] = 0;
1526 strcat(buffer, path[data->index]);
1527 } else {
1528 strcpy(buffer, path[data->index]);
1531 strcat(buffer, "/");
1532 strcat(buffer, data->name);
1533 if (have_space)
1534 strcat(buffer, "\"");
1536 if (stripExtension) {
1537 char *ptr = strrchr(data->name, '.');
1538 if (ptr && ptr!=data->name)
1539 *ptr = 0;
1541 addMenuEntry(menu, data->name, NULL, "SHEXEC", buffer, path[data->index]);
1543 wfree(buffer);
1544 if (data->name)
1545 wfree(data->name);
1546 wfree(data);
1549 WMFreeArray(files);
1550 WMFreeArray(dirs);
1552 return menu;
1556 /************ Menu Configuration From WMRootMenu *************/
1558 static WMenu*
1559 makeDefaultMenu(WScreen *scr)
1561 WMenu *menu=NULL;
1563 menu = wMenuCreate(scr, _("Commands"), True);
1564 wMenuAddCallback(menu, "XTerm", execCommand, "xterm");
1565 wMenuAddCallback(menu, "rxvt", execCommand, "rxvt");
1566 wMenuAddCallback(menu, _("Restart"), restartCommand, NULL);
1567 wMenuAddCallback(menu, _("Exit..."), exitCommand, NULL);
1568 return menu;
1576 *----------------------------------------------------------------------
1577 * configureMenu--
1578 * Reads root menu configuration from defaults database.
1580 *----------------------------------------------------------------------
1582 static WMenu*
1583 configureMenu(WScreen *scr, WMPropList *definition)
1585 WMenu *menu = NULL;
1586 WMPropList *elem;
1587 int i, count;
1588 WMPropList *title, *command, *params;
1589 char *tmp, *mtitle;
1592 if (WMIsPLString(definition)) {
1593 struct stat stat_buf;
1594 char *path = NULL;
1595 Bool menu_is_default = False;
1597 /* menu definition is a string. Probably a path, so parse the file */
1599 tmp = wexpandpath(WMGetFromPLString(definition));
1601 path = getLocalizedMenuFile(tmp);
1603 if (!path)
1604 path = wfindfile(DEF_CONFIG_PATHS, tmp);
1606 if (!path) {
1607 path = wfindfile(DEF_CONFIG_PATHS, DEF_MENU_FILE);
1608 menu_is_default = True;
1611 if (!path) {
1612 wsyserror(_("could not find menu file \"%s\" referenced in WMRootMenu"),
1613 tmp);
1614 wfree(tmp);
1615 return NULL;
1618 if (stat(path, &stat_buf)<0) {
1619 wsyserror(_("could not access menu \"%s\" referenced in WMRootMenu"), path);
1620 wfree(path);
1621 wfree(tmp);
1622 return NULL;
1625 if (!scr->root_menu || stat_buf.st_mtime > scr->root_menu->timestamp
1626 /* if the pointer in WMRootMenu has changed */
1627 || WDRootMenu->timestamp > scr->root_menu->timestamp) {
1629 if (menu_is_default) {
1630 wwarning(_("using default menu file \"%s\" as the menu referenced in WMRootMenu could not be found "),
1631 path);
1634 menu = readMenuFile(scr, path);
1635 if (menu)
1636 menu->timestamp = WMAX(stat_buf.st_mtime, WDRootMenu->timestamp);
1637 } else {
1638 menu = NULL;
1640 wfree(path);
1641 wfree(tmp);
1643 return menu;
1646 count = WMGetPropListItemCount(definition);
1647 if (count==0)
1648 return NULL;
1650 elem = WMGetFromPLArray(definition, 0);
1651 if (!WMIsPLString(elem)) {
1652 tmp = WMGetPropListDescription(elem, False);
1653 wwarning(_("%s:format error in root menu configuration \"%s\""),
1654 "WMRootMenu", tmp);
1655 wfree(tmp);
1656 return NULL;
1658 mtitle = WMGetFromPLString(elem);
1660 menu = wMenuCreate(scr, mtitle, False);
1661 menu->on_destroy = removeShortcutsForMenu;
1663 #ifdef GLOBAL_SUBMENU_FILE
1665 WMenu *submenu;
1666 WMenuEntry *mentry;
1668 submenu = readMenuFile(scr, GLOBAL_SUBMENU_FILE);
1670 if (submenu) {
1671 mentry = wMenuAddCallback(menu, submenu->frame->title, NULL, NULL);
1672 wMenuEntrySetCascade(menu, mentry, submenu);
1675 #endif
1677 for (i=1; i<count; i++) {
1678 elem = WMGetFromPLArray(definition, i);
1679 #if 0
1680 if (WMIsPLString(elem)) {
1681 char *file;
1683 file = WMGetFromPLString(elem);
1686 #endif
1687 if (!WMIsPLArray(elem) || WMGetPropListItemCount(elem) < 2)
1688 goto error;
1690 if (WMIsPLArray(WMGetFromPLArray(elem,1))) {
1691 WMenu *submenu;
1692 WMenuEntry *mentry;
1694 /* submenu */
1695 submenu = configureMenu(scr, elem);
1696 if (submenu) {
1697 mentry = wMenuAddCallback(menu, submenu->frame->title, NULL,
1698 NULL);
1699 wMenuEntrySetCascade(menu, mentry, submenu);
1701 } else {
1702 int idx = 0;
1703 WMPropList *shortcut;
1704 /* normal entry */
1706 title = WMGetFromPLArray(elem, idx++);
1707 shortcut = WMGetFromPLArray(elem, idx++);
1708 if (strcmp(WMGetFromPLString(shortcut), "SHORTCUT")==0) {
1709 shortcut = WMGetFromPLArray(elem, idx++);
1710 command = WMGetFromPLArray(elem, idx++);
1711 } else {
1712 command = shortcut;
1713 shortcut = NULL;
1715 params = WMGetFromPLArray(elem, idx++);
1717 if (!title || !command)
1718 goto error;
1720 addMenuEntry(menu, WMGetFromPLString(title),
1721 shortcut ? WMGetFromPLString(shortcut) : NULL,
1722 WMGetFromPLString(command),
1723 params ? WMGetFromPLString(params) : NULL, "WMRootMenu");
1725 continue;
1727 error:
1728 tmp = WMGetPropListDescription(elem, False);
1729 wwarning(_("%s:format error in root menu configuration \"%s\""),
1730 "WMRootMenu", tmp);
1731 wfree(tmp);
1734 return menu;
1745 *----------------------------------------------------------------------
1746 * OpenRootMenu--
1747 * Opens the root menu, parsing the menu configuration from the
1748 * defaults database.
1749 * If the menu is already mapped and is not sticked to the
1750 * root window, it will be unmapped.
1752 * Side effects:
1753 * The menu may be remade.
1755 * Notes:
1756 * Construction of OPEN_MENU entries are delayed to the moment the
1757 * user map's them.
1758 *----------------------------------------------------------------------
1760 void
1761 OpenRootMenu(WScreen *scr, int x, int y, int keyboard)
1763 WMenu *menu=NULL;
1764 WMPropList *definition;
1766 static WMPropList *domain=NULL;
1768 if (!domain) {
1769 domain = WMCreatePLString("WMRootMenu");
1773 scr->flags.root_menu_changed_shortcuts = 0;
1774 scr->flags.added_workspace_menu = 0;
1775 scr->flags.added_windows_menu = 0;
1777 if (scr->root_menu && scr->root_menu->flags.mapped) {
1778 menu = scr->root_menu;
1779 if (!menu->flags.buttoned) {
1780 wMenuUnmap(menu);
1781 } else {
1782 wRaiseFrame(menu->frame->core);
1784 if (keyboard)
1785 wMenuMapAt(menu, 0, 0, True);
1786 else
1787 wMenuMapCopyAt(menu, x-menu->frame->core->width/2, y);
1789 return;
1793 definition = WDRootMenu->dictionary;
1796 definition = PLGetDomain(domain);
1798 if (definition) {
1799 if (WMIsPLArray(definition)) {
1800 if (!scr->root_menu
1801 || WDRootMenu->timestamp > scr->root_menu->timestamp) {
1802 menu = configureMenu(scr, definition);
1803 if (menu)
1804 menu->timestamp = WDRootMenu->timestamp;
1806 } else
1807 menu = NULL;
1808 } else {
1809 menu = configureMenu(scr, definition);
1813 if (!menu) {
1814 /* menu hasn't changed or could not be read */
1815 if (!scr->root_menu) {
1816 wMessageDialog(scr, _("Error"),
1817 _("The applications menu could not be loaded. "
1818 "Look at the console output for a detailed "
1819 "description of the errors."),
1820 _("OK"), NULL, NULL);
1822 menu = makeDefaultMenu(scr);
1823 scr->root_menu = menu;
1825 menu = scr->root_menu;
1826 } else {
1827 /* new root menu */
1828 if (scr->root_menu) {
1829 wMenuDestroy(scr->root_menu, True);
1831 scr->root_menu = menu;
1833 if (menu) {
1834 int newx, newy;
1836 if (keyboard && x==0 && y==0) {
1837 newx = newy = 0;
1838 } else if (keyboard && x==scr->scr_width/2 && y==scr->scr_height/2) {
1839 newx = x - menu->frame->core->width/2;
1840 newy = y - menu->frame->core->height/2;
1841 } else {
1842 newx = x - menu->frame->core->width/2;
1843 newy = y;
1845 wMenuMapAt(menu, newx, newy, keyboard);
1848 if (scr->flags.root_menu_changed_shortcuts)
1849 rebindKeygrabs(scr);
1852 #endif /* !LITE */