Fix compiler warning from menu.c
[wmaker-crm.git] / src / rootmenu.c
blobd3d5b74482c5a6c71a445b34ba3607c42ccf524b
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
7 * Copyright (c) 2014 Window Maker Team
9 * This program is free software; you can redistribute it and/or modify
10 * it under the terms of the GNU General Public License as published by
11 * the Free Software Foundation; either version 2 of the License, or
12 * (at your option) any later version.
14 * This program is distributed in the hope that it will be useful,
15 * but WITHOUT ANY WARRANTY; without even the implied warranty of
16 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17 * GNU General Public License for more details.
19 * You should have received a copy of the GNU General Public License along
20 * with this program; if not, write to the Free Software Foundation, Inc.,
21 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 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 <strings.h>
34 #include <ctype.h>
35 #include <time.h>
36 #include <dirent.h>
37 #include <errno.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 "misc.h"
47 #include "main.h"
48 #include "dialog.h"
49 #include "keybind.h"
50 #include "stacking.h"
51 #include "workspace.h"
52 #include "defaults.h"
53 #include "framewin.h"
54 #include "session.h"
55 #include "shutdown.h"
56 #include "xmodifier.h"
57 #include "rootmenu.h"
58 #include "startup.h"
59 #include "switchmenu.h"
61 #include <WINGs/WUtil.h>
63 #define MAX_SHORTCUT_LENGTH 32
65 static WMenu *readMenuPipe(WScreen * scr, char **file_name);
66 static WMenu *readPLMenuPipe(WScreen * scr, char **file_name);
67 static WMenu *readMenuFile(WScreen *scr, const char *file_name);
68 static WMenu *readMenuDirectory(WScreen *scr, const char *title, char **file_name, const char *command);
69 static void menu_parser_register_macros(WMenuParser parser);
71 typedef struct Shortcut {
72 struct Shortcut *next;
74 int modifier;
75 KeyCode keycode;
76 WMenuEntry *entry;
77 WMenu *menu;
78 } Shortcut;
80 static Shortcut *shortcutList = NULL;
83 * Syntax:
84 * # main menu
85 * "Menu Name" MENU
86 * "Title" EXEC command_to_exec -params
87 * "Submenu" MENU
88 * "Title" EXEC command_to_exec -params
89 * "Submenu" END
90 * "Workspaces" WORKSPACE_MENU
91 * "Title" built_in_command
92 * "Quit" EXIT
93 * "Quick Quit" EXIT QUICK
94 * "Menu Name" END
96 * Commands may be preceded by SHORTCUT key
98 * Built-in commands:
100 * INFO_PANEL - shows the Info Panel
101 * LEGAL_PANEL - shows the Legal info panel
102 * SHUTDOWN [QUICK] - closes the X server [without confirmation]
103 * REFRESH - forces the desktop to be repainted
104 * EXIT [QUICK] - exit the window manager [without confirmation]
105 * EXEC <program> - execute an external program
106 * SHEXEC <command> - execute a shell command
107 * WORKSPACE_MENU - places the workspace submenu
108 * ARRANGE_ICONS
109 * RESTART [<window manager>] - restarts the window manager
110 * SHOW_ALL - unhide all windows on workspace
111 * HIDE_OTHERS - hides all windows excep the focused one
112 * OPEN_MENU file - read menu data from file which must be a valid menu file.
113 * OPEN_MENU /some/dir [/some/other/dir ...] [WITH command -options]
114 * - read menu data from directory(ies) and
115 * eventually precede each with a command.
116 * OPEN_MENU | command
117 * - opens command and uses its stdout to construct and insert
118 * the resulting menu in current position. The output of
119 * command must be a valid menu description.
120 * The space between '|' and command is optional.
121 * || will do the same, but will not cache the contents.
122 * OPEN_PLMENU | command
123 * - opens command and uses its stdout which must be in proplist
124 * fromat to construct and insert the resulting menu in current
125 * position.
126 * The space between '|' and command is optional.
127 * || will do the same, but will not cache the contents.
128 * SAVE_SESSION - saves the current state of the desktop, which include
129 * all running applications, all their hints (geometry,
130 * position on screen, workspace they live on, the dock
131 * or clip from where they were launched, and
132 * if minimized, shaded or hidden. Also saves the current
133 * workspace the user is on. All will be restored on every
134 * start of windowmaker until another SAVE_SESSION or
135 * CLEAR_SESSION is used. If SaveSessionOnExit = Yes; in
136 * WindowMaker domain file, then saving is automatically
137 * done on every windowmaker exit, overwriting any
138 * SAVE_SESSION or CLEAR_SESSION (see below). Also save
139 * dock state now.
140 * CLEAR_SESSION - clears any previous saved session. This will not have
141 * any effect if SaveSessionOnExit is True.
145 /* menu commands */
147 static void execCommand(WMenu * menu, WMenuEntry * entry)
149 ExecuteInputCommand(menu->frame->screen_ptr, (char *)entry->clientdata);
152 static void exitCommand(WMenu * menu, WMenuEntry * entry)
154 ExecuteExitCommand(menu->frame->screen_ptr, (long)entry->clientdata);
158 static void shutdownCommand(WMenu * menu, WMenuEntry * entry)
160 static int inside = 0;
161 int result;
163 /* prevent reentrant calls */
164 if (inside)
165 return;
166 inside = 1;
168 #define R_CANCEL 0
169 #define R_CLOSE 1
170 #define R_KILL 2
172 result = R_CANCEL;
173 if ((long)entry->clientdata == M_QUICK)
174 result = R_CLOSE;
175 else {
176 int r, oldSaveSessionFlag;
178 oldSaveSessionFlag = wPreferences.save_session_on_exit;
180 r = wExitDialog(menu->frame->screen_ptr,
181 _("Kill X session"),
182 _("Kill Window System session?\n"
183 "(all applications will be closed)"), _("Kill"), _("Cancel"), NULL);
184 if (r == WAPRDefault) {
185 result = R_KILL;
186 } else if (r == WAPRAlternate) {
187 /* Don't modify the "save session on exit" flag if the
188 * user canceled the operation. */
189 wPreferences.save_session_on_exit = oldSaveSessionFlag;
193 if (result != R_CANCEL) {
194 Shutdown(WSKillMode);
196 #undef R_CLOSE
197 #undef R_CANCEL
198 #undef R_KILL
199 inside = 0;
202 static void restartCommand(WMenu * menu, WMenuEntry * entry)
204 /* Parameter not used, but tell the compiler that it is ok */
205 (void) menu;
206 (void) entry;
208 Shutdown(WSRestartPreparationMode);
209 Restart((char *)entry->clientdata, False);
210 Restart(NULL, True);
213 static void refreshCommand(WMenu * menu, WMenuEntry * entry)
215 /* Parameter not used, but tell the compiler that it is ok */
216 (void) entry;
218 wRefreshDesktop(menu->frame->screen_ptr);
221 static void arrangeIconsCommand(WMenu * menu, WMenuEntry * entry)
223 /* Parameter not used, but tell the compiler that it is ok */
224 (void) entry;
226 wArrangeIcons(menu->frame->screen_ptr, True);
229 static void showAllCommand(WMenu * menu, WMenuEntry * entry)
231 /* Parameter not used, but tell the compiler that it is ok */
232 (void) entry;
234 wShowAllWindows(menu->frame->screen_ptr);
237 static void hideOthersCommand(WMenu * menu, WMenuEntry * entry)
239 /* Parameter not used, but tell the compiler that it is ok */
240 (void) entry;
242 wHideOtherApplications(menu->frame->screen_ptr->focused_window);
245 static void saveSessionCommand(WMenu * menu, WMenuEntry * entry)
247 /* Parameter not used, but tell the compiler that it is ok */
248 (void) entry;
250 if (!wPreferences.save_session_on_exit)
251 wSessionSaveState(menu->frame->screen_ptr);
253 wScreenSaveState(menu->frame->screen_ptr);
256 static void clearSessionCommand(WMenu * menu, WMenuEntry * entry)
258 /* Parameter not used, but tell the compiler that it is ok */
259 (void) entry;
261 wSessionClearState(menu->frame->screen_ptr);
262 wScreenSaveState(menu->frame->screen_ptr);
265 static void infoPanelCommand(WMenu * menu, WMenuEntry * entry)
267 /* Parameter not used, but tell the compiler that it is ok */
268 (void) entry;
270 wShowInfoPanel(menu->frame->screen_ptr);
273 static void legalPanelCommand(WMenu * menu, WMenuEntry * entry)
275 /* Parameter not used, but tell the compiler that it is ok */
276 (void) entry;
278 wShowLegalPanel(menu->frame->screen_ptr);
281 /********************************************************************/
283 static char *getLocalizedMenuFile(const char *menu)
285 char *buffer, *ptr, *locale;
286 int len;
288 if (!w_global.locale)
289 return NULL;
291 len = strlen(menu) + strlen(w_global.locale) + 8;
292 buffer = wmalloc(len);
294 /* try menu.locale_name */
295 snprintf(buffer, len, "%s.%s", menu, w_global.locale);
296 if (access(buffer, F_OK) == 0)
297 return buffer;
299 /* position of locale in our buffer */
300 locale = buffer + strlen(menu) + 1;
302 /* check if it is in the form aa_bb.encoding and check for aa_bb */
303 ptr = strchr(locale, '.');
304 if (ptr) {
305 *ptr = 0;
306 if (access(buffer, F_OK) == 0)
307 return buffer;
310 /* now check for aa */
311 ptr = strchr(locale, '_');
312 if (ptr) {
313 *ptr = 0;
314 if (access(buffer, F_OK) == 0)
315 return buffer;
318 wfree(buffer);
320 return NULL;
323 Bool wRootMenuPerformShortcut(XEvent * event)
325 WScreen *scr = wScreenForRootWindow(event->xkey.root);
326 Shortcut *ptr;
327 int modifiers;
328 int done = 0;
330 /* ignore CapsLock */
331 modifiers = event->xkey.state & w_global.shortcut.modifiers_mask;
333 for (ptr = shortcutList; ptr != NULL; ptr = ptr->next) {
334 if (ptr->keycode == 0 || ptr->menu->menu->screen_ptr != scr)
335 continue;
337 if (ptr->keycode == event->xkey.keycode && ptr->modifier == modifiers) {
338 (*ptr->entry->callback) (ptr->menu, ptr->entry);
339 done = True;
343 return done;
346 void wRootMenuBindShortcuts(Window window)
348 Shortcut *ptr;
350 ptr = shortcutList;
351 while (ptr) {
352 if (ptr->modifier != AnyModifier) {
353 XGrabKey(dpy, ptr->keycode, ptr->modifier | LockMask,
354 window, True, GrabModeAsync, GrabModeAsync);
355 #ifdef NUMLOCK_HACK
356 wHackedGrabKey(ptr->keycode, ptr->modifier, window, True, GrabModeAsync, GrabModeAsync);
357 #endif
359 XGrabKey(dpy, ptr->keycode, ptr->modifier, window, True, GrabModeAsync, GrabModeAsync);
360 ptr = ptr->next;
364 static void rebindKeygrabs(WScreen * scr)
366 WWindow *wwin;
368 wwin = scr->focused_window;
370 while (wwin != NULL) {
371 XUngrabKey(dpy, AnyKey, AnyModifier, wwin->frame->core->window);
373 if (!WFLAGP(wwin, no_bind_keys)) {
374 wWindowSetKeyGrabs(wwin);
376 wwin = wwin->prev;
380 static void removeShortcutsForMenu(WMenu * menu)
382 Shortcut *ptr, *tmp;
383 Shortcut *newList = NULL;
385 ptr = shortcutList;
386 while (ptr != NULL) {
387 tmp = ptr->next;
388 if (ptr->menu == menu) {
389 wfree(ptr);
390 } else {
391 ptr->next = newList;
392 newList = ptr;
394 ptr = tmp;
396 shortcutList = newList;
397 menu->menu->screen_ptr->flags.root_menu_changed_shortcuts = 1;
400 static Bool addShortcut(const char *file, const char *shortcutDefinition, WMenu *menu, WMenuEntry *entry)
402 Shortcut *ptr;
403 KeySym ksym;
404 char *k;
405 char buf[MAX_SHORTCUT_LENGTH], *b;
407 ptr = wmalloc(sizeof(Shortcut));
409 wstrlcpy(buf, shortcutDefinition, MAX_SHORTCUT_LENGTH);
410 b = (char *)buf;
412 /* get modifiers */
413 ptr->modifier = 0;
414 while ((k = strchr(b, '+')) != NULL) {
415 int mod;
417 *k = 0;
418 mod = wXModifierFromKey(b);
419 if (mod < 0) {
420 wwarning(_("%s: invalid key modifier \"%s\""), file, b);
421 wfree(ptr);
422 return False;
424 ptr->modifier |= mod;
426 b = k + 1;
429 /* get key */
430 ksym = XStringToKeysym(b);
432 if (ksym == NoSymbol) {
433 wwarning(_("%s:invalid kbd shortcut specification \"%s\" for entry %s"),
434 file, shortcutDefinition, entry->text);
435 wfree(ptr);
436 return False;
439 ptr->keycode = XKeysymToKeycode(dpy, ksym);
440 if (ptr->keycode == 0) {
441 wwarning(_("%s:invalid key in shortcut \"%s\" for entry %s"), file,
442 shortcutDefinition, entry->text);
443 wfree(ptr);
444 return False;
447 ptr->menu = menu;
448 ptr->entry = entry;
450 ptr->next = shortcutList;
451 shortcutList = ptr;
453 menu->menu->screen_ptr->flags.root_menu_changed_shortcuts = 1;
455 return True;
458 static char *next_token(char *line, char **next)
460 char *tmp, c;
461 char *ret;
463 *next = NULL;
464 while (*line == ' ' || *line == '\t')
465 line++;
467 tmp = line;
469 if (*tmp == '"') {
470 tmp++;
471 line++;
472 while (*tmp != 0 && *tmp != '"')
473 tmp++;
474 if (*tmp != '"') {
475 wwarning(_("%s: unmatched '\"' in menu file"), line);
476 return NULL;
478 } else {
479 do {
480 if (*tmp == '\\')
481 tmp++;
483 if (*tmp != 0)
484 tmp++;
486 } while (*tmp != 0 && *tmp != ' ' && *tmp != '\t');
489 c = *tmp;
490 *tmp = 0;
491 ret = wstrdup(line);
492 *tmp = c;
494 if (c == 0)
495 return ret;
496 else
497 tmp++;
499 /* skip blanks */
500 while (*tmp == ' ' || *tmp == '\t')
501 tmp++;
503 if (*tmp != 0)
504 *next = tmp;
506 return ret;
509 static void separateCommand(char *line, char ***file, char **command)
511 char *token, *tmp = line;
512 WMArray *array = WMCreateArray(4);
513 int count, i;
515 *file = NULL;
516 *command = NULL;
517 do {
518 token = next_token(tmp, &tmp);
519 if (token) {
520 if (strcmp(token, "WITH") == 0) {
521 if (tmp != NULL && *tmp != 0)
522 *command = wstrdup(tmp);
523 else
524 wwarning(_("%s: missing command"), line);
525 wfree(token);
526 break;
528 WMAddToArray(array, token);
530 } while (token != NULL && tmp != NULL);
532 count = WMGetArrayItemCount(array);
533 if (count > 0) {
534 *file = wmalloc(sizeof(char *) * (count + 1));
535 (*file)[count] = NULL;
536 for (i = 0; i < count; i++) {
537 (*file)[i] = WMGetFromArray(array, i);
540 WMFreeArray(array);
543 static WMenu *constructPLMenu(WScreen *screen, const char *path)
545 WMPropList *pl = NULL;
546 WMenu *menu = NULL;
548 if (!path)
549 return NULL;
551 pl = WMReadPropListFromFile(path);
552 if (!pl)
553 return NULL;
555 menu = configureMenu(screen, pl);
557 WMReleasePropList(pl);
559 if (!menu)
560 return NULL;
562 menu->on_destroy = removeShortcutsForMenu;
563 return menu;
568 static void constructMenu(WMenu * menu, WMenuEntry * entry)
570 WMenu *submenu;
571 struct stat stat_buf;
572 char **path;
573 char *cmd;
574 char *lpath = NULL;
575 int i, first = -1;
576 time_t last = 0;
578 separateCommand((char *)entry->clientdata, &path, &cmd);
579 if (path == NULL || *path == NULL || **path == 0) {
580 wwarning(_("invalid OPEN_MENU specification: %s"), (char *)entry->clientdata);
581 if (path) {
582 for (i = 0; path[i] != NULL; i++)
583 wfree(path[i]);
584 wfree(path);
586 if (cmd)
587 wfree(cmd);
588 return;
591 if (path[0][0] == '|') {
592 /* pipe menu */
594 if (!menu->cascades[entry->cascade] || menu->cascades[entry->cascade]->timestamp == 0) {
595 /* parse pipe */
597 submenu = readMenuPipe(menu->frame->screen_ptr, path);
599 if (submenu != NULL) {
600 if (path[0][1] == '|')
601 submenu->timestamp = 0;
602 else
603 submenu->timestamp = 1; /* there's no automatic reloading */
605 } else {
606 submenu = NULL;
609 } else {
611 /* try interpreting path as a proplist file */
612 submenu = constructPLMenu(menu->frame->screen_ptr, path[0]);
613 /* if unsuccessful, try it as an old-style file */
614 if (!submenu) {
616 i = 0;
617 while (path[i] != NULL) {
618 char *tmp;
620 if (strcmp(path[i], "-noext") == 0) {
621 i++;
622 continue;
625 tmp = wexpandpath(path[i]);
627 if (strstr(tmp, "#usergnusteppath#") == tmp) {
628 char *old_tmp = tmp;
630 tmp = wstrconcat(wusergnusteppath(),
631 tmp + 17);
632 wfree(old_tmp);
635 wfree(path[i]);
636 lpath = getLocalizedMenuFile(tmp);
637 if (lpath) {
638 wfree(tmp);
639 path[i] = lpath;
640 lpath = NULL;
641 } else {
642 path[i] = tmp;
645 if (stat(path[i], &stat_buf) == 0) {
646 if (last < stat_buf.st_mtime)
647 last = stat_buf.st_mtime;
648 if (first < 0)
649 first = i;
650 } else {
651 werror(_("%s:could not stat menu"), path[i]);
652 /*goto finish; */
655 i++;
658 if (first < 0) {
659 werror(_("%s:could not stat menu:%s"), "OPEN_MENU", (char *)entry->clientdata);
660 goto finish;
662 stat(path[first], &stat_buf);
663 if (!menu->cascades[entry->cascade]
664 || menu->cascades[entry->cascade]->timestamp < last) {
666 if (S_ISDIR(stat_buf.st_mode)) {
667 /* menu directory */
668 submenu = readMenuDirectory(menu->frame->screen_ptr, entry->text, path, cmd);
669 if (submenu)
670 submenu->timestamp = last;
671 } else if (S_ISREG(stat_buf.st_mode)) {
672 /* menu file */
674 if (cmd || path[1])
675 wwarning(_("too many parameters in OPEN_MENU: %s"),
676 (char *)entry->clientdata);
678 submenu = readMenuFile(menu->frame->screen_ptr, path[first]);
679 if (submenu)
680 submenu->timestamp = stat_buf.st_mtime;
681 } else {
682 submenu = NULL;
684 } else {
685 submenu = NULL;
690 if (submenu) {
691 wMenuEntryRemoveCascade(menu, entry);
692 wMenuEntrySetCascade(menu, entry, submenu);
695 finish:
696 i = 0;
697 while (path[i] != NULL)
698 wfree(path[i++]);
699 wfree(path);
700 if (cmd)
701 wfree(cmd);
704 static void constructPLMenuFromPipe(WMenu * menu, WMenuEntry * entry)
706 WMenu *submenu = NULL;
707 char **path;
708 char *cmd;
709 int i;
711 separateCommand((char *)entry->clientdata, &path, &cmd);
712 if (path == NULL || *path == NULL || **path == 0) {
713 wwarning(_("invalid OPEN_PLMENU specification: %s"),
714 (char *)entry->clientdata);
715 if (path) {
716 for (i = 0; path[i] != NULL; i++)
717 wfree(path[i]);
718 wfree(path);
720 if (cmd)
721 wfree(cmd);
722 return;
725 if (path[0][0] == '|') {
726 /* pipe menu */
728 if (!menu->cascades[entry->cascade]
729 || menu->cascades[entry->cascade]->timestamp == 0) {
730 /* parse pipe */
731 submenu = readPLMenuPipe(menu->frame->screen_ptr, path);
733 if (submenu != NULL) {
734 if (path[0][1] == '|')
735 submenu->timestamp = 0;
736 else
737 submenu->timestamp = 1; /* there's no automatic reloading */
742 if (submenu) {
743 wMenuEntryRemoveCascade(menu, entry);
744 wMenuEntrySetCascade(menu, entry, submenu);
747 i = 0;
748 while (path[i] != NULL)
749 wfree(path[i++]);
751 wfree(path);
752 if (cmd)
753 wfree(cmd);
756 static void cleanupWorkspaceMenu(WMenu *menu)
758 if (menu->frame->screen_ptr->workspace_menu == menu)
759 menu->frame->screen_ptr->workspace_menu = NULL;
762 static WMenuEntry *addWorkspaceMenu(WScreen *scr, WMenu *menu, const char *title)
764 WMenu *wsmenu;
765 WMenuEntry *entry;
767 if (scr->flags.added_workspace_menu) {
768 wwarning(_
769 ("There are more than one WORKSPACE_MENU commands in the applications menu. Only one is allowed."));
770 return NULL;
771 } else {
772 scr->flags.added_workspace_menu = 1;
774 wsmenu = wWorkspaceMenuMake(scr, True);
775 wsmenu->on_destroy = cleanupWorkspaceMenu;
777 scr->workspace_menu = wsmenu;
778 entry = wMenuAddCallback(menu, title, NULL, NULL);
779 wMenuEntrySetCascade(menu, entry, wsmenu);
781 wWorkspaceMenuUpdate(scr, wsmenu);
783 return entry;
786 static void cleanupWindowsMenu(WMenu * menu)
788 if (menu->frame->screen_ptr->switch_menu == menu)
789 menu->frame->screen_ptr->switch_menu = NULL;
792 static WMenuEntry *addWindowsMenu(WScreen *scr, WMenu *menu, const char *title)
794 WMenu *wwmenu;
795 WWindow *wwin;
796 WMenuEntry *entry;
798 if (scr->flags.added_windows_menu) {
799 wwarning(_
800 ("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;
820 static WMenuEntry *addMenuEntry(WMenu *menu, const char *title, const char *shortcut, const char *command,
821 const char *params, const char *file_name)
823 WScreen *scr;
824 WMenuEntry *entry = NULL;
825 Bool shortcutOk = False;
827 if (!menu)
828 return NULL;
829 scr = menu->frame->screen_ptr;
830 if (strcmp(command, "OPEN_MENU") == 0) {
831 if (!params) {
832 wwarning(_("%s:missing parameter for menu command \"%s\""), file_name, command);
833 } else {
834 WMenu *dummy;
835 char *path;
837 path = wfindfile(DEF_CONFIG_PATHS, params);
838 if (!path) {
839 path = wstrdup(params);
841 dummy = wMenuCreate(scr, title, False);
842 dummy->on_destroy = removeShortcutsForMenu;
843 entry = wMenuAddCallback(menu, title, constructMenu, path);
844 entry->free_cdata = wfree;
845 wMenuEntrySetCascade(menu, entry, dummy);
847 } else if (strcmp(command, "OPEN_PLMENU") == 0) {
848 if (!params) {
849 wwarning(_("%s:missing parameter for menu command \"%s\""), file_name, command);
850 } else {
851 WMenu *dummy;
852 char *path;
854 path = wfindfile(DEF_CONFIG_PATHS, params);
855 if (!path)
856 path = wstrdup(params);
858 dummy = wMenuCreate(scr, title, False);
859 dummy->on_destroy = removeShortcutsForMenu;
860 entry = wMenuAddCallback(menu, title, constructPLMenuFromPipe, path);
861 entry->free_cdata = wfree;
862 wMenuEntrySetCascade(menu, entry, dummy);
864 } else if (strcmp(command, "EXEC") == 0) {
865 if (!params)
866 wwarning(_("%s:missing parameter for menu command \"%s\""), file_name, command);
867 else {
868 entry = wMenuAddCallback(menu, title, execCommand, wstrconcat("exec ", params));
869 entry->free_cdata = wfree;
870 shortcutOk = True;
872 } else if (strcmp(command, "SHEXEC") == 0) {
873 if (!params)
874 wwarning(_("%s:missing parameter for menu command \"%s\""), file_name, command);
875 else {
876 entry = wMenuAddCallback(menu, title, execCommand, wstrdup(params));
877 entry->free_cdata = wfree;
878 shortcutOk = True;
880 } else if (strcmp(command, "EXIT") == 0) {
882 if (params && strcmp(params, "QUICK") == 0)
883 entry = wMenuAddCallback(menu, title, exitCommand, (void *)M_QUICK);
884 else
885 entry = wMenuAddCallback(menu, title, exitCommand, NULL);
887 shortcutOk = True;
888 } else if (strcmp(command, "SHUTDOWN") == 0) {
890 if (params && strcmp(params, "QUICK") == 0)
891 entry = wMenuAddCallback(menu, title, shutdownCommand, (void *)M_QUICK);
892 else
893 entry = wMenuAddCallback(menu, title, shutdownCommand, NULL);
895 shortcutOk = True;
896 } else if (strcmp(command, "REFRESH") == 0) {
897 entry = wMenuAddCallback(menu, title, refreshCommand, NULL);
899 shortcutOk = True;
900 } else if (strcmp(command, "WORKSPACE_MENU") == 0) {
901 entry = addWorkspaceMenu(scr, menu, title);
903 shortcutOk = True;
904 } else if (strcmp(command, "WINDOWS_MENU") == 0) {
905 entry = addWindowsMenu(scr, menu, title);
907 shortcutOk = True;
908 } else if (strcmp(command, "ARRANGE_ICONS") == 0) {
909 entry = wMenuAddCallback(menu, title, arrangeIconsCommand, NULL);
911 shortcutOk = True;
912 } else if (strcmp(command, "HIDE_OTHERS") == 0) {
913 entry = wMenuAddCallback(menu, title, hideOthersCommand, NULL);
915 shortcutOk = True;
916 } else if (strcmp(command, "SHOW_ALL") == 0) {
917 entry = wMenuAddCallback(menu, title, showAllCommand, NULL);
919 shortcutOk = True;
920 } else if (strcmp(command, "RESTART") == 0) {
921 entry = wMenuAddCallback(menu, title, restartCommand, params ? wstrdup(params) : NULL);
922 entry->free_cdata = wfree;
923 shortcutOk = True;
924 } else if (strcmp(command, "SAVE_SESSION") == 0) {
925 entry = wMenuAddCallback(menu, title, saveSessionCommand, NULL);
927 shortcutOk = True;
928 } else if (strcmp(command, "CLEAR_SESSION") == 0) {
929 entry = wMenuAddCallback(menu, title, clearSessionCommand, NULL);
930 shortcutOk = True;
931 } else if (strcmp(command, "INFO_PANEL") == 0) {
932 entry = wMenuAddCallback(menu, title, infoPanelCommand, NULL);
933 shortcutOk = True;
934 } else if (strcmp(command, "LEGAL_PANEL") == 0) {
935 entry = wMenuAddCallback(menu, title, legalPanelCommand, NULL);
936 shortcutOk = True;
937 } else {
938 wwarning(_("%s:unknown command \"%s\" in menu config."), file_name, command);
940 return NULL;
943 if (shortcut && entry) {
944 if (!shortcutOk) {
945 wwarning(_("%s:can't add shortcut for entry \"%s\""), file_name, title);
946 } else {
947 if (addShortcut(file_name, shortcut, menu, entry)) {
949 entry->rtext = GetShortcutString(shortcut);
951 entry->rtext = wstrdup(shortcut);
957 return entry;
960 /******************* Menu Configuration From File *******************/
962 static void freeline(char *title, char *command, char *parameter, char *shortcut)
964 wfree(title);
965 wfree(command);
966 wfree(parameter);
967 wfree(shortcut);
970 static WMenu *parseCascade(WScreen * scr, WMenu * menu, WMenuParser parser)
972 char *command, *params, *shortcut, *title;
974 while (WMenuParserGetLine(parser, &title, &command, &params, &shortcut)) {
976 if (command == NULL || !command[0]) {
977 WMenuParserError(parser, _("missing command in menu config") );
978 freeline(title, command, params, shortcut);
979 goto error;
982 if (strcasecmp(command, "MENU") == 0) {
983 WMenu *cascade;
985 /* start submenu */
987 cascade = wMenuCreate(scr, M_(title), False);
988 cascade->on_destroy = removeShortcutsForMenu;
989 if (!parseCascade(scr, cascade, parser)) {
990 wMenuDestroy(cascade, True);
991 } else {
992 wMenuEntrySetCascade(menu, wMenuAddCallback(menu, M_(title), NULL, NULL), cascade);
994 } else if (strcasecmp(command, "END") == 0) {
995 /* end of menu */
996 freeline(title, command, params, shortcut);
997 return menu;
998 } else {
999 /* normal items */
1000 addMenuEntry(menu, M_(title), shortcut, command, params, WMenuParserGetFilename(parser));
1002 freeline(title, command, params, shortcut);
1005 WMenuParserError(parser, _("syntax error in menu file: END declaration missing") );
1007 error:
1008 return NULL;
1011 static WMenu *readMenu(WScreen *scr, const char *flat_file, FILE *file)
1013 WMenu *menu = NULL;
1014 WMenuParser parser;
1015 char *title, *command, *params, *shortcut;
1017 parser = WMenuParserCreate(flat_file, file, DEF_CONFIG_PATHS);
1018 menu_parser_register_macros(parser);
1020 while (WMenuParserGetLine(parser, &title, &command, &params, &shortcut)) {
1022 if (command == NULL || !command[0]) {
1023 WMenuParserError(parser, _("missing command in menu config") );
1024 freeline(title, command, params, shortcut);
1025 break;
1027 if (strcasecmp(command, "MENU") == 0) {
1028 menu = wMenuCreate(scr, M_(title), True);
1029 menu->on_destroy = removeShortcutsForMenu;
1030 if (!parseCascade(scr, menu, parser)) {
1031 wMenuDestroy(menu, True);
1032 menu = NULL;
1034 freeline(title, command, params, shortcut);
1035 break;
1036 } else {
1037 WMenuParserError(parser, _("invalid menu, no menu title given") );
1038 freeline(title, command, params, shortcut);
1039 break;
1042 freeline(title, command, params, shortcut);
1045 WMenuParserDelete(parser);
1046 return menu;
1049 static WMenu *readMenuFile(WScreen *scr, const char *file_name)
1051 WMenu *menu = NULL;
1052 FILE *file = NULL;
1054 file = fopen(file_name, "rb");
1055 if (!file) {
1056 werror(_("could not open menu file \"%s\": %s"), file_name, strerror(errno));
1057 return NULL;
1059 menu = readMenu(scr, file_name, file);
1060 fclose(file);
1062 return menu;
1065 static inline int generate_command_from_list(char *buffer, size_t buffer_size, char **command_elements)
1067 char *rd;
1068 int wr_idx;
1069 int i;
1071 wr_idx = 0;
1072 for (i = 0; command_elements[i] != NULL; i++) {
1074 if (i > 0)
1075 if (wr_idx < buffer_size - 1)
1076 buffer[wr_idx++] = ' ';
1078 for (rd = command_elements[i]; *rd != '\0'; rd++) {
1079 if (wr_idx < buffer_size - 1)
1080 buffer[wr_idx++] = *rd;
1081 else
1082 return 1;
1085 buffer[wr_idx] = '\0';
1086 return 0;
1089 /************ Menu Configuration From Pipe *************/
1090 static WMenu *readPLMenuPipe(WScreen * scr, char **file_name)
1092 WMPropList *plist = NULL;
1093 WMenu *menu = NULL;
1094 char *filename;
1095 char flat_file[MAXLINE];
1097 if (generate_command_from_list(flat_file, sizeof(flat_file), file_name)) {
1098 werror(_("could not open menu file \"%s\": %s"),
1099 file_name[0], _("pipe command for PropertyList is too long"));
1100 return NULL;
1102 filename = flat_file + (flat_file[1] == '|' ? 2 : 1);
1104 plist = WMReadPropListFromPipe(filename);
1106 if (!plist)
1107 return NULL;
1109 menu = configureMenu(scr, plist);
1111 WMReleasePropList(plist);
1113 if (!menu)
1114 return NULL;
1116 menu->on_destroy = removeShortcutsForMenu;
1117 return menu;
1120 static WMenu *readMenuPipe(WScreen * scr, char **file_name)
1122 WMenu *menu = NULL;
1123 FILE *file = NULL;
1124 char *filename;
1125 char flat_file[MAXLINE];
1127 if (generate_command_from_list(flat_file, sizeof(flat_file), file_name)) {
1128 werror(_("could not open menu file \"%s\": %s"),
1129 file_name[0], _("pipe command is too long"));
1130 return NULL;
1132 filename = flat_file + (flat_file[1] == '|' ? 2 : 1);
1135 * In case of memory problem, 'popen' will not set the errno, so we initialise it
1136 * to be able to display a meaningful message. For other problems, 'popen' will
1137 * properly set errno, so we'll still get a good message
1139 errno = ENOMEM;
1140 file = popen(filename, "r");
1141 if (!file) {
1142 werror(_("could not open menu file \"%s\": %s"), filename, strerror(errno));
1143 return NULL;
1145 menu = readMenu(scr, flat_file, file);
1146 pclose(file);
1148 return menu;
1151 typedef struct {
1152 char *name;
1153 int index;
1154 } dir_data;
1156 static int myCompare(const void *d1, const void *d2)
1158 dir_data *p1 = *(dir_data **) d1;
1159 dir_data *p2 = *(dir_data **) d2;
1161 return strcmp(p1->name, p2->name);
1164 /***** Preset some macro for file parser *****/
1165 static void menu_parser_register_macros(WMenuParser parser)
1167 Visual *visual;
1168 char buf[32];
1170 // Used to return CPP verion, now returns wmaker's version
1171 WMenuParserRegisterSimpleMacro(parser, "__VERSION__", VERSION);
1173 // All macros below were historically defined by WindowMaker
1174 visual = DefaultVisual(dpy, DefaultScreen(dpy));
1175 snprintf(buf, sizeof(buf), "%d", visual->class);
1176 WMenuParserRegisterSimpleMacro(parser, "VISUAL", buf);
1178 snprintf(buf, sizeof(buf), "%d", DefaultDepth(dpy, DefaultScreen(dpy)) );
1179 WMenuParserRegisterSimpleMacro(parser, "DEPTH", buf);
1181 snprintf(buf, sizeof(buf), "%d", WidthOfScreen(DefaultScreenOfDisplay(dpy)) );
1182 WMenuParserRegisterSimpleMacro(parser, "SCR_WIDTH", buf);
1184 snprintf(buf, sizeof(buf), "%d", HeightOfScreen(DefaultScreenOfDisplay(dpy)) );
1185 WMenuParserRegisterSimpleMacro(parser, "SCR_HEIGHT", buf);
1187 WMenuParserRegisterSimpleMacro(parser, "DISPLAY", XDisplayName(DisplayString(dpy)) );
1189 WMenuParserRegisterSimpleMacro(parser, "WM_VERSION", "\"" VERSION "\"");
1192 /************ Menu Configuration From Directory *************/
1194 static Bool isFilePackage(const char *file)
1196 int l;
1198 /* check if the extension indicates this file is a
1199 * file package. For now, only recognize .themed */
1201 l = strlen(file);
1203 if (l > 7 && strcmp(&(file[l - 7]), ".themed") == 0) {
1204 return True;
1205 } else {
1206 return False;
1210 static WMenu *readMenuDirectory(WScreen *scr, const char *title, char **path, const char *command)
1212 DIR *dir;
1213 struct dirent *dentry;
1214 struct stat stat_buf;
1215 WMenu *menu = NULL;
1216 char *buffer;
1217 WMArray *dirs = NULL, *files = NULL;
1218 WMArrayIterator iter;
1219 int length, i, have_space = 0;
1220 dir_data *data;
1221 int stripExtension = 0;
1223 dirs = WMCreateArray(16);
1224 files = WMCreateArray(16);
1226 i = 0;
1227 while (path[i] != NULL) {
1228 if (strcmp(path[i], "-noext") == 0) {
1229 stripExtension = 1;
1230 i++;
1231 continue;
1234 dir = opendir(path[i]);
1235 if (!dir) {
1236 i++;
1237 continue;
1240 while ((dentry = readdir(dir))) {
1242 if (strcmp(dentry->d_name, ".") == 0 || strcmp(dentry->d_name, "..") == 0)
1243 continue;
1245 if (dentry->d_name[0] == '.')
1246 continue;
1248 buffer = malloc(strlen(path[i]) + strlen(dentry->d_name) + 4);
1249 if (!buffer) {
1250 werror(_("out of memory while constructing directory menu %s"), path[i]);
1251 break;
1254 strcpy(buffer, path[i]);
1255 strcat(buffer, "/");
1256 strcat(buffer, dentry->d_name);
1258 if (stat(buffer, &stat_buf) != 0) {
1259 werror(_("%s:could not stat file \"%s\" in menu directory"),
1260 path[i], dentry->d_name);
1261 } else {
1262 Bool isFilePack = False;
1264 data = NULL;
1265 if (S_ISDIR(stat_buf.st_mode)
1266 && !(isFilePack = isFilePackage(dentry->d_name))) {
1268 /* access always returns success for user root */
1269 if (access(buffer, X_OK) == 0) {
1270 /* Directory is accesible. Add to directory list */
1272 data = (dir_data *) wmalloc(sizeof(dir_data));
1273 data->name = wstrdup(dentry->d_name);
1274 data->index = i;
1276 WMAddToArray(dirs, data);
1278 } else if (S_ISREG(stat_buf.st_mode) || isFilePack) {
1279 /* Hack because access always returns X_OK success for user root */
1280 #define S_IXANY (S_IXUSR | S_IXGRP | S_IXOTH)
1281 if ((command != NULL && access(buffer, R_OK) == 0) ||
1282 (command == NULL && access(buffer, X_OK) == 0 &&
1283 (stat_buf.st_mode & S_IXANY))) {
1285 data = (dir_data *) wmalloc(sizeof(dir_data));
1286 data->name = wstrdup(dentry->d_name);
1287 data->index = i;
1289 WMAddToArray(files, data);
1293 free(buffer);
1296 closedir(dir);
1297 i++;
1300 if (!WMGetArrayItemCount(dirs) && !WMGetArrayItemCount(files)) {
1301 WMFreeArray(dirs);
1302 WMFreeArray(files);
1303 return NULL;
1306 WMSortArray(dirs, myCompare);
1307 WMSortArray(files, myCompare);
1309 menu = wMenuCreate(scr, M_(title), False);
1310 menu->on_destroy = removeShortcutsForMenu;
1312 WM_ITERATE_ARRAY(dirs, data, iter) {
1313 /* New directory. Use same OPEN_MENU command that was used
1314 * for the current directory. */
1315 length = strlen(path[data->index]) + strlen(data->name) + 6;
1316 if (stripExtension)
1317 length += 7;
1318 if (command)
1319 length += strlen(command) + 6;
1320 buffer = malloc(length);
1321 if (!buffer) {
1322 werror(_("out of memory while constructing directory menu %s"), path[data->index]);
1323 break;
1326 buffer[0] = '\0';
1327 if (stripExtension)
1328 strcat(buffer, "-noext ");
1330 have_space = strchr(path[data->index], ' ') != NULL || strchr(data->name, ' ') != NULL;
1332 if (have_space)
1333 strcat(buffer, "\"");
1334 strcat(buffer, path[data->index]);
1336 strcat(buffer, "/");
1337 strcat(buffer, data->name);
1338 if (have_space)
1339 strcat(buffer, "\"");
1340 if (command) {
1341 strcat(buffer, " WITH ");
1342 strcat(buffer, command);
1345 addMenuEntry(menu, M_(data->name), NULL, "OPEN_MENU", buffer, path[data->index]);
1347 wfree(buffer);
1348 wfree(data->name);
1349 wfree(data);
1352 WM_ITERATE_ARRAY(files, data, iter) {
1353 /* executable: add as entry */
1354 length = strlen(path[data->index]) + strlen(data->name) + 6;
1355 if (command)
1356 length += strlen(command);
1358 buffer = malloc(length);
1359 if (!buffer) {
1360 werror(_("out of memory while constructing directory menu %s"), path[data->index]);
1361 break;
1364 have_space = strchr(path[data->index], ' ') != NULL || strchr(data->name, ' ') != NULL;
1365 if (command != NULL) {
1366 strcpy(buffer, command);
1367 strcat(buffer, " ");
1368 if (have_space)
1369 strcat(buffer, "\"");
1370 strcat(buffer, path[data->index]);
1371 } else {
1372 if (have_space) {
1373 buffer[0] = '"';
1374 buffer[1] = 0;
1375 strcat(buffer, path[data->index]);
1376 } else {
1377 strcpy(buffer, path[data->index]);
1380 strcat(buffer, "/");
1381 strcat(buffer, data->name);
1382 if (have_space)
1383 strcat(buffer, "\"");
1385 if (stripExtension) {
1386 char *ptr = strrchr(data->name, '.');
1387 if (ptr && ptr != data->name)
1388 *ptr = 0;
1390 addMenuEntry(menu, M_(data->name), NULL, "SHEXEC", buffer, path[data->index]);
1392 wfree(buffer);
1393 wfree(data->name);
1394 wfree(data);
1397 WMFreeArray(files);
1398 WMFreeArray(dirs);
1400 return menu;
1403 /************ Menu Configuration From WMRootMenu *************/
1405 static WMenu *makeDefaultMenu(WScreen * scr)
1407 WMenu *menu = NULL;
1409 menu = wMenuCreate(scr, _("Commands"), True);
1410 wMenuAddCallback(menu, M_("XTerm"), execCommand, "xterm");
1411 wMenuAddCallback(menu, M_("rxvt"), execCommand, "rxvt");
1412 wMenuAddCallback(menu, _("Restart"), restartCommand, NULL);
1413 wMenuAddCallback(menu, _("Exit..."), exitCommand, NULL);
1414 return menu;
1418 *----------------------------------------------------------------------
1419 * configureMenu--
1420 * Reads root menu configuration from defaults database.
1422 *----------------------------------------------------------------------
1424 WMenu *configureMenu(WScreen *scr, WMPropList *definition)
1426 WMenu *menu = NULL;
1427 WMPropList *elem;
1428 int i, count;
1429 WMPropList *title, *command, *params;
1430 char *tmp, *mtitle;
1432 if (WMIsPLString(definition)) {
1433 struct stat stat_buf;
1434 char *path = NULL;
1435 Bool menu_is_default = False;
1437 /* menu definition is a string. Probably a path, so parse the file */
1439 tmp = wexpandpath(WMGetFromPLString(definition));
1441 path = getLocalizedMenuFile(tmp);
1443 if (!path)
1444 path = wfindfile(DEF_CONFIG_PATHS, tmp);
1446 if (!path) {
1447 path = wfindfile(DEF_CONFIG_PATHS, DEF_MENU_FILE);
1448 menu_is_default = True;
1451 if (!path) {
1452 werror(_("could not find menu file \"%s\" referenced in WMRootMenu"), tmp);
1453 wfree(tmp);
1454 return NULL;
1457 if (stat(path, &stat_buf) < 0) {
1458 werror(_("could not access menu \"%s\" referenced in WMRootMenu"), path);
1459 wfree(path);
1460 wfree(tmp);
1461 return NULL;
1464 if (!scr->root_menu || stat_buf.st_mtime > scr->root_menu->timestamp
1465 /* if the pointer in WMRootMenu has changed */
1466 || w_global.domain.root_menu->timestamp > scr->root_menu->timestamp) {
1467 WMPropList *menu_from_file = NULL;
1469 if (menu_is_default) {
1470 wwarning(_
1471 ("using default menu file \"%s\" as the menu referenced in WMRootMenu could not be found "),
1472 path);
1475 menu_from_file = WMReadPropListFromFile(path);
1476 if (menu_from_file == NULL) { /* old style menu */
1477 menu = readMenuFile(scr, path);
1478 } else {
1479 menu = configureMenu(scr, menu_from_file);
1480 WMReleasePropList(menu_from_file);
1483 if (menu)
1484 menu->timestamp = WMAX(stat_buf.st_mtime, w_global.domain.root_menu->timestamp);
1485 } else {
1486 menu = NULL;
1488 wfree(path);
1489 wfree(tmp);
1491 return menu;
1494 count = WMGetPropListItemCount(definition);
1495 if (count == 0)
1496 return NULL;
1498 elem = WMGetFromPLArray(definition, 0);
1499 if (!WMIsPLString(elem)) {
1500 tmp = WMGetPropListDescription(elem, False);
1501 wwarning(_("%s:format error in root menu configuration \"%s\""), "WMRootMenu", tmp);
1502 wfree(tmp);
1503 return NULL;
1505 mtitle = WMGetFromPLString(elem);
1507 menu = wMenuCreate(scr, M_(mtitle), False);
1508 menu->on_destroy = removeShortcutsForMenu;
1510 for (i = 1; i < count; i++) {
1511 elem = WMGetFromPLArray(definition, i);
1512 #if 0
1513 if (WMIsPLString(elem)) {
1514 char *file;
1516 file = WMGetFromPLString(elem);
1519 #endif
1520 if (!WMIsPLArray(elem) || WMGetPropListItemCount(elem) < 2)
1521 goto error;
1523 if (WMIsPLArray(WMGetFromPLArray(elem, 1))) {
1524 WMenu *submenu;
1525 WMenuEntry *mentry;
1527 /* submenu */
1528 submenu = configureMenu(scr, elem);
1529 if (submenu) {
1530 mentry = wMenuAddCallback(menu, submenu->frame->title, NULL, NULL);
1531 wMenuEntrySetCascade(menu, mentry, submenu);
1533 } else {
1534 int idx = 0;
1535 WMPropList *shortcut;
1536 /* normal entry */
1538 title = WMGetFromPLArray(elem, idx++);
1539 shortcut = WMGetFromPLArray(elem, idx++);
1540 if (strcmp(WMGetFromPLString(shortcut), "SHORTCUT") == 0) {
1541 shortcut = WMGetFromPLArray(elem, idx++);
1542 command = WMGetFromPLArray(elem, idx++);
1543 } else {
1544 command = shortcut;
1545 shortcut = NULL;
1547 params = WMGetFromPLArray(elem, idx++);
1549 if (!title || !command)
1550 goto error;
1552 addMenuEntry(menu, M_(WMGetFromPLString(title)),
1553 shortcut ? WMGetFromPLString(shortcut) : NULL,
1554 WMGetFromPLString(command),
1555 params ? WMGetFromPLString(params) : NULL, "WMRootMenu");
1557 continue;
1559 error:
1560 tmp = WMGetPropListDescription(elem, False);
1561 wwarning(_("%s:format error in root menu configuration \"%s\""), "WMRootMenu", tmp);
1562 wfree(tmp);
1565 return menu;
1569 *----------------------------------------------------------------------
1570 * OpenRootMenu--
1571 * Opens the root menu, parsing the menu configuration from the
1572 * defaults database.
1573 * If the menu is already mapped and is not sticked to the
1574 * root window, it will be unmapped.
1576 * Side effects:
1577 * The menu may be remade.
1579 * Notes:
1580 * Construction of OPEN_MENU entries are delayed to the moment the
1581 * user map's them.
1582 *----------------------------------------------------------------------
1584 void OpenRootMenu(WScreen * scr, int x, int y, int keyboard)
1586 WMenu *menu = NULL;
1587 WMPropList *definition;
1589 static WMPropList *domain=NULL;
1591 if (!domain) {
1592 domain = WMCreatePLString("WMRootMenu");
1596 scr->flags.root_menu_changed_shortcuts = 0;
1597 scr->flags.added_workspace_menu = 0;
1598 scr->flags.added_windows_menu = 0;
1600 if (scr->root_menu && scr->root_menu->flags.mapped) {
1601 menu = scr->root_menu;
1602 if (!menu->flags.buttoned) {
1603 wMenuUnmap(menu);
1604 } else {
1605 wRaiseFrame(menu->frame->core);
1607 if (keyboard)
1608 wMenuMapAt(menu, 0, 0, True);
1609 else
1610 wMenuMapCopyAt(menu, x - menu->frame->core->width / 2, y);
1612 return;
1615 definition = w_global.domain.root_menu->dictionary;
1618 definition = PLGetDomain(domain);
1620 if (definition) {
1621 if (WMIsPLArray(definition)) {
1622 if (!scr->root_menu || w_global.domain.root_menu->timestamp > scr->root_menu->timestamp) {
1623 menu = configureMenu(scr, definition);
1624 if (menu)
1625 menu->timestamp = w_global.domain.root_menu->timestamp;
1627 } else
1628 menu = NULL;
1629 } else {
1630 menu = configureMenu(scr, definition);
1634 if (!menu) {
1635 /* menu hasn't changed or could not be read */
1636 if (!scr->root_menu) {
1637 wMessageDialog(scr, _("Error"),
1638 _("The applications menu could not be loaded. "
1639 "Look at the console output for a detailed "
1640 "description of the errors."), _("OK"), NULL, NULL);
1642 menu = makeDefaultMenu(scr);
1643 scr->root_menu = menu;
1645 menu = scr->root_menu;
1646 } else {
1647 /* new root menu */
1648 if (scr->root_menu) {
1649 wMenuDestroy(scr->root_menu, True);
1651 scr->root_menu = menu;
1653 if (menu) {
1654 int newx, newy;
1656 if (keyboard && x == 0 && y == 0) {
1657 newx = newy = 0;
1658 } else if (keyboard && x == scr->scr_width / 2 && y == scr->scr_height / 2) {
1659 newx = x - menu->frame->core->width / 2;
1660 newy = y - menu->frame->core->height / 2;
1661 } else {
1662 newx = x - menu->frame->core->width / 2;
1663 newy = y;
1665 wMenuMapAt(menu, newx, newy, keyboard);
1668 if (scr->flags.root_menu_changed_shortcuts)
1669 rebindKeygrabs(scr);