Rename INSTALL.pt
[wmaker-crm.git] / src / rootmenu.c
blob02388b2b1134d5bd184b62cd0194e3b487ebacb6
1 /* rootmenu.c- user defined menu
3 * Window Maker window manager
5 * Copyright (c) 1997-2003 Alfredo K. Kojima
6 * Copyright (c) 1998-2003 Dan Pascu
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 #include <stdio.h>
27 #include <stdlib.h>
28 #include <unistd.h>
29 #include <sys/stat.h>
30 #include <sys/wait.h>
31 #include <sys/types.h>
32 #include <string.h>
33 #include <ctype.h>
34 #include <time.h>
35 #include <dirent.h>
37 #include <X11/Xlib.h>
38 #include <X11/Xutil.h>
39 #include <X11/Xatom.h>
41 #include "WindowMaker.h"
42 #include "actions.h"
43 #include "menu.h"
44 #include "funcs.h"
45 #include "dialog.h"
46 #include "keybind.h"
47 #include "stacking.h"
48 #include "workspace.h"
49 #include "defaults.h"
50 #include "framewin.h"
51 #include "session.h"
52 #include "xmodifier.h"
54 #include <WINGs/WUtil.h>
56 #define MAX_SHORTCUT_LENGTH 32
58 extern char *Locale;
60 extern WDDomain *WDRootMenu;
62 extern Cursor wCursor[WCUR_LAST];
64 extern Time LastTimestamp;
66 extern WPreferences wPreferences;
68 extern int wScreenCount;
70 static WMenu *readMenuPipe(WScreen * scr, char **file_name);
71 static WMenu *readMenuFile(WScreen * scr, char *file_name);
72 static WMenu *readMenuDirectory(WScreen * scr, char *title, char **file_name, char *command);
74 typedef struct Shortcut {
75 struct Shortcut *next;
77 int modifier;
78 KeyCode keycode;
79 WMenuEntry *entry;
80 WMenu *menu;
81 } Shortcut;
83 static Shortcut *shortcutList = NULL;
86 * Syntax:
87 * # main menu
88 * "Menu Name" MENU
89 * "Title" EXEC command_to_exec -params
90 * "Submenu" MENU
91 * "Title" EXEC command_to_exec -params
92 * "Submenu" END
93 * "Workspaces" WORKSPACE_MENU
94 * "Title" built_in_command
95 * "Quit" EXIT
96 * "Quick Quit" EXIT QUICK
97 * "Menu Name" END
99 * Commands may be preceded by SHORTCUT key
101 * Built-in commands:
103 * INFO_PANEL - shows the Info Panel
104 * LEGAL_PANEL - shows the Legal info panel
105 * SHUTDOWN [QUICK] - closes the X server [without confirmation]
106 * REFRESH - forces the desktop to be repainted
107 * EXIT [QUICK] - exit the window manager [without confirmation]
108 * EXEC <program> - execute an external program
109 * SHEXEC <command> - execute a shell command
110 * WORKSPACE_MENU - places the workspace submenu
111 * ARRANGE_ICONS
112 * RESTART [<window manager>] - restarts the window manager
113 * SHOW_ALL - unhide all windows on workspace
114 * HIDE_OTHERS - hides all windows excep the focused one
115 * OPEN_MENU file - read menu data from file which must be a valid menu file.
116 * OPEN_MENU /some/dir [/some/other/dir ...] [WITH command -options]
117 * - read menu data from directory(ies) and
118 * eventually precede each with a command.
119 * OPEN_MENU | command
120 * - opens command and uses its stdout to construct and insert
121 * the resulting menu in current position. The output of
122 * command must be a valid menu description.
123 * The space between '|' and command is optional.
124 * || will do the same, but will not cache the contents.
125 * SAVE_SESSION - saves the current state of the desktop, which include
126 * all running applications, all their hints (geometry,
127 * position on screen, workspace they live on, the dock
128 * or clip from where they were launched, and
129 * if minimized, shaded or hidden. Also saves the current
130 * workspace the user is on. All will be restored on every
131 * start of windowmaker until another SAVE_SESSION or
132 * CLEAR_SESSION is used. If SaveSessionOnExit = Yes; in
133 * WindowMaker domain file, then saving is automatically
134 * done on every windowmaker exit, overwriting any
135 * SAVE_SESSION or CLEAR_SESSION (see below). Also save
136 * dock state now.
137 * CLEAR_SESSION - clears any previous saved session. This will not have
138 * any effect if SaveSessionOnExit is True.
142 #define M_QUICK 1
144 /* menu commands */
146 static void execCommand(WMenu * menu, WMenuEntry * entry)
148 char *cmdline;
150 cmdline = ExpandOptions(menu->frame->screen_ptr, (char *)entry->clientdata);
152 XGrabPointer(dpy, menu->frame->screen_ptr->root_win, True, 0,
153 GrabModeAsync, GrabModeAsync, None, wCursor[WCUR_WAIT], CurrentTime);
154 XSync(dpy, 0);
156 if (cmdline) {
157 ExecuteShellCommand(menu->frame->screen_ptr, cmdline);
158 wfree(cmdline);
160 XUngrabPointer(dpy, CurrentTime);
161 XSync(dpy, 0);
164 static void exitCommand(WMenu * menu, WMenuEntry * entry)
166 static int inside = 0;
167 int result;
169 /* prevent reentrant calls */
170 if (inside)
171 return;
172 inside = 1;
174 #define R_CANCEL 0
175 #define R_EXIT 1
177 result = R_CANCEL;
179 if ((long)entry->clientdata == M_QUICK) {
180 result = R_EXIT;
181 } else {
182 int r, oldSaveSessionFlag;
184 oldSaveSessionFlag = wPreferences.save_session_on_exit;
185 r = wExitDialog(menu->frame->screen_ptr, _("Exit"),
186 _("Exit window manager?"), _("Exit"), _("Cancel"), NULL);
188 if (r == WAPRDefault) {
189 result = R_EXIT;
190 } else if (r == WAPRAlternate) {
191 /* Don't modify the "save session on exit" flag if the
192 * user canceled the operation. */
193 wPreferences.save_session_on_exit = oldSaveSessionFlag;
196 if (result == R_EXIT)
197 Shutdown(WSExitMode);
199 #undef R_EXIT
200 #undef R_CANCEL
201 inside = 0;
204 static void shutdownCommand(WMenu * menu, WMenuEntry * entry)
206 static int inside = 0;
207 int result;
209 /* prevent reentrant calls */
210 if (inside)
211 return;
212 inside = 1;
214 #define R_CANCEL 0
215 #define R_CLOSE 1
216 #define R_KILL 2
218 result = R_CANCEL;
219 if ((long)entry->clientdata == M_QUICK)
220 result = R_CLOSE;
221 else {
223 int r, oldSaveSessionFlag;
225 oldSaveSessionFlag = wPreferences.save_session_on_exit;
227 r = wExitDialog(menu->frame->screen_ptr,
228 _("Kill X session"),
229 _("Kill Window System session?\n"
230 "(all applications will be closed)"), _("Kill"), _("Cancel"), NULL);
231 if (r == WAPRDefault) {
232 result = R_KILL;
233 } else if (r == WAPRAlternate) {
234 /* Don't modify the "save session on exit" flag if the
235 * user canceled the operation. */
236 wPreferences.save_session_on_exit = oldSaveSessionFlag;
241 if (result != R_CANCEL) {
243 Shutdown(WSKillMode);
246 #undef R_CLOSE
247 #undef R_CANCEL
248 #undef R_KILL
249 inside = 0;
252 static void restartCommand(WMenu * menu, WMenuEntry * entry)
254 Shutdown(WSRestartPreparationMode);
255 Restart((char *)entry->clientdata, False);
256 Restart(NULL, True);
259 static void refreshCommand(WMenu * menu, WMenuEntry * entry)
261 wRefreshDesktop(menu->frame->screen_ptr);
264 static void arrangeIconsCommand(WMenu * menu, WMenuEntry * entry)
266 wArrangeIcons(menu->frame->screen_ptr, True);
269 static void showAllCommand(WMenu * menu, WMenuEntry * entry)
271 wShowAllWindows(menu->frame->screen_ptr);
274 static void hideOthersCommand(WMenu * menu, WMenuEntry * entry)
276 wHideOtherApplications(menu->frame->screen_ptr->focused_window);
279 static void saveSessionCommand(WMenu * menu, WMenuEntry * entry)
281 if (!wPreferences.save_session_on_exit)
282 wSessionSaveState(menu->frame->screen_ptr);
284 wScreenSaveState(menu->frame->screen_ptr);
287 static void clearSessionCommand(WMenu * menu, WMenuEntry * entry)
289 wSessionClearState(menu->frame->screen_ptr);
290 wScreenSaveState(menu->frame->screen_ptr);
293 static void infoPanelCommand(WMenu * menu, WMenuEntry * entry)
295 wShowInfoPanel(menu->frame->screen_ptr);
298 static void legalPanelCommand(WMenu * menu, WMenuEntry * entry)
300 wShowLegalPanel(menu->frame->screen_ptr);
303 /********************************************************************/
305 static char *getLocalizedMenuFile(char *menu)
307 char *buffer, *ptr, *locale;
308 int len;
310 if (!Locale)
311 return NULL;
313 len = strlen(menu) + strlen(Locale) + 8;
314 buffer = wmalloc(len);
316 /* try menu.locale_name */
317 snprintf(buffer, len, "%s.%s", menu, Locale);
318 if (access(buffer, F_OK) == 0) {
319 return buffer;
322 /* position of locale in our buffer */
323 locale = buffer + strlen(menu) + 1;
325 /* check if it is in the form aa_bb.encoding and check for aa_bb */
326 ptr = strchr(locale, '.');
327 if (ptr) {
328 *ptr = 0;
329 if (access(buffer, F_OK) == 0) {
330 return buffer;
333 /* now check for aa */
334 ptr = strchr(locale, '_');
335 if (ptr) {
336 *ptr = 0;
337 if (access(buffer, F_OK) == 0) {
338 return buffer;
342 wfree(buffer);
344 return NULL;
347 Bool wRootMenuPerformShortcut(XEvent * event)
349 WScreen *scr = wScreenForRootWindow(event->xkey.root);
350 Shortcut *ptr;
351 int modifiers;
352 int done = 0;
354 /* ignore CapsLock */
355 modifiers = event->xkey.state & ValidModMask;
357 for (ptr = shortcutList; ptr != NULL; ptr = ptr->next) {
358 if (ptr->keycode == 0 || ptr->menu->menu->screen_ptr != scr)
359 continue;
361 if (ptr->keycode == event->xkey.keycode && ptr->modifier == modifiers) {
362 (*ptr->entry->callback) (ptr->menu, ptr->entry);
363 done = True;
367 return done;
370 void wRootMenuBindShortcuts(Window window)
372 Shortcut *ptr;
374 ptr = shortcutList;
375 while (ptr) {
376 if (ptr->modifier != AnyModifier) {
377 XGrabKey(dpy, ptr->keycode, ptr->modifier | LockMask,
378 window, True, GrabModeAsync, GrabModeAsync);
379 #ifdef NUMLOCK_HACK
380 wHackedGrabKey(ptr->keycode, ptr->modifier, window, True, GrabModeAsync, GrabModeAsync);
381 #endif
383 XGrabKey(dpy, ptr->keycode, ptr->modifier, window, True, GrabModeAsync, GrabModeAsync);
384 ptr = ptr->next;
388 static void rebindKeygrabs(WScreen * scr)
390 WWindow *wwin;
392 wwin = scr->focused_window;
394 while (wwin != NULL) {
395 XUngrabKey(dpy, AnyKey, AnyModifier, wwin->frame->core->window);
397 if (!WFLAGP(wwin, no_bind_keys)) {
398 wWindowSetKeyGrabs(wwin);
400 wwin = wwin->prev;
404 static void removeShortcutsForMenu(WMenu * menu)
406 Shortcut *ptr, *tmp;
407 Shortcut *newList = NULL;
409 ptr = shortcutList;
410 while (ptr != NULL) {
411 tmp = ptr->next;
412 if (ptr->menu == menu) {
413 wfree(ptr);
414 } else {
415 ptr->next = newList;
416 newList = ptr;
418 ptr = tmp;
420 shortcutList = newList;
421 menu->menu->screen_ptr->flags.root_menu_changed_shortcuts = 1;
424 static Bool addShortcut(char *file, char *shortcutDefinition, WMenu * menu, WMenuEntry * entry)
426 Shortcut *ptr;
427 KeySym ksym;
428 char *k;
429 char buf[MAX_SHORTCUT_LENGTH], *b;
431 ptr = wmalloc(sizeof(Shortcut));
433 strncpy(buf, shortcutDefinition, MAX_SHORTCUT_LENGTH);
434 b = (char *)buf;
436 /* get modifiers */
437 ptr->modifier = 0;
438 while ((k = strchr(b, '+')) != NULL) {
439 int mod;
441 *k = 0;
442 mod = wXModifierFromKey(b);
443 if (mod < 0) {
444 wwarning(_("%s: invalid key modifier \"%s\""), file, b);
445 wfree(ptr);
446 return False;
448 ptr->modifier |= mod;
450 b = k + 1;
453 /* get key */
454 ksym = XStringToKeysym(b);
456 if (ksym == NoSymbol) {
457 wwarning(_("%s:invalid kbd shortcut specification \"%s\" for entry %s"),
458 file, shortcutDefinition, entry->text);
459 wfree(ptr);
460 return False;
463 ptr->keycode = XKeysymToKeycode(dpy, ksym);
464 if (ptr->keycode == 0) {
465 wwarning(_("%s:invalid key in shortcut \"%s\" for entry %s"), file,
466 shortcutDefinition, entry->text);
467 wfree(ptr);
468 return False;
471 ptr->menu = menu;
472 ptr->entry = entry;
474 ptr->next = shortcutList;
475 shortcutList = ptr;
477 menu->menu->screen_ptr->flags.root_menu_changed_shortcuts = 1;
479 return True;
482 /*******************************/
484 static char *cropline(char *line)
486 char *end;
488 if (strlen(line) == 0)
489 return line;
491 end = &(line[strlen(line)]) - 1;
492 while (isspace(*line) && *line != 0)
493 line++;
494 while (end > line && isspace(*end)) {
495 *end = 0;
496 end--;
498 return line;
501 static char *next_token(char *line, char **next)
503 char *tmp, c;
504 char *ret;
506 *next = NULL;
507 while (*line == ' ' || *line == '\t')
508 line++;
510 tmp = line;
512 if (*tmp == '"') {
513 tmp++;
514 line++;
515 while (*tmp != 0 && *tmp != '"')
516 tmp++;
517 if (*tmp != '"') {
518 wwarning(_("%s: unmatched '\"' in menu file"), line);
519 return NULL;
521 } else {
522 do {
523 if (*tmp == '\\')
524 tmp++;
526 if (*tmp != 0)
527 tmp++;
529 } while (*tmp != 0 && *tmp != ' ' && *tmp != '\t');
532 c = *tmp;
533 *tmp = 0;
534 ret = wstrdup(line);
535 *tmp = c;
537 if (c == 0)
538 return ret;
539 else
540 tmp++;
542 /* skip blanks */
543 while (*tmp == ' ' || *tmp == '\t')
544 tmp++;
546 if (*tmp != 0)
547 *next = tmp;
549 return ret;
552 static void separateCommand(char *line, char ***file, char **command)
554 char *token, *tmp = line;
555 WMArray *array = WMCreateArray(4);
556 int count, i;
558 *file = NULL;
559 *command = NULL;
560 do {
561 token = next_token(tmp, &tmp);
562 if (token) {
563 if (strcmp(token, "WITH") == 0) {
564 if (tmp != NULL && *tmp != 0)
565 *command = wstrdup(tmp);
566 else
567 wwarning(_("%s: missing command"), line);
568 break;
570 WMAddToArray(array, token);
572 } while (token != NULL && tmp != NULL);
574 count = WMGetArrayItemCount(array);
575 if (count > 0) {
576 *file = wmalloc(sizeof(char *) * (count + 1));
577 (*file)[count] = NULL;
578 for (i = 0; i < count; i++) {
579 (*file)[i] = WMGetFromArray(array, i);
582 WMFreeArray(array);
585 static void constructMenu(WMenu * menu, WMenuEntry * entry)
587 WMenu *submenu;
588 struct stat stat_buf;
589 char **path;
590 char *cmd;
591 char *lpath = NULL;
592 int i, first = -1;
593 time_t last = 0;
595 separateCommand((char *)entry->clientdata, &path, &cmd);
596 if (path == NULL || *path == NULL || **path == 0) {
597 wwarning(_("invalid OPEN_MENU specification: %s"), (char *)entry->clientdata);
598 return;
601 if (path[0][0] == '|') {
602 /* pipe menu */
604 if (!menu->cascades[entry->cascade] || menu->cascades[entry->cascade]->timestamp == 0) {
605 /* parse pipe */
607 submenu = readMenuPipe(menu->frame->screen_ptr, path);
609 if (submenu != NULL) {
610 if (path[0][1] == '|')
611 submenu->timestamp = 0;
612 else
613 submenu->timestamp = 1; /* there's no automatic reloading */
615 } else {
616 submenu = NULL;
619 } else {
620 i = 0;
621 while (path[i] != NULL) {
622 char *tmp;
624 if (strcmp(path[i], "-noext") == 0) {
625 i++;
626 continue;
629 tmp = wexpandpath(path[i]);
630 wfree(path[i]);
631 lpath = getLocalizedMenuFile(tmp);
632 if (lpath) {
633 wfree(tmp);
634 path[i] = lpath;
635 lpath = NULL;
636 } else {
637 path[i] = tmp;
640 if (stat(path[i], &stat_buf) == 0) {
641 if (last < stat_buf.st_mtime)
642 last = stat_buf.st_mtime;
643 if (first < 0)
644 first = i;
645 } else {
646 wsyserror(_("%s:could not stat menu"), path[i]);
647 /*goto finish; */
650 i++;
653 if (first < 0) {
654 wsyserror(_("%s:could not stat menu:%s"), "OPEN_MENU", (char *)entry->clientdata);
655 goto finish;
657 stat(path[first], &stat_buf);
658 if (!menu->cascades[entry->cascade]
659 || menu->cascades[entry->cascade]->timestamp < last) {
661 if (S_ISDIR(stat_buf.st_mode)) {
662 /* menu directory */
663 submenu = readMenuDirectory(menu->frame->screen_ptr, entry->text, path, cmd);
664 if (submenu)
665 submenu->timestamp = last;
666 } else if (S_ISREG(stat_buf.st_mode)) {
667 /* menu file */
669 if (cmd || path[1])
670 wwarning(_("too many parameters in OPEN_MENU: %s"),
671 (char *)entry->clientdata);
673 submenu = readMenuFile(menu->frame->screen_ptr, path[first]);
674 if (submenu)
675 submenu->timestamp = stat_buf.st_mtime;
676 } else {
677 submenu = NULL;
679 } else {
680 submenu = NULL;
684 if (submenu) {
685 wMenuEntryRemoveCascade(menu, entry);
686 wMenuEntrySetCascade(menu, entry, submenu);
689 finish:
690 i = 0;
691 while (path[i] != NULL)
692 wfree(path[i++]);
693 wfree(path);
694 if (cmd)
695 wfree(cmd);
698 static void cleanupWorkspaceMenu(WMenu * menu)
700 if (menu->frame->screen_ptr->workspace_menu == menu)
701 menu->frame->screen_ptr->workspace_menu = NULL;
704 static WMenuEntry *addWorkspaceMenu(WScreen * scr, WMenu * menu, char *title)
706 WMenu *wsmenu;
707 WMenuEntry *entry;
709 if (scr->flags.added_workspace_menu) {
710 wwarning(_
711 ("There are more than one WORKSPACE_MENU commands in the applications menu. Only one is allowed."));
712 return NULL;
713 } else {
714 scr->flags.added_workspace_menu = 1;
716 wsmenu = wWorkspaceMenuMake(scr, True);
717 wsmenu->on_destroy = cleanupWorkspaceMenu;
719 scr->workspace_menu = wsmenu;
720 entry = wMenuAddCallback(menu, title, NULL, NULL);
721 wMenuEntrySetCascade(menu, entry, wsmenu);
723 wWorkspaceMenuUpdate(scr, wsmenu);
725 return entry;
728 static void cleanupWindowsMenu(WMenu * menu)
730 if (menu->frame->screen_ptr->switch_menu == menu)
731 menu->frame->screen_ptr->switch_menu = NULL;
734 static WMenuEntry *addWindowsMenu(WScreen * scr, WMenu * menu, char *title)
736 WMenu *wwmenu;
737 WWindow *wwin;
738 WMenuEntry *entry;
740 if (scr->flags.added_windows_menu) {
741 wwarning(_
742 ("There are more than one WINDOWS_MENU commands in the applications menu. Only one is allowed."));
743 return NULL;
744 } else {
745 scr->flags.added_windows_menu = 1;
747 wwmenu = wMenuCreate(scr, _("Window List"), False);
748 wwmenu->on_destroy = cleanupWindowsMenu;
749 scr->switch_menu = wwmenu;
750 wwin = scr->focused_window;
751 while (wwin) {
752 UpdateSwitchMenu(scr, wwin, ACTION_ADD);
754 wwin = wwin->prev;
756 entry = wMenuAddCallback(menu, title, NULL, NULL);
757 wMenuEntrySetCascade(menu, entry, wwmenu);
759 return entry;
762 static WMenuEntry *addMenuEntry(WMenu * menu, char *title, char *shortcut, char *command,
763 char *params, char *file_name)
765 WScreen *scr;
766 WMenuEntry *entry = NULL;
767 Bool shortcutOk = False;
769 if (!menu)
770 return NULL;
771 scr = menu->frame->screen_ptr;
772 if (strcmp(command, "OPEN_MENU") == 0) {
773 if (!params) {
774 wwarning(_("%s:missing parameter for menu command \"%s\""), file_name, command);
775 } else {
776 WMenu *dummy;
777 char *path;
779 path = wfindfile(DEF_CONFIG_PATHS, params);
780 if (!path) {
781 path = wstrdup(params);
783 dummy = wMenuCreate(scr, title, False);
784 dummy->on_destroy = removeShortcutsForMenu;
785 entry = wMenuAddCallback(menu, title, constructMenu, path);
786 entry->free_cdata = free;
787 wMenuEntrySetCascade(menu, entry, dummy);
789 } else if (strcmp(command, "EXEC") == 0) {
790 if (!params)
791 wwarning(_("%s:missing parameter for menu command \"%s\""), file_name, command);
792 else {
793 entry = wMenuAddCallback(menu, title, execCommand, wstrconcat("exec ", params));
794 entry->free_cdata = free;
795 shortcutOk = True;
797 } else if (strcmp(command, "SHEXEC") == 0) {
798 if (!params)
799 wwarning(_("%s:missing parameter for menu command \"%s\""), file_name, command);
800 else {
801 entry = wMenuAddCallback(menu, title, execCommand, wstrdup(params));
802 entry->free_cdata = free;
803 shortcutOk = True;
805 } else if (strcmp(command, "EXIT") == 0) {
807 if (params && strcmp(params, "QUICK") == 0)
808 entry = wMenuAddCallback(menu, title, exitCommand, (void *)M_QUICK);
809 else
810 entry = wMenuAddCallback(menu, title, exitCommand, NULL);
812 shortcutOk = True;
813 } else if (strcmp(command, "SHUTDOWN") == 0) {
815 if (params && strcmp(params, "QUICK") == 0)
816 entry = wMenuAddCallback(menu, title, shutdownCommand, (void *)M_QUICK);
817 else
818 entry = wMenuAddCallback(menu, title, shutdownCommand, NULL);
820 shortcutOk = True;
821 } else if (strcmp(command, "REFRESH") == 0) {
822 entry = wMenuAddCallback(menu, title, refreshCommand, NULL);
824 shortcutOk = True;
825 } else if (strcmp(command, "WORKSPACE_MENU") == 0) {
826 entry = addWorkspaceMenu(scr, menu, title);
828 shortcutOk = True;
829 } else if (strcmp(command, "WINDOWS_MENU") == 0) {
830 entry = addWindowsMenu(scr, menu, title);
832 shortcutOk = True;
833 } else if (strcmp(command, "ARRANGE_ICONS") == 0) {
834 entry = wMenuAddCallback(menu, title, arrangeIconsCommand, NULL);
836 shortcutOk = True;
837 } else if (strcmp(command, "HIDE_OTHERS") == 0) {
838 entry = wMenuAddCallback(menu, title, hideOthersCommand, NULL);
840 shortcutOk = True;
841 } else if (strcmp(command, "SHOW_ALL") == 0) {
842 entry = wMenuAddCallback(menu, title, showAllCommand, NULL);
844 shortcutOk = True;
845 } else if (strcmp(command, "RESTART") == 0) {
846 entry = wMenuAddCallback(menu, title, restartCommand, params ? wstrdup(params) : NULL);
847 entry->free_cdata = free;
848 shortcutOk = True;
849 } else if (strcmp(command, "SAVE_SESSION") == 0) {
850 entry = wMenuAddCallback(menu, title, saveSessionCommand, NULL);
852 shortcutOk = True;
853 } else if (strcmp(command, "CLEAR_SESSION") == 0) {
854 entry = wMenuAddCallback(menu, title, clearSessionCommand, NULL);
855 shortcutOk = True;
856 } else if (strcmp(command, "INFO_PANEL") == 0) {
857 entry = wMenuAddCallback(menu, title, infoPanelCommand, NULL);
858 shortcutOk = True;
859 } else if (strcmp(command, "LEGAL_PANEL") == 0) {
860 entry = wMenuAddCallback(menu, title, legalPanelCommand, NULL);
861 shortcutOk = True;
862 } else {
863 wwarning(_("%s:unknown command \"%s\" in menu config."), file_name, command);
865 return NULL;
868 if (shortcut && entry) {
869 if (!shortcutOk) {
870 wwarning(_("%s:can't add shortcut for entry \"%s\""), file_name, title);
871 } else {
872 if (addShortcut(file_name, shortcut, menu, entry)) {
874 entry->rtext = GetShortcutString(shortcut);
876 entry->rtext = wstrdup(shortcut);
882 return entry;
885 /******************* Menu Configuration From File *******************/
887 static void separateline(char *line, char *title, char *command, char *parameter, char *shortcut)
889 int l, i;
891 l = strlen(line);
893 *title = 0;
894 *command = 0;
895 *parameter = 0;
896 *shortcut = 0;
897 /* get the title */
898 while (isspace(*line) && (*line != 0))
899 line++;
900 if (*line == '"') {
901 line++;
902 i = 0;
903 while (line[i] != '"' && (line[i] != 0))
904 i++;
905 if (line[i] != '"')
906 return;
907 } else {
908 i = 0;
909 while (!isspace(line[i]) && (line[i] != 0))
910 i++;
912 strncpy(title, line, i);
913 title[i++] = 0;
914 line += i;
916 /* get the command or shortcut keyword */
917 while (isspace(*line) && (*line != 0))
918 line++;
919 if (*line == 0)
920 return;
921 i = 0;
922 while (!isspace(line[i]) && (line[i] != 0))
923 i++;
924 strncpy(command, line, i);
925 command[i++] = 0;
926 line += i;
928 if (strcmp(command, "SHORTCUT") == 0) {
929 /* get the shortcut key */
930 while (isspace(*line) && (*line != 0))
931 line++;
932 if (*line == '"') {
933 line++;
934 i = 0;
935 while (line[i] != '"' && (line[i] != 0))
936 i++;
937 if (line[i] != '"')
938 return;
939 } else {
940 i = 0;
941 while (!isspace(line[i]) && (line[i] != 0))
942 i++;
944 strncpy(shortcut, line, i);
945 shortcut[i++] = 0;
946 line += i;
948 *command = 0;
950 /* get the command */
951 while (isspace(*line) && (*line != 0))
952 line++;
953 if (*line == 0)
954 return;
955 i = 0;
956 while (!isspace(line[i]) && (line[i] != 0))
957 i++;
958 strncpy(command, line, i);
959 command[i++] = 0;
960 line += i;
963 /* get the parameters */
964 while (isspace(*line) && (*line != 0))
965 line++;
966 if (*line == 0)
967 return;
969 if (*line == '"') {
970 line++;
971 l = 0;
972 while (line[l] != 0 && line[l] != '"') {
973 parameter[l] = line[l];
974 l++;
976 parameter[l] = 0;
977 return;
980 l = strlen(line);
981 while (isspace(line[l]) && (l > 0))
982 l--;
983 strncpy(parameter, line, l);
984 parameter[l] = 0;
987 static WMenu *parseCascade(WScreen * scr, WMenu * menu, FILE * file, char *file_name)
989 char linebuf[MAXLINE];
990 char elinebuf[MAXLINE];
991 char title[MAXLINE];
992 char command[MAXLINE];
993 char shortcut[MAXLINE];
994 char params[MAXLINE];
995 char *line;
997 while (!feof(file)) {
998 int lsize, ok;
1000 ok = 0;
1001 fgets(linebuf, MAXLINE, file);
1002 line = cropline(linebuf);
1003 lsize = strlen(line);
1004 do {
1005 if (line[lsize - 1] == '\\') {
1006 char *line2;
1007 int lsize2;
1008 fgets(elinebuf, MAXLINE, file);
1009 line2 = cropline(elinebuf);
1010 lsize2 = strlen(line2);
1011 if (lsize2 + lsize > MAXLINE) {
1012 wwarning(_("%s:maximal line size exceeded in menu config: %s"),
1013 file_name, line);
1014 ok = 2;
1015 } else {
1016 line[lsize - 1] = 0;
1017 lsize += lsize2 - 1;
1018 strcat(line, line2);
1020 } else {
1021 ok = 1;
1023 } while (!ok && !feof(file));
1024 if (ok == 2)
1025 continue;
1027 if (line[0] == 0 || line[0] == '#' || (line[0] == '/' && line[1] == '/'))
1028 continue;
1030 separateline(line, title, command, params, shortcut);
1032 if (!command[0]) {
1033 wwarning(_("%s:missing command in menu config: %s"), file_name, line);
1034 goto error;
1037 if (strcasecmp(command, "MENU") == 0) {
1038 WMenu *cascade;
1040 /* start submenu */
1042 cascade = wMenuCreate(scr, title, False);
1043 cascade->on_destroy = removeShortcutsForMenu;
1044 if (parseCascade(scr, cascade, file, file_name) == NULL) {
1045 wMenuDestroy(cascade, True);
1046 } else {
1047 wMenuEntrySetCascade(menu, wMenuAddCallback(menu, title, NULL, NULL), cascade);
1049 } else if (strcasecmp(command, "END") == 0) {
1050 /* end of menu */
1051 return menu;
1053 } else {
1054 /* normal items */
1055 addMenuEntry(menu, title, shortcut[0] ? shortcut : NULL, command,
1056 params[0] ? params : NULL, file_name);
1060 wwarning(_("%s:syntax error in menu file:END declaration missing"), file_name);
1061 return menu;
1063 error:
1064 return menu;
1067 static WMenu *readMenuFile(WScreen * scr, char *file_name)
1069 WMenu *menu = NULL;
1070 FILE *file = NULL;
1071 char linebuf[MAXLINE];
1072 char title[MAXLINE];
1073 char shortcut[MAXLINE];
1074 char command[MAXLINE];
1075 char params[MAXLINE];
1076 char *line;
1077 #ifdef USECPP
1078 char *args;
1079 int cpp = 0;
1080 #endif
1082 #ifdef USECPP
1083 if (!wPreferences.flags.nocpp) {
1084 args = MakeCPPArgs(file_name);
1085 if (!args) {
1086 wwarning(_("could not make arguments for menu file preprocessor"));
1087 } else {
1088 snprintf(command, sizeof(command), "%s %s %s", CPP_PATH, args, file_name);
1089 wfree(args);
1090 file = popen(command, "r");
1091 if (!file) {
1092 wsyserror(_("%s:could not open/preprocess menu file"), file_name);
1093 } else {
1094 cpp = 1;
1098 #endif /* USECPP */
1100 if (!file) {
1101 file = fopen(file_name, "rb");
1102 if (!file) {
1103 wsyserror(_("%s:could not open menu file"), file_name);
1104 return NULL;
1108 while (!feof(file)) {
1109 if (!fgets(linebuf, MAXLINE, file))
1110 break;
1111 line = cropline(linebuf);
1112 if (line[0] == 0 || line[0] == '#' || (line[0] == '/' && line[1] == '/'))
1113 continue;
1115 separateline(line, title, command, params, shortcut);
1117 if (!command[0]) {
1118 wwarning(_("%s:missing command in menu config: %s"), file_name, line);
1119 break;
1121 if (strcasecmp(command, "MENU") == 0) {
1122 menu = wMenuCreate(scr, title, True);
1123 menu->on_destroy = removeShortcutsForMenu;
1124 if (!parseCascade(scr, menu, file, file_name)) {
1125 wMenuDestroy(menu, True);
1127 break;
1128 } else {
1129 wwarning(_("%s:invalid menu file. MENU command is missing"), file_name);
1130 break;
1134 #ifdef CPP
1135 if (cpp) {
1136 if (pclose(file) == -1) {
1137 wsyserror(_("error reading preprocessed menu data"));
1139 } else {
1140 fclose(file);
1142 #else
1143 fclose(file);
1144 #endif
1146 return menu;
1149 /************ Menu Configuration From Pipe *************/
1151 static WMenu *readMenuPipe(WScreen * scr, char **file_name)
1153 WMenu *menu = NULL;
1154 FILE *file = NULL;
1155 char linebuf[MAXLINE];
1156 char title[MAXLINE];
1157 char command[MAXLINE];
1158 char params[MAXLINE];
1159 char shortcut[MAXLINE];
1160 char *line;
1161 char *filename;
1162 char flat_file[MAXLINE];
1163 int i;
1164 #ifdef USECPP
1165 char *args;
1166 int cpp = 0;
1167 #endif
1169 flat_file[0] = '\0';
1171 for (i = 0; file_name[i] != NULL; i++) {
1172 strcat(flat_file, file_name[i]);
1173 strcat(flat_file, " ");
1175 filename = flat_file + (flat_file[1] == '|' ? 2 : 1);
1177 #ifdef USECPP
1178 if (!wPreferences.flags.nocpp) {
1179 args = MakeCPPArgs(filename);
1180 if (!args) {
1181 wwarning(_("could not make arguments for menu file preprocessor"));
1182 } else {
1183 snprintf(command, sizeof(command), "%s | %s %s", filename, CPP_PATH, args);
1185 wfree(args);
1186 file = popen(command, "r");
1187 if (!file) {
1188 wsyserror(_("%s:could not open/preprocess menu file"), filename);
1189 } else {
1190 cpp = 1;
1194 #endif /* USECPP */
1196 if (!file) {
1197 file = popen(filename, "rb");
1199 if (!file) {
1200 wsyserror(_("%s:could not open menu file"), filename);
1201 return NULL;
1205 while (!feof(file)) {
1206 if (!fgets(linebuf, MAXLINE, file))
1207 break;
1208 line = cropline(linebuf);
1209 if (line[0] == 0 || line[0] == '#' || (line[0] == '/' && line[1] == '/'))
1210 continue;
1212 separateline(line, title, command, params, shortcut);
1214 if (!command[0]) {
1215 wwarning(_("%s:missing command in menu config: %s"), filename, line);
1216 break;
1218 if (strcasecmp(command, "MENU") == 0) {
1219 menu = wMenuCreate(scr, title, True);
1220 menu->on_destroy = removeShortcutsForMenu;
1221 if (!parseCascade(scr, menu, file, filename)) {
1222 wMenuDestroy(menu, True);
1224 break;
1225 } else {
1226 wwarning(_("%s:no title given for the root menu"), filename);
1227 break;
1231 pclose(file);
1233 return menu;
1236 typedef struct {
1237 char *name;
1238 int index;
1239 } dir_data;
1241 static int myCompare(const void *d1, const void *d2)
1243 dir_data *p1 = *(dir_data **) d1;
1244 dir_data *p2 = *(dir_data **) d2;
1246 return strcmp(p1->name, p2->name);
1249 /************ Menu Configuration From Directory *************/
1251 static Bool isFilePackage(char *file)
1253 int l;
1255 /* check if the extension indicates this file is a
1256 * file package. For now, only recognize .themed */
1258 l = strlen(file);
1260 if (l > 7 && strcmp(&(file[l - 7]), ".themed") == 0) {
1261 return True;
1262 } else {
1263 return False;
1267 static WMenu *readMenuDirectory(WScreen * scr, char *title, char **path, char *command)
1269 DIR *dir;
1270 struct dirent *dentry;
1271 struct stat stat_buf;
1272 WMenu *menu = NULL;
1273 char *buffer;
1274 WMArray *dirs = NULL, *files = NULL;
1275 WMArrayIterator iter;
1276 int length, i, have_space = 0;
1277 dir_data *data;
1278 int stripExtension = 0;
1280 dirs = WMCreateArray(16);
1281 files = WMCreateArray(16);
1283 i = 0;
1284 while (path[i] != NULL) {
1285 if (strcmp(path[i], "-noext") == 0) {
1286 stripExtension = 1;
1287 i++;
1288 continue;
1291 dir = opendir(path[i]);
1292 if (!dir) {
1293 i++;
1294 continue;
1297 while ((dentry = readdir(dir))) {
1299 if (strcmp(dentry->d_name, ".") == 0 || strcmp(dentry->d_name, "..") == 0)
1300 continue;
1302 if (dentry->d_name[0] == '.')
1303 continue;
1305 buffer = malloc(strlen(path[i]) + strlen(dentry->d_name) + 4);
1306 if (!buffer) {
1307 wsyserror(_("out of memory while constructing directory menu %s"), path[i]);
1308 break;
1311 strcpy(buffer, path[i]);
1312 strcat(buffer, "/");
1313 strcat(buffer, dentry->d_name);
1315 if (stat(buffer, &stat_buf) != 0) {
1316 wsyserror(_("%s:could not stat file \"%s\" in menu directory"),
1317 path[i], dentry->d_name);
1318 } else {
1319 Bool isFilePack = False;
1321 data = NULL;
1322 if (S_ISDIR(stat_buf.st_mode)
1323 && !(isFilePack = isFilePackage(dentry->d_name))) {
1325 /* access always returns success for user root */
1326 if (access(buffer, X_OK) == 0) {
1327 /* Directory is accesible. Add to directory list */
1329 data = (dir_data *) wmalloc(sizeof(dir_data));
1330 data->name = wstrdup(dentry->d_name);
1331 data->index = i;
1333 WMAddToArray(dirs, data);
1335 } else if (S_ISREG(stat_buf.st_mode) || isFilePack) {
1336 /* Hack because access always returns X_OK success for user root */
1337 #define S_IXANY (S_IXUSR | S_IXGRP | S_IXOTH)
1338 if ((command != NULL && access(buffer, R_OK) == 0) ||
1339 (command == NULL && access(buffer, X_OK) == 0 &&
1340 (stat_buf.st_mode & S_IXANY))) {
1342 data = (dir_data *) wmalloc(sizeof(dir_data));
1343 data->name = wstrdup(dentry->d_name);
1344 data->index = i;
1346 WMAddToArray(files, data);
1350 wfree(buffer);
1353 closedir(dir);
1354 i++;
1357 if (!WMGetArrayItemCount(dirs) && !WMGetArrayItemCount(files)) {
1358 WMFreeArray(dirs);
1359 WMFreeArray(files);
1360 return NULL;
1363 WMSortArray(dirs, myCompare);
1364 WMSortArray(files, myCompare);
1366 menu = wMenuCreate(scr, title, False);
1367 menu->on_destroy = removeShortcutsForMenu;
1369 WM_ITERATE_ARRAY(dirs, data, iter) {
1370 /* New directory. Use same OPEN_MENU command that was used
1371 * for the current directory. */
1372 length = strlen(path[data->index]) + strlen(data->name) + 6;
1373 if (stripExtension)
1374 length += 7;
1375 if (command)
1376 length += strlen(command) + 6;
1377 buffer = malloc(length);
1378 if (!buffer) {
1379 wsyserror(_("out of memory while constructing directory menu %s"), path[data->index]);
1380 break;
1383 buffer[0] = '\0';
1384 if (stripExtension)
1385 strcat(buffer, "-noext ");
1387 have_space = strchr(path[data->index], ' ') != NULL || strchr(data->name, ' ') != NULL;
1389 if (have_space)
1390 strcat(buffer, "\"");
1391 strcat(buffer, path[data->index]);
1393 strcat(buffer, "/");
1394 strcat(buffer, data->name);
1395 if (have_space)
1396 strcat(buffer, "\"");
1397 if (command) {
1398 strcat(buffer, " WITH ");
1399 strcat(buffer, command);
1402 addMenuEntry(menu, data->name, NULL, "OPEN_MENU", buffer, path[data->index]);
1404 wfree(buffer);
1405 if (data->name)
1406 wfree(data->name);
1407 wfree(data);
1410 WM_ITERATE_ARRAY(files, data, iter) {
1411 /* executable: add as entry */
1412 length = strlen(path[data->index]) + strlen(data->name) + 6;
1413 if (command)
1414 length += strlen(command);
1416 buffer = malloc(length);
1417 if (!buffer) {
1418 wsyserror(_("out of memory while constructing directory menu %s"), path[data->index]);
1419 break;
1422 have_space = strchr(path[data->index], ' ') != NULL || strchr(data->name, ' ') != NULL;
1423 if (command != NULL) {
1424 strcpy(buffer, command);
1425 strcat(buffer, " ");
1426 if (have_space)
1427 strcat(buffer, "\"");
1428 strcat(buffer, path[data->index]);
1429 } else {
1430 if (have_space) {
1431 buffer[0] = '"';
1432 buffer[1] = 0;
1433 strcat(buffer, path[data->index]);
1434 } else {
1435 strcpy(buffer, path[data->index]);
1438 strcat(buffer, "/");
1439 strcat(buffer, data->name);
1440 if (have_space)
1441 strcat(buffer, "\"");
1443 if (stripExtension) {
1444 char *ptr = strrchr(data->name, '.');
1445 if (ptr && ptr != data->name)
1446 *ptr = 0;
1448 addMenuEntry(menu, data->name, NULL, "SHEXEC", buffer, path[data->index]);
1450 wfree(buffer);
1451 if (data->name)
1452 wfree(data->name);
1453 wfree(data);
1456 WMFreeArray(files);
1457 WMFreeArray(dirs);
1459 return menu;
1462 /************ Menu Configuration From WMRootMenu *************/
1464 static WMenu *makeDefaultMenu(WScreen * scr)
1466 WMenu *menu = NULL;
1468 menu = wMenuCreate(scr, _("Commands"), True);
1469 wMenuAddCallback(menu, "XTerm", execCommand, "xterm");
1470 wMenuAddCallback(menu, "rxvt", execCommand, "rxvt");
1471 wMenuAddCallback(menu, _("Restart"), restartCommand, NULL);
1472 wMenuAddCallback(menu, _("Exit..."), exitCommand, NULL);
1473 return menu;
1477 *----------------------------------------------------------------------
1478 * configureMenu--
1479 * Reads root menu configuration from defaults database.
1481 *----------------------------------------------------------------------
1483 static WMenu *configureMenu(WScreen * scr, WMPropList * definition)
1485 WMenu *menu = NULL;
1486 WMPropList *elem;
1487 int i, count;
1488 WMPropList *title, *command, *params;
1489 char *tmp, *mtitle;
1491 if (WMIsPLString(definition)) {
1492 struct stat stat_buf;
1493 char *path = NULL;
1494 Bool menu_is_default = False;
1496 /* menu definition is a string. Probably a path, so parse the file */
1498 tmp = wexpandpath(WMGetFromPLString(definition));
1500 path = getLocalizedMenuFile(tmp);
1502 if (!path)
1503 path = wfindfile(DEF_CONFIG_PATHS, tmp);
1505 if (!path) {
1506 path = wfindfile(DEF_CONFIG_PATHS, DEF_MENU_FILE);
1507 menu_is_default = True;
1510 if (!path) {
1511 wsyserror(_("could not find menu file \"%s\" referenced in WMRootMenu"), tmp);
1512 wfree(tmp);
1513 return NULL;
1516 if (stat(path, &stat_buf) < 0) {
1517 wsyserror(_("could not access menu \"%s\" referenced in WMRootMenu"), path);
1518 wfree(path);
1519 wfree(tmp);
1520 return NULL;
1523 if (!scr->root_menu || stat_buf.st_mtime > scr->root_menu->timestamp
1524 /* if the pointer in WMRootMenu has changed */
1525 || WDRootMenu->timestamp > scr->root_menu->timestamp) {
1527 if (menu_is_default) {
1528 wwarning(_
1529 ("using default menu file \"%s\" as the menu referenced in WMRootMenu could not be found "),
1530 path);
1533 menu = readMenuFile(scr, path);
1534 if (menu)
1535 menu->timestamp = WMAX(stat_buf.st_mtime, WDRootMenu->timestamp);
1536 } else {
1537 menu = NULL;
1539 wfree(path);
1540 wfree(tmp);
1542 return menu;
1545 count = WMGetPropListItemCount(definition);
1546 if (count == 0)
1547 return NULL;
1549 elem = WMGetFromPLArray(definition, 0);
1550 if (!WMIsPLString(elem)) {
1551 tmp = WMGetPropListDescription(elem, False);
1552 wwarning(_("%s:format error in root menu configuration \"%s\""), "WMRootMenu", tmp);
1553 wfree(tmp);
1554 return NULL;
1556 mtitle = WMGetFromPLString(elem);
1558 menu = wMenuCreate(scr, mtitle, False);
1559 menu->on_destroy = removeShortcutsForMenu;
1561 #ifdef GLOBAL_SUBMENU_FILE
1563 WMenu *submenu;
1564 WMenuEntry *mentry;
1566 submenu = readMenuFile(scr, GLOBAL_SUBMENU_FILE);
1568 if (submenu) {
1569 mentry = wMenuAddCallback(menu, submenu->frame->title, NULL, NULL);
1570 wMenuEntrySetCascade(menu, mentry, submenu);
1573 #endif
1575 for (i = 1; i < count; i++) {
1576 elem = WMGetFromPLArray(definition, i);
1577 #if 0
1578 if (WMIsPLString(elem)) {
1579 char *file;
1581 file = WMGetFromPLString(elem);
1584 #endif
1585 if (!WMIsPLArray(elem) || WMGetPropListItemCount(elem) < 2)
1586 goto error;
1588 if (WMIsPLArray(WMGetFromPLArray(elem, 1))) {
1589 WMenu *submenu;
1590 WMenuEntry *mentry;
1592 /* submenu */
1593 submenu = configureMenu(scr, elem);
1594 if (submenu) {
1595 mentry = wMenuAddCallback(menu, submenu->frame->title, NULL, NULL);
1596 wMenuEntrySetCascade(menu, mentry, submenu);
1598 } else {
1599 int idx = 0;
1600 WMPropList *shortcut;
1601 /* normal entry */
1603 title = WMGetFromPLArray(elem, idx++);
1604 shortcut = WMGetFromPLArray(elem, idx++);
1605 if (strcmp(WMGetFromPLString(shortcut), "SHORTCUT") == 0) {
1606 shortcut = WMGetFromPLArray(elem, idx++);
1607 command = WMGetFromPLArray(elem, idx++);
1608 } else {
1609 command = shortcut;
1610 shortcut = NULL;
1612 params = WMGetFromPLArray(elem, idx++);
1614 if (!title || !command)
1615 goto error;
1617 addMenuEntry(menu, WMGetFromPLString(title),
1618 shortcut ? WMGetFromPLString(shortcut) : NULL,
1619 WMGetFromPLString(command),
1620 params ? WMGetFromPLString(params) : NULL, "WMRootMenu");
1622 continue;
1624 error:
1625 tmp = WMGetPropListDescription(elem, False);
1626 wwarning(_("%s:format error in root menu configuration \"%s\""), "WMRootMenu", tmp);
1627 wfree(tmp);
1630 return menu;
1634 *----------------------------------------------------------------------
1635 * OpenRootMenu--
1636 * Opens the root menu, parsing the menu configuration from the
1637 * defaults database.
1638 * If the menu is already mapped and is not sticked to the
1639 * root window, it will be unmapped.
1641 * Side effects:
1642 * The menu may be remade.
1644 * Notes:
1645 * Construction of OPEN_MENU entries are delayed to the moment the
1646 * user map's them.
1647 *----------------------------------------------------------------------
1649 void OpenRootMenu(WScreen * scr, int x, int y, int keyboard)
1651 WMenu *menu = NULL;
1652 WMPropList *definition;
1654 static WMPropList *domain=NULL;
1656 if (!domain) {
1657 domain = WMCreatePLString("WMRootMenu");
1661 scr->flags.root_menu_changed_shortcuts = 0;
1662 scr->flags.added_workspace_menu = 0;
1663 scr->flags.added_windows_menu = 0;
1665 if (scr->root_menu && scr->root_menu->flags.mapped) {
1666 menu = scr->root_menu;
1667 if (!menu->flags.buttoned) {
1668 wMenuUnmap(menu);
1669 } else {
1670 wRaiseFrame(menu->frame->core);
1672 if (keyboard)
1673 wMenuMapAt(menu, 0, 0, True);
1674 else
1675 wMenuMapCopyAt(menu, x - menu->frame->core->width / 2, y);
1677 return;
1680 definition = WDRootMenu->dictionary;
1683 definition = PLGetDomain(domain);
1685 if (definition) {
1686 if (WMIsPLArray(definition)) {
1687 if (!scr->root_menu || WDRootMenu->timestamp > scr->root_menu->timestamp) {
1688 menu = configureMenu(scr, definition);
1689 if (menu)
1690 menu->timestamp = WDRootMenu->timestamp;
1692 } else
1693 menu = NULL;
1694 } else {
1695 menu = configureMenu(scr, definition);
1699 if (!menu) {
1700 /* menu hasn't changed or could not be read */
1701 if (!scr->root_menu) {
1702 wMessageDialog(scr, _("Error"),
1703 _("The applications menu could not be loaded. "
1704 "Look at the console output for a detailed "
1705 "description of the errors."), _("OK"), NULL, NULL);
1707 menu = makeDefaultMenu(scr);
1708 scr->root_menu = menu;
1710 menu = scr->root_menu;
1711 } else {
1712 /* new root menu */
1713 if (scr->root_menu) {
1714 wMenuDestroy(scr->root_menu, True);
1716 scr->root_menu = menu;
1718 if (menu) {
1719 int newx, newy;
1721 if (keyboard && x == 0 && y == 0) {
1722 newx = newy = 0;
1723 } else if (keyboard && x == scr->scr_width / 2 && y == scr->scr_height / 2) {
1724 newx = x - menu->frame->core->width / 2;
1725 newy = y - menu->frame->core->height / 2;
1726 } else {
1727 newx = x - menu->frame->core->width / 2;
1728 newy = y;
1730 wMenuMapAt(menu, newx, newy, keyboard);
1733 if (scr->flags.root_menu_changed_shortcuts)
1734 rebindKeygrabs(scr);