- s/sprintf/snprintf
[wmaker-crm.git] / src / rootmenu.c
blob6ca770df41ec58275d327fd1e3edcf538421ba1f
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;
334 int len;
336 if (!Locale)
337 return NULL;
339 len = strlen(menu)+32;
340 buffer = wmalloc(len);
342 /* try menu.locale_name */
343 snprintf(buffer, len, "%s.%s", menu, Locale);
344 if (access(buffer, F_OK)==0) {
345 return buffer;
347 /* check if it is in the form aa_bb.encoding and check for aa_bb */
348 ptr = strchr(Locale, '.');
349 if (ptr) {
350 *ptr = 0;
351 if (access(buffer, F_OK)==0) {
352 return buffer;
355 /* now check for aa */
356 ptr = strchr(buffer, '_');
357 if (ptr) {
358 *ptr = 0;
359 if (access(buffer, F_OK)==0) {
360 return buffer;
364 return NULL;
368 static void
369 raiseMenus(WMenu *menu)
371 int i;
373 if (menu->flags.mapped) {
374 wRaiseFrame(menu->frame->core);
376 for (i=0; i<menu->cascade_no; i++) {
377 if (menu->cascades[i])
378 raiseMenus(menu->cascades[i]);
384 Bool
385 wRootMenuPerformShortcut(XEvent *event)
387 Shortcut *ptr;
388 int modifiers;
389 int done = 0;
391 /* ignore CapsLock */
392 modifiers = event->xkey.state & ValidModMask;
394 for (ptr = shortcutList; ptr!=NULL; ptr = ptr->next) {
395 if (ptr->keycode==0)
396 continue;
398 if (ptr->keycode==event->xkey.keycode && (ptr->modifier==modifiers)) {
399 (*ptr->entry->callback)(ptr->menu, ptr->entry);
400 done = True;
403 return done;
407 void
408 wRootMenuBindShortcuts(Window window)
410 Shortcut *ptr;
412 ptr = shortcutList;
413 while (ptr) {
414 if (ptr->modifier!=AnyModifier) {
415 XGrabKey(dpy, ptr->keycode, ptr->modifier|LockMask,
416 window, True, GrabModeAsync, GrabModeAsync);
417 #ifdef NUMLOCK_HACK
418 wHackedGrabKey(ptr->keycode, ptr->modifier,
419 window, True, GrabModeAsync, GrabModeAsync);
420 #endif
422 XGrabKey(dpy, ptr->keycode, ptr->modifier, window, True,
423 GrabModeAsync, GrabModeAsync);
424 ptr = ptr->next;
429 static void
430 rebindKeygrabs(WScreen *scr)
432 WWindow *wwin;
434 wwin = scr->focused_window;
436 while (wwin!=NULL) {
437 XUngrabKey(dpy, AnyKey, AnyModifier, wwin->frame->core->window);
439 if (!WFLAGP(wwin, no_bind_keys)) {
440 wWindowSetKeyGrabs(wwin);
442 wwin = wwin->prev;
447 static void
448 removeShortcutsForMenu(WMenu *menu)
450 Shortcut *ptr, *tmp;
451 Shortcut *newList = NULL;
453 ptr = shortcutList;
454 while (ptr!=NULL) {
455 tmp = ptr->next;
456 if (ptr->menu == menu) {
457 wfree(ptr);
458 } else {
459 ptr->next = newList;
460 newList = ptr;
462 ptr = tmp;
464 shortcutList = newList;
465 menu->menu->screen_ptr->flags.root_menu_changed_shortcuts = 1;
469 static Bool
470 addShortcut(char *file, char *shortcutDefinition, WMenu *menu,
471 WMenuEntry *entry)
473 Shortcut *ptr;
474 KeySym ksym;
475 char *k;
476 char buf[128], *b;
478 ptr = wmalloc(sizeof(Shortcut));
480 strcpy(buf, shortcutDefinition);
481 b = (char*)buf;
483 /* get modifiers */
484 ptr->modifier = 0;
485 while ((k = strchr(b, '+'))!=NULL) {
486 int mod;
488 *k = 0;
489 mod = wXModifierFromKey(b);
490 if (mod<0) {
491 wwarning(_("%s:invalid key modifier \"%s\""), file, b);
492 wfree(ptr);
493 return False;
495 ptr->modifier |= mod;
497 b = k+1;
500 /* get key */
501 ksym = XStringToKeysym(b);
503 if (ksym==NoSymbol) {
504 wwarning(_("%s:invalid kbd shortcut specification \"%s\" for entry %s"),
505 file, shortcutDefinition, entry->text);
506 wfree(ptr);
507 return False;
510 ptr->keycode = XKeysymToKeycode(dpy, ksym);
511 if (ptr->keycode==0) {
512 wwarning(_("%s:invalid key in shortcut \"%s\" for entry %s"), file,
513 shortcutDefinition, entry->text);
514 wfree(ptr);
515 return False;
518 ptr->menu = menu;
519 ptr->entry = entry;
521 ptr->next = shortcutList;
522 shortcutList = ptr;
524 menu->menu->screen_ptr->flags.root_menu_changed_shortcuts = 1;
526 return True;
530 /*******************************/
532 static char*
533 cropline(char *line)
535 char *end;
537 if (strlen(line)==0)
538 return line;
540 end = &(line[strlen(line)])-1;
541 while (isspace(*line) && *line!=0) line++;
542 while (end>line && isspace(*end)) {
543 *end=0;
544 end--;
546 return line;
550 static char*
551 next_token(char *line, char **next)
553 char *tmp, c;
554 char *ret;
556 *next = NULL;
557 while (*line==' ' || *line=='\t') line++;
559 tmp = line;
561 if (*tmp=='"') {
562 tmp++; line++;
563 while (*tmp!=0 && *tmp!='"') tmp++;
564 if (*tmp!='"') {
565 wwarning(_("%s: unmatched '\"' in menu file"), line);
566 return NULL;
568 } else {
569 do {
570 if (*tmp=='\\')
571 tmp++;
573 if (*tmp!=0)
574 tmp++;
576 } while (*tmp!=0 && *tmp!=' ' && *tmp!='\t');
579 c = *tmp;
580 *tmp = 0;
581 ret = wstrdup(line);
582 *tmp = c;
584 if (c==0)
585 return ret;
586 else
587 tmp++;
589 /* skip blanks */
590 while (*tmp==' ' || *tmp=='\t') tmp++;
592 if (*tmp!=0)
593 *next = tmp;
595 return ret;
599 static void
600 separateCommand(char *line, char ***file, char **command)
602 char *token, *tmp = line;
603 WMArray *array = WMCreateArray(4);
604 int count, i;
606 *file = NULL;
607 *command = NULL;
608 do {
609 token = next_token(tmp, &tmp);
610 if (token) {
611 if (strcmp(token, "WITH")==0) {
612 if (tmp!=NULL && *tmp!=0)
613 *command = wstrdup(tmp);
614 else
615 wwarning(_("%s: missing command"), line);
616 break;
618 WMAddToArray(array, token);
620 } while (token!=NULL && tmp!=NULL);
622 count = WMGetArrayItemCount(array);
623 if (count>0) {
624 *file = wmalloc(sizeof(char*)*(count+1));
625 (*file)[count] = NULL;
626 for (i = 0; i < count; i++) {
627 (*file)[i] = WMGetFromArray(array, i);
630 WMFreeArray(array);
634 static void
635 constructMenu(WMenu *menu, WMenuEntry *entry)
637 WMenu *submenu;
638 struct stat stat_buf;
639 char **path;
640 char *cmd;
641 char *lpath = NULL;
642 int i, first=-1;
643 time_t last=0;
645 separateCommand((char*)entry->clientdata, &path, &cmd);
646 if (path == NULL || *path==NULL || **path==0) {
647 wwarning(_("invalid OPEN_MENU specification: %s"),
648 (char*)entry->clientdata);
649 return;
652 if (path[0][0]=='|') {
653 /* pipe menu */
655 if (!menu->cascades[entry->cascade] ||
656 menu->cascades[entry->cascade]->timestamp == 0) {
657 /* parse pipe */
659 submenu = readMenuPipe(menu->frame->screen_ptr, path);
661 /* there's no automatic reloading */
662 if(submenu != NULL)
663 submenu->timestamp = 1;
664 } else {
665 submenu = NULL;
668 } else {
669 i=0;
670 while(path[i] != NULL) {
671 char *tmp;
673 if (strcmp(path[i], "-noext")==0) {
674 i++;
675 continue;
678 tmp = wexpandpath(path[i]);
679 wfree(path[i]);
680 lpath = getLocalizedMenuFile(tmp);
681 if (lpath) {
682 wfree(tmp);
683 path[i] = lpath;
684 lpath = NULL;
685 } else {
686 path[i] = tmp;
689 if (stat(path[i], &stat_buf)==0) {
690 if (last < stat_buf.st_mtime)
691 last = stat_buf.st_mtime;
692 if (first<0)
693 first=i;
694 } else {
695 wsyserror(_("%s:could not stat menu"), path[i]);
696 /*goto finish;*/
699 i++;
702 if (first < 0) {
703 wsyserror(_("%s:could not stat menu:%s"), "OPEN_MENU",
704 (char*)entry->clientdata);
705 goto finish;
707 stat(path[first], &stat_buf);
708 if (!menu->cascades[entry->cascade]
709 || menu->cascades[entry->cascade]->timestamp < last) {
711 if (S_ISDIR(stat_buf.st_mode)) {
712 /* menu directory */
713 submenu = readMenuDirectory(menu->frame->screen_ptr,
714 entry->text, path, cmd);
715 if (submenu)
716 submenu->timestamp = last;
717 } else if (S_ISREG(stat_buf.st_mode)) {
718 /* menu file */
720 if (cmd || path[1])
721 wwarning(_("too many parameters in OPEN_MENU: %s"),
722 (char*)entry->clientdata);
724 submenu = readMenuFile(menu->frame->screen_ptr, path[first]);
725 if (submenu)
726 submenu->timestamp = stat_buf.st_mtime;
727 } else {
728 submenu = NULL;
730 } else {
731 submenu = NULL;
735 if (submenu) {
736 wMenuEntryRemoveCascade(menu, entry);
737 wMenuEntrySetCascade(menu, entry, submenu);
740 finish:
741 i = 0;
742 while (path[i]!=NULL)
743 wfree(path[i++]);
744 wfree(path);
745 if (cmd)
746 wfree(cmd);
750 static void
751 cleanupWorkspaceMenu(WMenu *menu)
753 if (menu->frame->screen_ptr->workspace_menu == menu)
754 menu->frame->screen_ptr->workspace_menu = NULL;
758 static WMenuEntry*
759 addWorkspaceMenu(WScreen *scr, WMenu *menu, char *title)
761 WMenu *wsmenu;
762 WMenuEntry *entry;
764 if (scr->flags.added_workspace_menu) {
765 wwarning(_("There are more than one WORKSPACE_MENU commands in the applications menu. Only one is allowed."));
766 return NULL;
767 } else {
768 scr->flags.added_workspace_menu = 1;
770 wsmenu = wWorkspaceMenuMake(scr, True);
771 wsmenu->on_destroy = cleanupWorkspaceMenu;
773 scr->workspace_menu = wsmenu;
774 entry = wMenuAddCallback(menu, title, NULL, NULL);
775 wMenuEntrySetCascade(menu, entry, wsmenu);
777 wWorkspaceMenuUpdate(scr, wsmenu);
779 return entry;
783 static void
784 cleanupWindowsMenu(WMenu *menu)
786 if (menu->frame->screen_ptr->switch_menu == menu)
787 menu->frame->screen_ptr->switch_menu = NULL;
791 static WMenuEntry*
792 addWindowsMenu(WScreen *scr, WMenu *menu, char *title)
794 WMenu *wwmenu;
795 WWindow *wwin;
796 WMenuEntry *entry;
798 if (scr->flags.added_windows_menu) {
799 wwarning(_("There are more than one WINDOWS_MENU commands in the applications menu. Only one is allowed."));
800 return NULL;
801 } else {
802 scr->flags.added_windows_menu = 1;
804 wwmenu = wMenuCreate(scr, _("Window List"), False);
805 wwmenu->on_destroy = cleanupWindowsMenu;
806 scr->switch_menu = wwmenu;
807 wwin = scr->focused_window;
808 while (wwin) {
809 UpdateSwitchMenu(scr, wwin, ACTION_ADD);
811 wwin = wwin->prev;
813 entry = wMenuAddCallback(menu, title, NULL, NULL);
814 wMenuEntrySetCascade(menu, entry, wwmenu);
816 return entry;
820 static WMenuEntry*
821 addMenuEntry(WMenu *menu, char *title, char *shortcut, char *command,
822 char *params, char *file_name)
824 WScreen *scr;
825 WMenuEntry *entry = NULL;
826 Bool shortcutOk = False;
828 if (!menu)
829 return NULL;
830 scr = menu->frame->screen_ptr;
831 if (strcmp(command, "OPEN_MENU")==0) {
832 if (!params) {
833 wwarning(_("%s:missing parameter for menu command \"%s\""),
834 file_name, command);
835 } else {
836 WMenu *dummy;
837 char *path;
839 path = wfindfile(DEF_CONFIG_PATHS, params);
840 if (!path) {
841 path = wstrdup(params);
843 dummy = wMenuCreate(scr, title, False);
844 dummy->on_destroy = removeShortcutsForMenu;
845 entry = wMenuAddCallback(menu, title, constructMenu, path);
846 entry->free_cdata = free;
847 wMenuEntrySetCascade(menu, entry, dummy);
849 } else if (strcmp(command, "EXEC")==0) {
850 if (!params)
851 wwarning(_("%s:missing parameter for menu command \"%s\""),
852 file_name, command);
853 else {
854 entry = wMenuAddCallback(menu, title, execCommand,
855 wstrconcat("exec ", params));
856 entry->free_cdata = free;
857 shortcutOk = True;
859 } else if (strcmp(command, "SHEXEC")==0) {
860 if (!params)
861 wwarning(_("%s:missing parameter for menu command \"%s\""),
862 file_name, command);
863 else {
864 entry = wMenuAddCallback(menu, title, execCommand,
865 wstrdup(params));
866 entry->free_cdata = free;
867 shortcutOk = True;
869 } else if (strcmp(command, "EXIT")==0) {
871 if (params && strcmp(params, "QUICK")==0)
872 entry = wMenuAddCallback(menu, title, exitCommand, (void*)M_QUICK);
873 else
874 entry = wMenuAddCallback(menu, title, exitCommand, NULL);
876 shortcutOk = True;
877 } else if (strcmp(command, "SHUTDOWN")==0) {
879 if (params && strcmp(params, "QUICK")==0)
880 entry = wMenuAddCallback(menu, title, shutdownCommand,
881 (void*)M_QUICK);
882 else
883 entry = wMenuAddCallback(menu, title, shutdownCommand, NULL);
885 shortcutOk = True;
886 } else if (strcmp(command, "REFRESH")==0) {
887 entry = wMenuAddCallback(menu, title, refreshCommand, NULL);
889 shortcutOk = True;
890 } else if (strcmp(command, "WORKSPACE_MENU")==0) {
891 entry = addWorkspaceMenu(scr, menu, title);
893 shortcutOk = True;
894 } else if (strcmp(command, "WINDOWS_MENU")==0) {
895 entry = addWindowsMenu(scr, menu, title);
897 shortcutOk = True;
898 } else if (strcmp(command, "ARRANGE_ICONS")==0) {
899 entry = wMenuAddCallback(menu, title, arrangeIconsCommand, NULL);
901 shortcutOk = True;
902 } else if (strcmp(command, "HIDE_OTHERS")==0) {
903 entry = wMenuAddCallback(menu, title, hideOthersCommand, NULL);
905 shortcutOk = True;
906 } else if (strcmp(command, "SHOW_ALL")==0) {
907 entry = wMenuAddCallback(menu, title, showAllCommand, NULL);
909 shortcutOk = True;
910 } else if (strcmp(command, "RESTART")==0) {
911 entry = wMenuAddCallback(menu, title, restartCommand,
912 params ? wstrdup(params) : NULL);
913 entry->free_cdata = free;
914 shortcutOk = True;
915 } else if (strcmp(command, "SAVE_SESSION")==0) {
916 entry = wMenuAddCallback(menu, title, saveSessionCommand, NULL);
918 shortcutOk = True;
919 } else if (strcmp(command, "CLEAR_SESSION")==0) {
920 entry = wMenuAddCallback(menu, title, clearSessionCommand, NULL);
921 shortcutOk = True;
922 } else if (strcmp(command, "INFO_PANEL")==0) {
923 entry = wMenuAddCallback(menu, title, infoPanelCommand, NULL);
924 shortcutOk = True;
925 } else if (strcmp(command, "LEGAL_PANEL")==0) {
926 entry = wMenuAddCallback(menu, title, legalPanelCommand, NULL);
927 shortcutOk = True;
928 } else {
929 wwarning(_("%s:unknown command \"%s\" in menu config."), file_name,
930 command);
932 return NULL;
935 if (shortcut && entry) {
936 if (!shortcutOk) {
937 wwarning(_("%s:can't add shortcut for entry \"%s\""), file_name,
938 title);
939 } else {
940 if (addShortcut(file_name, shortcut, menu, entry)) {
942 entry->rtext = GetShortcutString(shortcut);
944 entry->rtext = wstrdup(shortcut);
950 return entry;
955 /******************* Menu Configuration From File *******************/
957 static void
958 separateline(char *line, char *title, char *command, char *parameter,
959 char *shortcut)
961 int l, i;
963 l = strlen(line);
965 *title = 0;
966 *command = 0;
967 *parameter = 0;
968 *shortcut = 0;
969 /* get the title */
970 while (isspace(*line) && (*line!=0)) line++;
971 if (*line=='"') {
972 line++;
973 i=0;
974 while (line[i]!='"' && (line[i]!=0)) i++;
975 if (line[i]!='"')
976 return;
977 } else {
978 i=0;
979 while (!isspace(line[i]) && (line[i]!=0)) i++;
981 strncpy(title, line, i);
982 title[i++]=0;
983 line+=i;
985 /* get the command or shortcut keyword */
986 while (isspace(*line) && (*line!=0)) line++;
987 if (*line==0)
988 return;
989 i=0;
990 while (!isspace(line[i]) && (line[i]!=0)) i++;
991 strncpy(command, line, i);
992 command[i++]=0;
993 line+=i;
995 if (strcmp(command, "SHORTCUT")==0) {
996 /* get the shortcut key */
997 while (isspace(*line) && (*line!=0)) line++;
998 if (*line=='"') {
999 line++;
1000 i=0;
1001 while (line[i]!='"' && (line[i]!=0)) i++;
1002 if (line[i]!='"')
1003 return;
1004 } else {
1005 i=0;
1006 while (!isspace(line[i]) && (line[i]!=0)) i++;
1008 strncpy(shortcut, line, i);
1009 shortcut[i++]=0;
1010 line+=i;
1012 *command=0;
1014 /* get the command */
1015 while (isspace(*line) && (*line!=0)) line++;
1016 if (*line==0)
1017 return;
1018 i=0;
1019 while (!isspace(line[i]) && (line[i]!=0)) i++;
1020 strncpy(command, line, i);
1021 command[i++]=0;
1022 line+=i;
1025 /* get the parameters */
1026 while (isspace(*line) && (*line!=0)) line++;
1027 if (*line==0)
1028 return;
1030 if (*line=='"') {
1031 line++;
1032 l = 0;
1033 while (line[l]!=0 && line[l]!='"') {
1034 parameter[l] = line[l];
1035 l++;
1037 parameter[l] = 0;
1038 return;
1041 l = strlen(line);
1042 while (isspace(line[l]) && (l>0)) l--;
1043 strncpy(parameter, line, l);
1044 parameter[l]=0;
1048 static WMenu*
1049 parseCascade(WScreen *scr, WMenu *menu, FILE *file, char *file_name)
1051 char linebuf[MAXLINE];
1052 char elinebuf[MAXLINE];
1053 char title[MAXLINE];
1054 char command[MAXLINE];
1055 char shortcut[MAXLINE];
1056 char params[MAXLINE];
1057 char *line;
1059 while (!IsEof(file)) {
1060 int lsize, ok;
1062 ok = 0;
1063 fgets(linebuf, MAXLINE, file);
1064 line = cropline(linebuf);
1065 lsize = strlen(line);
1066 do {
1067 if (line[lsize-1]=='\\') {
1068 char *line2;
1069 int lsize2;
1070 fgets(elinebuf, MAXLINE, file);
1071 line2=cropline(elinebuf);
1072 lsize2=strlen(line2);
1073 if (lsize2+lsize>MAXLINE) {
1074 wwarning(_("%s:maximal line size exceeded in menu config: %s"),
1075 file_name, line);
1076 ok=2;
1077 } else {
1078 line[lsize-1]=0;
1079 lsize+=lsize2-1;
1080 strcat(line, line2);
1082 } else {
1083 ok=1;
1085 } while (!ok && !IsEof(file));
1086 if (ok==2)
1087 continue;
1089 if (line[0]==0 || line[0]=='#' || (line[0]=='/' && line[1]=='/'))
1090 continue;
1093 separateline(line, title, command, params, shortcut);
1095 if (!command[0]) {
1096 wwarning(_("%s:missing command in menu config: %s"), file_name,
1097 line);
1098 goto error;
1101 if (strcasecmp(command, "MENU")==0) {
1102 WMenu *cascade;
1104 /* start submenu */
1106 cascade = wMenuCreate(scr, title, False);
1107 cascade->on_destroy = removeShortcutsForMenu;
1108 if (parseCascade(scr, cascade, file, file_name)==NULL) {
1109 wMenuDestroy(cascade, True);
1110 } else {
1111 wMenuEntrySetCascade(menu,
1112 wMenuAddCallback(menu, title, NULL, NULL),
1113 cascade);
1115 } else if (strcasecmp(command, "END")==0) {
1116 /* end of menu */
1117 return menu;
1119 } else {
1120 /* normal items */
1121 addMenuEntry(menu, title, shortcut[0] ? shortcut : NULL, command,
1122 params[0] ? params : NULL, file_name);
1126 wwarning(_("%s:syntax error in menu file:END declaration missing"),
1127 file_name);
1128 return menu;
1130 error:
1131 return menu;
1135 static WMenu*
1136 readMenuFile(WScreen *scr, char *file_name)
1138 WMenu *menu=NULL;
1139 FILE *file = NULL;
1140 char linebuf[MAXLINE];
1141 char title[MAXLINE];
1142 char shortcut[MAXLINE];
1143 char command[MAXLINE];
1144 char params[MAXLINE];
1145 char *line;
1146 #ifdef USECPP
1147 char *args;
1148 int cpp = 0;
1149 #endif
1151 #ifdef USECPP
1152 if (!wPreferences.flags.nocpp) {
1153 args = MakeCPPArgs(file_name);
1154 if (!args) {
1155 wwarning(_("could not make arguments for menu file preprocessor"));
1156 } else {
1157 snprintf(command, sizeof(command), "%s %s %s",
1158 CPP_PATH, args, file_name);
1159 wfree(args);
1160 file = popen(command, "r");
1161 if (!file) {
1162 wsyserror(_("%s:could not open/preprocess menu file"),
1163 file_name);
1164 } else {
1165 cpp = 1;
1169 #endif /* USECPP */
1171 if (!file) {
1172 file = fopen(file_name, "r");
1173 if (!file) {
1174 wsyserror(_("%s:could not open menu file"), file_name);
1175 return NULL;
1179 while (!IsEof(file)) {
1180 if (!fgets(linebuf, MAXLINE, file))
1181 break;
1182 line = cropline(linebuf);
1183 if (line[0]==0 || line[0]=='#' || (line[0]=='/' && line[1]=='/'))
1184 continue;
1186 separateline(line, title, command, params, shortcut);
1188 if (!command[0]) {
1189 wwarning(_("%s:missing command in menu config: %s"), file_name,
1190 line);
1191 break;
1193 if (strcasecmp(command, "MENU")==0) {
1194 menu = wMenuCreate(scr, title, True);
1195 menu->on_destroy = removeShortcutsForMenu;
1196 if (!parseCascade(scr, menu, file, file_name)) {
1197 wMenuDestroy(menu, True);
1199 break;
1200 } else {
1201 wwarning(_("%s:invalid menu file. MENU command is missing"),
1202 file_name);
1203 break;
1207 #ifdef CPP
1208 if (cpp) {
1209 if (pclose(file)==-1) {
1210 wsyserror(_("error reading preprocessed menu data"));
1212 } else {
1213 fclose(file);
1215 #else
1216 fclose(file);
1217 #endif
1219 return menu;
1222 /************ Menu Configuration From Pipe *************/
1224 static WMenu*
1225 readMenuPipe(WScreen *scr, char **file_name)
1227 WMenu *menu=NULL;
1228 FILE *file = NULL;
1229 char linebuf[MAXLINE];
1230 char title[MAXLINE];
1231 char command[MAXLINE];
1232 char params[MAXLINE];
1233 char shortcut[MAXLINE];
1234 char *line;
1235 char * filename;
1236 char flat_file[MAXLINE];
1237 int i;
1238 #ifdef USECPP
1239 char *args;
1240 int cpp = 0;
1241 #endif
1243 flat_file[0] = '\0';
1245 for(i = 0 ; file_name[i] != NULL ; i++) {
1246 strcat(flat_file, file_name[i]);
1247 strcat(flat_file, " ");
1249 filename = flat_file+1;
1251 #ifdef USECPP
1252 if (!wPreferences.flags.nocpp) {
1253 args = MakeCPPArgs(filename);
1254 if (!args) {
1255 wwarning(_("could not make arguments for menu file preprocessor"));
1256 } else {
1257 snprintf(command, sizeof(command), "%s | %s %s",
1258 filename, CPP_PATH, args);
1260 wfree(args);
1261 file = popen(command, "r");
1262 if (!file) {
1263 wsyserror(_("%s:could not open/preprocess menu file"), filename);
1264 } else {
1265 cpp = 1;
1270 #endif /* USECPP */
1272 if (!file) {
1273 file = popen(filename, "r");
1275 if (!file) {
1276 wsyserror(_("%s:could not open menu file"), filename);
1277 return NULL;
1281 while (!IsEof(file)) {
1282 if (!fgets(linebuf, MAXLINE, file))
1283 break;
1284 line = cropline(linebuf);
1285 if (line[0]==0 || line[0]=='#' || (line[0]=='/' && line[1]=='/'))
1286 continue;
1288 separateline(line, title, command, params, shortcut);
1290 if (!command[0]) {
1291 wwarning(_("%s:missing command in menu config: %s"), file_name,
1292 line);
1293 break;
1295 if (strcasecmp(command, "MENU")==0) {
1296 menu = wMenuCreate(scr, title, True);
1297 menu->on_destroy = removeShortcutsForMenu;
1298 if (!parseCascade(scr, menu, file, filename)) {
1299 wMenuDestroy(menu, True);
1301 break;
1302 } else {
1303 wwarning(_("%s:no title given for the root menu"), filename);
1304 break;
1308 pclose(file);
1310 return menu;
1315 typedef struct {
1316 char *name;
1317 int index;
1318 } dir_data;
1321 static int
1322 myCompare(const void *d1, const void *d2)
1324 dir_data *p1 = *(dir_data**)d1;
1325 dir_data *p2 = *(dir_data**)d2;
1327 return strcmp(p1->name, p2->name);
1331 /************ Menu Configuration From Directory *************/
1333 static Bool
1334 isFilePackage(char *file)
1336 int l;
1338 /* check if the extension indicates this file is a
1339 * file package. For now, only recognize .themed */
1341 l = strlen(file);
1343 if (l > 7 && strcmp(&(file[l-7]), ".themed")==0) {
1344 return True;
1345 } else {
1346 return False;
1351 static WMenu*
1352 readMenuDirectory(WScreen *scr, char *title, char **path, char *command)
1354 DIR *dir;
1355 struct dirent *dentry;
1356 struct stat stat_buf;
1357 WMenu *menu=NULL;
1358 char *buffer;
1359 WMArray *dirs = NULL, *files = NULL;
1360 WMArrayIterator iter;
1361 int length, i, have_space=0;
1362 dir_data *data;
1363 int stripExtension = 0;
1366 dirs = WMCreateArray(16);
1367 files = WMCreateArray(16);
1369 i=0;
1370 while (path[i]!=NULL) {
1371 if (strcmp(path[i], "-noext")==0) {
1372 stripExtension = 1;
1373 i++;
1374 continue;
1377 dir = opendir(path[i]);
1378 if (!dir) {
1379 i++;
1380 continue;
1383 while ((dentry = readdir(dir))) {
1385 if (strcmp(dentry->d_name, ".")==0 ||
1386 strcmp(dentry->d_name, "..")==0)
1387 continue;
1389 if (dentry->d_name[0] == '.')
1390 continue;
1392 buffer = malloc(strlen(path[i])+strlen(dentry->d_name)+4);
1393 if (!buffer) {
1394 wsyserror(_("out of memory while constructing directory menu %s"),
1395 path[i]);
1396 break;
1399 strcpy(buffer, path[i]);
1400 strcat(buffer, "/");
1401 strcat(buffer, dentry->d_name);
1403 if (stat(buffer, &stat_buf)!=0) {
1404 wsyserror(_("%s:could not stat file \"%s\" in menu directory"),
1405 path[i], dentry->d_name);
1406 } else {
1407 Bool isFilePack = False;
1409 data = NULL;
1410 if (S_ISDIR(stat_buf.st_mode)
1411 && !(isFilePack = isFilePackage(dentry->d_name))) {
1413 /* access always returns success for user root */
1414 if (access(buffer, X_OK)==0) {
1415 /* Directory is accesible. Add to directory list */
1417 data = (dir_data*) wmalloc(sizeof(dir_data));
1418 data->name = wstrdup(dentry->d_name);
1419 data->index = i;
1421 WMAddToArray(dirs, data);
1423 } else if (S_ISREG(stat_buf.st_mode) || isFilePack) {
1424 /* Hack because access always returns X_OK success for user root */
1425 #define S_IXANY (S_IXUSR | S_IXGRP | S_IXOTH)
1426 if ((command!=NULL && access(buffer, R_OK)==0) ||
1427 (command==NULL && access(buffer, X_OK)==0 &&
1428 (stat_buf.st_mode & S_IXANY))) {
1430 data = (dir_data*) wmalloc(sizeof(dir_data));
1431 data->name = wstrdup(dentry->d_name);
1432 data->index = i;
1434 WMAddToArray(files, data);
1438 wfree(buffer);
1441 closedir(dir);
1442 i++;
1445 if (!WMGetArrayItemCount(dirs) && !WMGetArrayItemCount(files)) {
1446 WMFreeArray(dirs);
1447 WMFreeArray(files);
1448 return NULL;
1451 WMSortArray(dirs, myCompare);
1452 WMSortArray(files, myCompare);
1454 menu = wMenuCreate(scr, title, False);
1455 menu->on_destroy = removeShortcutsForMenu;
1457 WM_ITERATE_ARRAY(dirs, data, iter) {
1458 /* New directory. Use same OPEN_MENU command that was used
1459 * for the current directory. */
1460 length = strlen(path[data->index])+strlen(data->name)+6;
1461 if (stripExtension)
1462 length += 7;
1463 if (command)
1464 length += strlen(command) + 6;
1465 buffer = malloc(length);
1466 if (!buffer) {
1467 wsyserror(_("out of memory while constructing directory menu %s"),
1468 path[data->index]);
1469 break;
1472 buffer[0] = '\0';
1473 if (stripExtension)
1474 strcat(buffer, "-noext ");
1476 have_space = strchr(path[data->index], ' ')!=NULL ||
1477 strchr(data->name, ' ')!=NULL;
1479 if (have_space)
1480 strcat(buffer, "\"");
1481 strcat(buffer, path[data->index]);
1483 strcat(buffer, "/");
1484 strcat(buffer, data->name);
1485 if (have_space)
1486 strcat(buffer, "\"");
1487 if (command) {
1488 strcat(buffer, " WITH ");
1489 strcat(buffer, command);
1492 addMenuEntry(menu, data->name, NULL, "OPEN_MENU", buffer, path[data->index]);
1494 wfree(buffer);
1495 if (data->name)
1496 wfree(data->name);
1497 wfree(data);
1500 WM_ITERATE_ARRAY(files, data, iter) {
1501 /* executable: add as entry */
1502 length = strlen(path[data->index])+strlen(data->name)+6;
1503 if (command)
1504 length += strlen(command);
1506 buffer = malloc(length);
1507 if (!buffer) {
1508 wsyserror(_("out of memory while constructing directory menu %s"),
1509 path[data->index]);
1510 break;
1513 have_space = strchr(path[data->index], ' ')!=NULL ||
1514 strchr(data->name, ' ')!=NULL;
1515 if (command!=NULL) {
1516 strcpy(buffer, command);
1517 strcat(buffer, " ");
1518 if (have_space)
1519 strcat(buffer, "\"");
1520 strcat(buffer, path[data->index]);
1521 } else {
1522 if (have_space) {
1523 buffer[0] = '"';
1524 buffer[1] = 0;
1525 strcat(buffer, path[data->index]);
1526 } else {
1527 strcpy(buffer, path[data->index]);
1530 strcat(buffer, "/");
1531 strcat(buffer, data->name);
1532 if (have_space)
1533 strcat(buffer, "\"");
1535 if (stripExtension) {
1536 char *ptr = strrchr(data->name, '.');
1537 if (ptr && ptr!=data->name)
1538 *ptr = 0;
1540 addMenuEntry(menu, data->name, NULL, "SHEXEC", buffer, path[data->index]);
1542 wfree(buffer);
1543 if (data->name)
1544 wfree(data->name);
1545 wfree(data);
1548 WMFreeArray(files);
1549 WMFreeArray(dirs);
1551 return menu;
1555 /************ Menu Configuration From WMRootMenu *************/
1557 static WMenu*
1558 makeDefaultMenu(WScreen *scr)
1560 WMenu *menu=NULL;
1562 menu = wMenuCreate(scr, _("Commands"), True);
1563 wMenuAddCallback(menu, "XTerm", execCommand, "xterm");
1564 wMenuAddCallback(menu, "rxvt", execCommand, "rxvt");
1565 wMenuAddCallback(menu, _("Restart"), restartCommand, NULL);
1566 wMenuAddCallback(menu, _("Exit..."), exitCommand, NULL);
1567 return menu;
1575 *----------------------------------------------------------------------
1576 * configureMenu--
1577 * Reads root menu configuration from defaults database.
1579 *----------------------------------------------------------------------
1581 static WMenu*
1582 configureMenu(WScreen *scr, proplist_t definition)
1584 WMenu *menu = NULL;
1585 proplist_t elem;
1586 int i, count;
1587 proplist_t title, command, params;
1588 char *tmp, *mtitle;
1591 if (PLIsString(definition)) {
1592 struct stat stat_buf;
1593 char *path = NULL;
1594 Bool menu_is_default = False;
1596 /* menu definition is a string. Probably a path, so parse the file */
1598 tmp = wexpandpath(PLGetString(definition));
1600 path = getLocalizedMenuFile(tmp);
1602 if (!path)
1603 path = wfindfile(DEF_CONFIG_PATHS, tmp);
1605 if (!path) {
1606 path = wfindfile(DEF_CONFIG_PATHS, DEF_MENU_FILE);
1607 menu_is_default = True;
1610 if (!path) {
1611 wsyserror(_("could not find menu file \"%s\" referenced in WMRootMenu"),
1612 tmp);
1613 wfree(tmp);
1614 return NULL;
1617 if (stat(path, &stat_buf)<0) {
1618 wsyserror(_("could not access menu \"%s\" referenced in WMRootMenu"), path);
1619 wfree(path);
1620 wfree(tmp);
1621 return NULL;
1624 if (!scr->root_menu || stat_buf.st_mtime > scr->root_menu->timestamp
1625 /* if the pointer in WMRootMenu has changed */
1626 || WDRootMenu->timestamp > scr->root_menu->timestamp) {
1628 if (menu_is_default) {
1629 wwarning(_("using default menu file \"%s\" as the menu referenced in WMRootMenu could not be found "),
1630 path);
1633 menu = readMenuFile(scr, path);
1634 if (menu)
1635 menu->timestamp = WMAX(stat_buf.st_mtime, WDRootMenu->timestamp);
1636 } else {
1637 menu = NULL;
1639 wfree(path);
1640 wfree(tmp);
1642 return menu;
1645 count = PLGetNumberOfElements(definition);
1646 if (count==0)
1647 return NULL;
1649 elem = PLGetArrayElement(definition, 0);
1650 if (!PLIsString(elem)) {
1651 tmp = PLGetDescription(elem);
1652 wwarning(_("%s:format error in root menu configuration \"%s\""),
1653 "WMRootMenu", tmp);
1654 wfree(tmp);
1655 return NULL;
1657 mtitle = PLGetString(elem);
1659 menu = wMenuCreate(scr, mtitle, False);
1660 menu->on_destroy = removeShortcutsForMenu;
1662 #ifdef GLOBAL_SUBMENU_FILE
1664 WMenu *submenu;
1665 WMenuEntry *mentry;
1667 submenu = readMenuFile(scr, GLOBAL_SUBMENU_FILE);
1669 if (submenu) {
1670 mentry = wMenuAddCallback(menu, submenu->frame->title, NULL, NULL);
1671 wMenuEntrySetCascade(menu, mentry, submenu);
1674 #endif
1676 for (i=1; i<count; i++) {
1677 elem = PLGetArrayElement(definition, i);
1678 #if 0
1679 if (PLIsString(elem)) {
1680 char *file;
1682 file = PLGetString(elem);
1685 #endif
1686 if (!PLIsArray(elem) || PLGetNumberOfElements(elem) < 2)
1687 goto error;
1689 if (PLIsArray(PLGetArrayElement(elem,1))) {
1690 WMenu *submenu;
1691 WMenuEntry *mentry;
1693 /* submenu */
1694 submenu = configureMenu(scr, elem);
1695 if (submenu) {
1696 mentry = wMenuAddCallback(menu, submenu->frame->title, NULL,
1697 NULL);
1698 wMenuEntrySetCascade(menu, mentry, submenu);
1700 } else {
1701 int idx = 0;
1702 char *shortcut;
1703 /* normal entry */
1705 title = PLGetArrayElement(elem, idx++);
1706 shortcut = PLGetArrayElement(elem, idx++);
1707 if (strcmp(PLGetString(shortcut), "SHORTCUT")==0) {
1708 shortcut = PLGetArrayElement(elem, idx++);
1709 command = PLGetArrayElement(elem, idx++);
1710 } else {
1711 command = shortcut;
1712 shortcut = NULL;
1714 params = PLGetArrayElement(elem, idx++);
1716 if (!title || !command)
1717 goto error;
1719 addMenuEntry(menu, PLGetString(title),
1720 shortcut ? PLGetString(shortcut) : NULL,
1721 PLGetString(command),
1722 params ? PLGetString(params) : NULL, "WMRootMenu");
1724 continue;
1726 error:
1727 tmp = PLGetDescription(elem);
1728 wwarning(_("%s:format error in root menu configuration \"%s\""),
1729 "WMRootMenu", tmp);
1730 wfree(tmp);
1733 return menu;
1744 *----------------------------------------------------------------------
1745 * OpenRootMenu--
1746 * Opens the root menu, parsing the menu configuration from the
1747 * defaults database.
1748 * If the menu is already mapped and is not sticked to the
1749 * root window, it will be unmapped.
1751 * Side effects:
1752 * The menu may be remade.
1754 * Notes:
1755 * Construction of OPEN_MENU entries are delayed to the moment the
1756 * user map's them.
1757 *----------------------------------------------------------------------
1759 void
1760 OpenRootMenu(WScreen *scr, int x, int y, int keyboard)
1762 WMenu *menu=NULL;
1763 proplist_t definition;
1765 static proplist_t domain=NULL;
1767 if (!domain) {
1768 domain = PLMakeString("WMRootMenu");
1772 scr->flags.root_menu_changed_shortcuts = 0;
1773 scr->flags.added_workspace_menu = 0;
1774 scr->flags.added_windows_menu = 0;
1776 if (scr->root_menu && scr->root_menu->flags.mapped) {
1777 menu = scr->root_menu;
1778 if (!menu->flags.buttoned) {
1779 wMenuUnmap(menu);
1780 } else {
1781 wRaiseFrame(menu->frame->core);
1783 if (keyboard)
1784 wMenuMapAt(menu, 0, 0, True);
1785 else
1786 wMenuMapCopyAt(menu, x-menu->frame->core->width/2, y);
1788 return;
1792 definition = WDRootMenu->dictionary;
1795 definition = PLGetDomain(domain);
1797 if (definition) {
1798 if (PLIsArray(definition)) {
1799 if (!scr->root_menu
1800 || WDRootMenu->timestamp > scr->root_menu->timestamp) {
1801 menu = configureMenu(scr, definition);
1802 if (menu)
1803 menu->timestamp = WDRootMenu->timestamp;
1805 } else
1806 menu = NULL;
1807 } else {
1808 menu = configureMenu(scr, definition);
1812 if (!menu) {
1813 /* menu hasn't changed or could not be read */
1814 if (!scr->root_menu) {
1815 wMessageDialog(scr, _("Error"),
1816 _("The applications menu could not be loaded. "
1817 "Look at the console output for a detailed "
1818 "description of the errors."),
1819 _("OK"), NULL, NULL);
1821 menu = makeDefaultMenu(scr);
1822 scr->root_menu = menu;
1824 menu = scr->root_menu;
1825 } else {
1826 /* new root menu */
1827 if (scr->root_menu) {
1828 wMenuDestroy(scr->root_menu, True);
1830 scr->root_menu = menu;
1832 if (menu) {
1833 int newx, newy;
1835 if (keyboard && x==0 && y==0) {
1836 newx = newy = 0;
1837 } else if (keyboard && x==scr->scr_width/2 && y==scr->scr_height/2) {
1838 newx = x - menu->frame->core->width/2;
1839 newy = y - menu->frame->core->height/2;
1840 } else {
1841 newx = x - menu->frame->core->width/2;
1842 newy = y;
1844 wMenuMapAt(menu, newx, newy, keyboard);
1847 if (scr->flags.root_menu_changed_shortcuts)
1848 rebindKeygrabs(scr);
1851 #endif /* !LITE */