wmaker: Added 'const' attribute to remaining functions
[wmaker-crm.git] / src / rootmenu.c
blob5d971b6ba2178f86839f5544edc2091b2d95a0d3
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 along
19 * with this program; if not, write to the Free Software Foundation, Inc.,
20 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
23 #include "wconfig.h"
25 #include <stdio.h>
26 #include <stdlib.h>
27 #include <unistd.h>
28 #include <sys/stat.h>
29 #include <sys/wait.h>
30 #include <sys/types.h>
31 #include <string.h>
32 #include <strings.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 "misc.h"
45 #include "main.h"
46 #include "dialog.h"
47 #include "keybind.h"
48 #include "stacking.h"
49 #include "workspace.h"
50 #include "defaults.h"
51 #include "framewin.h"
52 #include "session.h"
53 #include "shutdown.h"
54 #include "xmodifier.h"
55 #include "rootmenu.h"
56 #include "startup.h"
57 #include "switchmenu.h"
59 #include <WINGs/WUtil.h>
61 #define MAX_SHORTCUT_LENGTH 32
63 extern char *Locale;
64 extern WDDomain *WDRootMenu;
65 extern Cursor wCursor[WCUR_LAST];
66 extern WPreferences wPreferences;
68 static WMenu *readMenuPipe(WScreen * scr, char **file_name);
69 static WMenu *readPLMenuPipe(WScreen * scr, char **file_name);
70 static WMenu *readMenuFile(WScreen *scr, const char *file_name);
71 static WMenu *readMenuDirectory(WScreen *scr, const char *title, char **file_name, const char *command);
72 static WMenu *configureMenu(WScreen * scr, WMPropList * definition, Bool includeGlobals);
73 static void menu_parser_register_macros(WMenuParser parser);
75 typedef struct Shortcut {
76 struct Shortcut *next;
78 int modifier;
79 KeyCode keycode;
80 WMenuEntry *entry;
81 WMenu *menu;
82 } Shortcut;
84 static Shortcut *shortcutList = NULL;
87 * Syntax:
88 * # main menu
89 * "Menu Name" MENU
90 * "Title" EXEC command_to_exec -params
91 * "Submenu" MENU
92 * "Title" EXEC command_to_exec -params
93 * "Submenu" END
94 * "Workspaces" WORKSPACE_MENU
95 * "Title" built_in_command
96 * "Quit" EXIT
97 * "Quick Quit" EXIT QUICK
98 * "Menu Name" END
100 * Commands may be preceded by SHORTCUT key
102 * Built-in commands:
104 * INFO_PANEL - shows the Info Panel
105 * LEGAL_PANEL - shows the Legal info panel
106 * SHUTDOWN [QUICK] - closes the X server [without confirmation]
107 * REFRESH - forces the desktop to be repainted
108 * EXIT [QUICK] - exit the window manager [without confirmation]
109 * EXEC <program> - execute an external program
110 * SHEXEC <command> - execute a shell command
111 * WORKSPACE_MENU - places the workspace submenu
112 * ARRANGE_ICONS
113 * RESTART [<window manager>] - restarts the window manager
114 * SHOW_ALL - unhide all windows on workspace
115 * HIDE_OTHERS - hides all windows excep the focused one
116 * OPEN_MENU file - read menu data from file which must be a valid menu file.
117 * OPEN_MENU /some/dir [/some/other/dir ...] [WITH command -options]
118 * - read menu data from directory(ies) and
119 * eventually precede each with a command.
120 * OPEN_MENU | command
121 * - opens command and uses its stdout to construct and insert
122 * the resulting menu in current position. The output of
123 * command must be a valid menu description.
124 * The space between '|' and command is optional.
125 * || will do the same, but will not cache the contents.
126 * OPEN_PLMENU | command
127 * - opens command and uses its stdout which must be in proplist
128 * fromat to construct and insert the resulting menu in current
129 * position.
130 * The space between '|' and command is optional.
131 * || will do the same, but will not cache the contents.
132 * SAVE_SESSION - saves the current state of the desktop, which include
133 * all running applications, all their hints (geometry,
134 * position on screen, workspace they live on, the dock
135 * or clip from where they were launched, and
136 * if minimized, shaded or hidden. Also saves the current
137 * workspace the user is on. All will be restored on every
138 * start of windowmaker until another SAVE_SESSION or
139 * CLEAR_SESSION is used. If SaveSessionOnExit = Yes; in
140 * WindowMaker domain file, then saving is automatically
141 * done on every windowmaker exit, overwriting any
142 * SAVE_SESSION or CLEAR_SESSION (see below). Also save
143 * dock state now.
144 * CLEAR_SESSION - clears any previous saved session. This will not have
145 * any effect if SaveSessionOnExit is True.
149 #define M_QUICK 1
151 /* menu commands */
153 static void execCommand(WMenu * menu, WMenuEntry * entry)
155 char *cmdline;
157 cmdline = ExpandOptions(menu->frame->screen_ptr, (char *)entry->clientdata);
159 XGrabPointer(dpy, menu->frame->screen_ptr->root_win, True, 0,
160 GrabModeAsync, GrabModeAsync, None, wCursor[WCUR_WAIT], 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);
171 static void exitCommand(WMenu * menu, WMenuEntry * entry)
173 static int inside = 0;
174 int result;
176 /* prevent reentrant calls */
177 if (inside)
178 return;
179 inside = 1;
181 #define R_CANCEL 0
182 #define R_EXIT 1
184 result = R_CANCEL;
186 if ((long)entry->clientdata == M_QUICK) {
187 result = R_EXIT;
188 } else {
189 int r, oldSaveSessionFlag;
191 oldSaveSessionFlag = wPreferences.save_session_on_exit;
192 r = wExitDialog(menu->frame->screen_ptr, _("Exit"),
193 _("Exit window manager?"), _("Exit"), _("Cancel"), NULL);
195 if (r == WAPRDefault) {
196 result = R_EXIT;
197 } else if (r == WAPRAlternate) {
198 /* Don't modify the "save session on exit" flag if the
199 * user canceled the operation. */
200 wPreferences.save_session_on_exit = oldSaveSessionFlag;
203 if (result == R_EXIT)
204 Shutdown(WSExitMode);
206 #undef R_EXIT
207 #undef R_CANCEL
208 inside = 0;
211 static void shutdownCommand(WMenu * menu, WMenuEntry * entry)
213 static int inside = 0;
214 int result;
216 /* prevent reentrant calls */
217 if (inside)
218 return;
219 inside = 1;
221 #define R_CANCEL 0
222 #define R_CLOSE 1
223 #define R_KILL 2
225 result = R_CANCEL;
226 if ((long)entry->clientdata == M_QUICK)
227 result = R_CLOSE;
228 else {
229 int r, oldSaveSessionFlag;
231 oldSaveSessionFlag = wPreferences.save_session_on_exit;
233 r = wExitDialog(menu->frame->screen_ptr,
234 _("Kill X session"),
235 _("Kill Window System session?\n"
236 "(all applications will be closed)"), _("Kill"), _("Cancel"), NULL);
237 if (r == WAPRDefault) {
238 result = R_KILL;
239 } else if (r == WAPRAlternate) {
240 /* Don't modify the "save session on exit" flag if the
241 * user canceled the operation. */
242 wPreferences.save_session_on_exit = oldSaveSessionFlag;
246 if (result != R_CANCEL) {
247 Shutdown(WSKillMode);
249 #undef R_CLOSE
250 #undef R_CANCEL
251 #undef R_KILL
252 inside = 0;
255 static void restartCommand(WMenu * menu, WMenuEntry * entry)
257 Shutdown(WSRestartPreparationMode);
258 Restart((char *)entry->clientdata, False);
259 Restart(NULL, True);
262 static void refreshCommand(WMenu * menu, WMenuEntry * entry)
264 wRefreshDesktop(menu->frame->screen_ptr);
267 static void arrangeIconsCommand(WMenu * menu, WMenuEntry * entry)
269 wArrangeIcons(menu->frame->screen_ptr, True);
272 static void showAllCommand(WMenu * menu, WMenuEntry * entry)
274 wShowAllWindows(menu->frame->screen_ptr);
277 static void hideOthersCommand(WMenu * menu, WMenuEntry * entry)
279 wHideOtherApplications(menu->frame->screen_ptr->focused_window);
282 static void saveSessionCommand(WMenu * menu, WMenuEntry * entry)
284 if (!wPreferences.save_session_on_exit)
285 wSessionSaveState(menu->frame->screen_ptr);
287 wScreenSaveState(menu->frame->screen_ptr);
290 static void clearSessionCommand(WMenu * menu, WMenuEntry * entry)
292 wSessionClearState(menu->frame->screen_ptr);
293 wScreenSaveState(menu->frame->screen_ptr);
296 static void infoPanelCommand(WMenu * menu, WMenuEntry * entry)
298 wShowInfoPanel(menu->frame->screen_ptr);
301 static void legalPanelCommand(WMenu * menu, WMenuEntry * entry)
303 wShowLegalPanel(menu->frame->screen_ptr);
306 /********************************************************************/
308 static char *getLocalizedMenuFile(const char *menu)
310 char *buffer, *ptr, *locale;
311 int len;
313 if (!Locale)
314 return NULL;
316 len = strlen(menu) + strlen(Locale) + 8;
317 buffer = wmalloc(len);
319 /* try menu.locale_name */
320 snprintf(buffer, len, "%s.%s", menu, Locale);
321 if (access(buffer, F_OK) == 0)
322 return buffer;
324 /* position of locale in our buffer */
325 locale = buffer + strlen(menu) + 1;
327 /* check if it is in the form aa_bb.encoding and check for aa_bb */
328 ptr = strchr(locale, '.');
329 if (ptr) {
330 *ptr = 0;
331 if (access(buffer, F_OK) == 0)
332 return buffer;
335 /* now check for aa */
336 ptr = strchr(locale, '_');
337 if (ptr) {
338 *ptr = 0;
339 if (access(buffer, F_OK) == 0)
340 return buffer;
343 wfree(buffer);
345 return NULL;
348 Bool wRootMenuPerformShortcut(XEvent * event)
350 WScreen *scr = wScreenForRootWindow(event->xkey.root);
351 Shortcut *ptr;
352 int modifiers;
353 int done = 0;
355 /* ignore CapsLock */
356 modifiers = event->xkey.state & ValidModMask;
358 for (ptr = shortcutList; ptr != NULL; ptr = ptr->next) {
359 if (ptr->keycode == 0 || ptr->menu->menu->screen_ptr != scr)
360 continue;
362 if (ptr->keycode == event->xkey.keycode && ptr->modifier == modifiers) {
363 (*ptr->entry->callback) (ptr->menu, ptr->entry);
364 done = True;
368 return done;
371 void wRootMenuBindShortcuts(Window window)
373 Shortcut *ptr;
375 ptr = shortcutList;
376 while (ptr) {
377 if (ptr->modifier != AnyModifier) {
378 XGrabKey(dpy, ptr->keycode, ptr->modifier | LockMask,
379 window, True, GrabModeAsync, GrabModeAsync);
380 #ifdef NUMLOCK_HACK
381 wHackedGrabKey(ptr->keycode, ptr->modifier, window, True, GrabModeAsync, GrabModeAsync);
382 #endif
384 XGrabKey(dpy, ptr->keycode, ptr->modifier, window, True, GrabModeAsync, GrabModeAsync);
385 ptr = ptr->next;
389 static void rebindKeygrabs(WScreen * scr)
391 WWindow *wwin;
393 wwin = scr->focused_window;
395 while (wwin != NULL) {
396 XUngrabKey(dpy, AnyKey, AnyModifier, wwin->frame->core->window);
398 if (!WFLAGP(wwin, no_bind_keys)) {
399 wWindowSetKeyGrabs(wwin);
401 wwin = wwin->prev;
405 static void removeShortcutsForMenu(WMenu * menu)
407 Shortcut *ptr, *tmp;
408 Shortcut *newList = NULL;
410 ptr = shortcutList;
411 while (ptr != NULL) {
412 tmp = ptr->next;
413 if (ptr->menu == menu) {
414 wfree(ptr);
415 } else {
416 ptr->next = newList;
417 newList = ptr;
419 ptr = tmp;
421 shortcutList = newList;
422 menu->menu->screen_ptr->flags.root_menu_changed_shortcuts = 1;
425 static Bool addShortcut(const char *file, const char *shortcutDefinition, WMenu *menu, WMenuEntry *entry)
427 Shortcut *ptr;
428 KeySym ksym;
429 char *k;
430 char buf[MAX_SHORTCUT_LENGTH], *b;
432 ptr = wmalloc(sizeof(Shortcut));
434 wstrlcpy(buf, shortcutDefinition, MAX_SHORTCUT_LENGTH);
435 b = (char *)buf;
437 /* get modifiers */
438 ptr->modifier = 0;
439 while ((k = strchr(b, '+')) != NULL) {
440 int mod;
442 *k = 0;
443 mod = wXModifierFromKey(b);
444 if (mod < 0) {
445 wwarning(_("%s: invalid key modifier \"%s\""), file, b);
446 wfree(ptr);
447 return False;
449 ptr->modifier |= mod;
451 b = k + 1;
454 /* get key */
455 ksym = XStringToKeysym(b);
457 if (ksym == NoSymbol) {
458 wwarning(_("%s:invalid kbd shortcut specification \"%s\" for entry %s"),
459 file, shortcutDefinition, entry->text);
460 wfree(ptr);
461 return False;
464 ptr->keycode = XKeysymToKeycode(dpy, ksym);
465 if (ptr->keycode == 0) {
466 wwarning(_("%s:invalid key in shortcut \"%s\" for entry %s"), file,
467 shortcutDefinition, entry->text);
468 wfree(ptr);
469 return False;
472 ptr->menu = menu;
473 ptr->entry = entry;
475 ptr->next = shortcutList;
476 shortcutList = ptr;
478 menu->menu->screen_ptr->flags.root_menu_changed_shortcuts = 1;
480 return True;
483 static char *next_token(char *line, char **next)
485 char *tmp, c;
486 char *ret;
488 *next = NULL;
489 while (*line == ' ' || *line == '\t')
490 line++;
492 tmp = line;
494 if (*tmp == '"') {
495 tmp++;
496 line++;
497 while (*tmp != 0 && *tmp != '"')
498 tmp++;
499 if (*tmp != '"') {
500 wwarning(_("%s: unmatched '\"' in menu file"), line);
501 return NULL;
503 } else {
504 do {
505 if (*tmp == '\\')
506 tmp++;
508 if (*tmp != 0)
509 tmp++;
511 } while (*tmp != 0 && *tmp != ' ' && *tmp != '\t');
514 c = *tmp;
515 *tmp = 0;
516 ret = wstrdup(line);
517 *tmp = c;
519 if (c == 0)
520 return ret;
521 else
522 tmp++;
524 /* skip blanks */
525 while (*tmp == ' ' || *tmp == '\t')
526 tmp++;
528 if (*tmp != 0)
529 *next = tmp;
531 return ret;
534 static void separateCommand(char *line, char ***file, char **command)
536 char *token, *tmp = line;
537 WMArray *array = WMCreateArray(4);
538 int count, i;
540 *file = NULL;
541 *command = NULL;
542 do {
543 token = next_token(tmp, &tmp);
544 if (token) {
545 if (strcmp(token, "WITH") == 0) {
546 if (tmp != NULL && *tmp != 0)
547 *command = wstrdup(tmp);
548 else
549 wwarning(_("%s: missing command"), line);
550 break;
552 WMAddToArray(array, token);
554 } while (token != NULL && tmp != NULL);
556 count = WMGetArrayItemCount(array);
557 if (count > 0) {
558 *file = wmalloc(sizeof(char *) * (count + 1));
559 (*file)[count] = NULL;
560 for (i = 0; i < count; i++) {
561 (*file)[i] = WMGetFromArray(array, i);
564 WMFreeArray(array);
567 static WMenu *constructPLMenu(WScreen *screen, const char *path)
569 WMPropList *pl = NULL;
570 WMenu *menu = NULL;
572 if (!path)
573 return NULL;
575 pl = WMReadPropListFromFile(path);
576 if (!pl)
577 return NULL;
579 menu = configureMenu(screen, pl, False);
581 WMReleasePropList(pl);
583 if (!menu)
584 return NULL;
586 menu->on_destroy = removeShortcutsForMenu;
587 return menu;
592 static void constructMenu(WMenu * menu, WMenuEntry * entry)
594 WMenu *submenu;
595 struct stat stat_buf;
596 char **path;
597 char *cmd;
598 char *lpath = NULL;
599 int i, first = -1;
600 time_t last = 0;
602 separateCommand((char *)entry->clientdata, &path, &cmd);
603 if (path == NULL || *path == NULL || **path == 0) {
604 wwarning(_("invalid OPEN_MENU specification: %s"), (char *)entry->clientdata);
605 if (cmd)
606 wfree(cmd);
607 return;
610 if (path[0][0] == '|') {
611 /* pipe menu */
613 if (!menu->cascades[entry->cascade] || menu->cascades[entry->cascade]->timestamp == 0) {
614 /* parse pipe */
616 submenu = readMenuPipe(menu->frame->screen_ptr, path);
618 if (submenu != NULL) {
619 if (path[0][1] == '|')
620 submenu->timestamp = 0;
621 else
622 submenu->timestamp = 1; /* there's no automatic reloading */
624 } else {
625 submenu = NULL;
628 } else {
630 /* try interpreting path as a proplist file */
631 submenu = constructPLMenu(menu->frame->screen_ptr, path[0]);
632 /* if unsuccessful, try it as an old-style file */
633 if (!submenu) {
635 i = 0;
636 while (path[i] != NULL) {
637 char *tmp;
639 if (strcmp(path[i], "-noext") == 0) {
640 i++;
641 continue;
644 tmp = wexpandpath(path[i]);
645 wfree(path[i]);
646 lpath = getLocalizedMenuFile(tmp);
647 if (lpath) {
648 wfree(tmp);
649 path[i] = lpath;
650 lpath = NULL;
651 } else {
652 path[i] = tmp;
655 if (stat(path[i], &stat_buf) == 0) {
656 if (last < stat_buf.st_mtime)
657 last = stat_buf.st_mtime;
658 if (first < 0)
659 first = i;
660 } else {
661 werror(_("%s:could not stat menu"), path[i]);
662 /*goto finish; */
665 i++;
668 if (first < 0) {
669 werror(_("%s:could not stat menu:%s"), "OPEN_MENU", (char *)entry->clientdata);
670 goto finish;
672 stat(path[first], &stat_buf);
673 if (!menu->cascades[entry->cascade]
674 || menu->cascades[entry->cascade]->timestamp < last) {
676 if (S_ISDIR(stat_buf.st_mode)) {
677 /* menu directory */
678 submenu = readMenuDirectory(menu->frame->screen_ptr, entry->text, path, cmd);
679 if (submenu)
680 submenu->timestamp = last;
681 } else if (S_ISREG(stat_buf.st_mode)) {
682 /* menu file */
684 if (cmd || path[1])
685 wwarning(_("too many parameters in OPEN_MENU: %s"),
686 (char *)entry->clientdata);
688 submenu = readMenuFile(menu->frame->screen_ptr, path[first]);
689 if (submenu)
690 submenu->timestamp = stat_buf.st_mtime;
691 } else {
692 submenu = NULL;
694 } else {
695 submenu = NULL;
700 if (submenu) {
701 wMenuEntryRemoveCascade(menu, entry);
702 wMenuEntrySetCascade(menu, entry, submenu);
705 finish:
706 i = 0;
707 while (path[i] != NULL)
708 wfree(path[i++]);
709 wfree(path);
710 if (cmd)
711 wfree(cmd);
714 static void constructPLMenuFromPipe(WMenu * menu, WMenuEntry * entry)
716 WMenu *submenu = NULL;
717 char **path;
718 char *cmd;
719 int i;
721 separateCommand((char *)entry->clientdata, &path, &cmd);
722 if (path == NULL || *path == NULL || **path == 0) {
723 wwarning(_("invalid OPEN_PLMENU specification: %s"),
724 (char *)entry->clientdata);
725 if (cmd)
726 wfree(cmd);
727 return;
730 if (path[0][0] == '|') {
731 /* pipe menu */
733 if (!menu->cascades[entry->cascade]
734 || menu->cascades[entry->cascade]->timestamp == 0) {
735 /* parse pipe */
736 submenu = readPLMenuPipe(menu->frame->screen_ptr, path);
738 if (submenu != NULL) {
739 if (path[0][1] == '|')
740 submenu->timestamp = 0;
741 else
742 submenu->timestamp = 1; /* there's no automatic reloading */
747 if (submenu) {
748 wMenuEntryRemoveCascade(menu, entry);
749 wMenuEntrySetCascade(menu, entry, submenu);
752 i = 0;
753 while (path[i] != NULL)
754 wfree(path[i++]);
756 wfree(path);
757 if (cmd)
758 wfree(cmd);
761 static void cleanupWorkspaceMenu(WMenu * menu)
763 if (menu->frame->screen_ptr->workspace_menu == menu)
764 menu->frame->screen_ptr->workspace_menu = NULL;
767 static WMenuEntry *addWorkspaceMenu(WScreen *scr, WMenu *menu, const char *title)
769 WMenu *wsmenu;
770 WMenuEntry *entry;
772 if (scr->flags.added_workspace_menu) {
773 wwarning(_
774 ("There are more than one WORKSPACE_MENU commands in the applications menu. Only one is allowed."));
775 return NULL;
776 } else {
777 scr->flags.added_workspace_menu = 1;
779 wsmenu = wWorkspaceMenuMake(scr, True);
780 wsmenu->on_destroy = cleanupWorkspaceMenu;
782 scr->workspace_menu = wsmenu;
783 entry = wMenuAddCallback(menu, title, NULL, NULL);
784 wMenuEntrySetCascade(menu, entry, wsmenu);
786 wWorkspaceMenuUpdate(scr, wsmenu);
788 return entry;
791 static void cleanupWindowsMenu(WMenu * menu)
793 if (menu->frame->screen_ptr->switch_menu == menu)
794 menu->frame->screen_ptr->switch_menu = NULL;
797 static WMenuEntry *addWindowsMenu(WScreen *scr, WMenu *menu, const char *title)
799 WMenu *wwmenu;
800 WWindow *wwin;
801 WMenuEntry *entry;
803 if (scr->flags.added_windows_menu) {
804 wwarning(_
805 ("There are more than one WINDOWS_MENU commands in the applications menu. Only one is allowed."));
806 return NULL;
807 } else {
808 scr->flags.added_windows_menu = 1;
810 wwmenu = wMenuCreate(scr, _("Window List"), False);
811 wwmenu->on_destroy = cleanupWindowsMenu;
812 scr->switch_menu = wwmenu;
813 wwin = scr->focused_window;
814 while (wwin) {
815 UpdateSwitchMenu(scr, wwin, ACTION_ADD);
817 wwin = wwin->prev;
819 entry = wMenuAddCallback(menu, title, NULL, NULL);
820 wMenuEntrySetCascade(menu, entry, wwmenu);
822 return entry;
825 static WMenuEntry *addMenuEntry(WMenu *menu, const char *title, const char *shortcut, const char *command,
826 const char *params, const char *file_name)
828 WScreen *scr;
829 WMenuEntry *entry = NULL;
830 Bool shortcutOk = False;
832 if (!menu)
833 return NULL;
834 scr = menu->frame->screen_ptr;
835 if (strcmp(command, "OPEN_MENU") == 0) {
836 if (!params) {
837 wwarning(_("%s:missing parameter for menu command \"%s\""), file_name, command);
838 } else {
839 WMenu *dummy;
840 char *path;
842 path = wfindfile(DEF_CONFIG_PATHS, params);
843 if (!path) {
844 path = wstrdup(params);
846 dummy = wMenuCreate(scr, title, False);
847 dummy->on_destroy = removeShortcutsForMenu;
848 entry = wMenuAddCallback(menu, title, constructMenu, path);
849 entry->free_cdata = wfree;
850 wMenuEntrySetCascade(menu, entry, dummy);
852 } else if (strcmp(command, "OPEN_PLMENU") == 0) {
853 if (!params) {
854 wwarning(_("%s:missing parameter for menu command \"%s\""), file_name, command);
855 } else {
856 WMenu *dummy;
857 char *path;
859 path = wfindfile(DEF_CONFIG_PATHS, params);
860 if (!path)
861 path = wstrdup(params);
863 dummy = wMenuCreate(scr, title, False);
864 dummy->on_destroy = removeShortcutsForMenu;
865 entry = wMenuAddCallback(menu, title, constructPLMenuFromPipe, path);
866 entry->free_cdata = wfree;
867 wMenuEntrySetCascade(menu, entry, dummy);
869 } else if (strcmp(command, "EXEC") == 0) {
870 if (!params)
871 wwarning(_("%s:missing parameter for menu command \"%s\""), file_name, command);
872 else {
873 entry = wMenuAddCallback(menu, title, execCommand, wstrconcat("exec ", params));
874 entry->free_cdata = wfree;
875 shortcutOk = True;
877 } else if (strcmp(command, "SHEXEC") == 0) {
878 if (!params)
879 wwarning(_("%s:missing parameter for menu command \"%s\""), file_name, command);
880 else {
881 entry = wMenuAddCallback(menu, title, execCommand, wstrdup(params));
882 entry->free_cdata = wfree;
883 shortcutOk = True;
885 } else if (strcmp(command, "EXIT") == 0) {
887 if (params && strcmp(params, "QUICK") == 0)
888 entry = wMenuAddCallback(menu, title, exitCommand, (void *)M_QUICK);
889 else
890 entry = wMenuAddCallback(menu, title, exitCommand, NULL);
892 shortcutOk = True;
893 } else if (strcmp(command, "SHUTDOWN") == 0) {
895 if (params && strcmp(params, "QUICK") == 0)
896 entry = wMenuAddCallback(menu, title, shutdownCommand, (void *)M_QUICK);
897 else
898 entry = wMenuAddCallback(menu, title, shutdownCommand, NULL);
900 shortcutOk = True;
901 } else if (strcmp(command, "REFRESH") == 0) {
902 entry = wMenuAddCallback(menu, title, refreshCommand, NULL);
904 shortcutOk = True;
905 } else if (strcmp(command, "WORKSPACE_MENU") == 0) {
906 entry = addWorkspaceMenu(scr, menu, title);
908 shortcutOk = True;
909 } else if (strcmp(command, "WINDOWS_MENU") == 0) {
910 entry = addWindowsMenu(scr, menu, title);
912 shortcutOk = True;
913 } else if (strcmp(command, "ARRANGE_ICONS") == 0) {
914 entry = wMenuAddCallback(menu, title, arrangeIconsCommand, NULL);
916 shortcutOk = True;
917 } else if (strcmp(command, "HIDE_OTHERS") == 0) {
918 entry = wMenuAddCallback(menu, title, hideOthersCommand, NULL);
920 shortcutOk = True;
921 } else if (strcmp(command, "SHOW_ALL") == 0) {
922 entry = wMenuAddCallback(menu, title, showAllCommand, NULL);
924 shortcutOk = True;
925 } else if (strcmp(command, "RESTART") == 0) {
926 entry = wMenuAddCallback(menu, title, restartCommand, params ? wstrdup(params) : NULL);
927 entry->free_cdata = wfree;
928 shortcutOk = True;
929 } else if (strcmp(command, "SAVE_SESSION") == 0) {
930 entry = wMenuAddCallback(menu, title, saveSessionCommand, NULL);
932 shortcutOk = True;
933 } else if (strcmp(command, "CLEAR_SESSION") == 0) {
934 entry = wMenuAddCallback(menu, title, clearSessionCommand, NULL);
935 shortcutOk = True;
936 } else if (strcmp(command, "INFO_PANEL") == 0) {
937 entry = wMenuAddCallback(menu, title, infoPanelCommand, NULL);
938 shortcutOk = True;
939 } else if (strcmp(command, "LEGAL_PANEL") == 0) {
940 entry = wMenuAddCallback(menu, title, legalPanelCommand, NULL);
941 shortcutOk = True;
942 } else {
943 wwarning(_("%s:unknown command \"%s\" in menu config."), file_name, command);
945 return NULL;
948 if (shortcut && entry) {
949 if (!shortcutOk) {
950 wwarning(_("%s:can't add shortcut for entry \"%s\""), file_name, title);
951 } else {
952 if (addShortcut(file_name, shortcut, menu, entry)) {
954 entry->rtext = GetShortcutString(shortcut);
956 entry->rtext = wstrdup(shortcut);
962 return entry;
965 /******************* Menu Configuration From File *******************/
967 static void freeline(char *title, char *command, char *parameter, char *shortcut)
969 wfree(title);
970 wfree(command);
971 wfree(parameter);
972 wfree(shortcut);
975 static WMenu *parseCascade(WScreen * scr, WMenu * menu, WMenuParser parser)
977 char *command, *params, *shortcut, *title;
979 while (WMenuParserGetLine(parser, &title, &command, &params, &shortcut)) {
981 if (command == NULL || !command[0]) {
982 WMenuParserError(parser, _("missing command in menu config") );
983 freeline(title, command, params, shortcut);
984 goto error;
987 if (strcasecmp(command, "MENU") == 0) {
988 WMenu *cascade;
990 /* start submenu */
992 cascade = wMenuCreate(scr, M_(title), False);
993 cascade->on_destroy = removeShortcutsForMenu;
994 if (!parseCascade(scr, cascade, parser)) {
995 wMenuDestroy(cascade, True);
996 } else {
997 wMenuEntrySetCascade(menu, wMenuAddCallback(menu, M_(title), NULL, NULL), cascade);
999 } else if (strcasecmp(command, "END") == 0) {
1000 /* end of menu */
1001 freeline(title, command, params, shortcut);
1002 return menu;
1003 } else {
1004 /* normal items */
1005 addMenuEntry(menu, M_(title), shortcut, command, params, WMenuParserGetFilename(parser));
1007 freeline(title, command, params, shortcut);
1010 WMenuParserError(parser, _("syntax error in menu file: END declaration missing") );
1012 error:
1013 return NULL;
1016 static WMenu *readMenuFile(WScreen *scr, const char *file_name)
1018 WMenu *menu = NULL;
1019 FILE *file = NULL;
1020 WMenuParser parser;
1021 char *command, *params, *shortcut, *title;
1023 file = fopen(file_name, "rb");
1024 if (!file) {
1025 werror(_("%s:could not open menu file"), file_name);
1026 return NULL;
1028 parser = WMenuParserCreate(file_name, file, DEF_CONFIG_PATHS);
1029 menu_parser_register_macros(parser);
1031 while (WMenuParserGetLine(parser, &title, &command, &params, &shortcut)) {
1033 if (command == NULL || !command[0]) {
1034 WMenuParserError(parser, _("missing command in menu config") );
1035 freeline(title, command, params, shortcut);
1036 break;
1038 if (strcasecmp(command, "MENU") == 0) {
1039 menu = wMenuCreate(scr, M_(title), True);
1040 menu->on_destroy = removeShortcutsForMenu;
1041 if (!parseCascade(scr, menu, parser)) {
1042 wMenuDestroy(menu, True);
1043 menu = NULL;
1045 freeline(title, command, params, shortcut);
1046 break;
1047 } else {
1048 WMenuParserError(parser, _("invalid menu file, MENU command is missing") );
1049 freeline(title, command, params, shortcut);
1050 break;
1052 freeline(title, command, params, shortcut);
1055 WMenuParserDelete(parser);
1056 fclose(file);
1058 return menu;
1061 /************ Menu Configuration From Pipe *************/
1062 static WMenu *readPLMenuPipe(WScreen * scr, char **file_name)
1064 WMPropList *plist = NULL;
1065 WMenu *menu = NULL;
1066 char *filename;
1067 char flat_file[MAXLINE];
1068 int i;
1070 flat_file[0] = '\0';
1072 for (i = 0; file_name[i] != NULL; i++) {
1073 strcat(flat_file, file_name[i]);
1074 strcat(flat_file, " ");
1076 filename = flat_file + (flat_file[1] == '|' ? 2 : 1);
1078 plist = WMReadPropListFromPipe(filename);
1080 if (!plist)
1081 return NULL;
1083 menu = configureMenu(scr, plist, False);
1085 WMReleasePropList(plist);
1087 if (!menu)
1088 return NULL;
1090 menu->on_destroy = removeShortcutsForMenu;
1091 return menu;
1094 static WMenu *readMenuPipe(WScreen * scr, char **file_name)
1096 WMenu *menu = NULL;
1097 FILE *file = NULL;
1098 WMenuParser parser;
1099 char *command, *params, *shortcut, *title;
1100 char *filename;
1101 char flat_file[MAXLINE];
1102 int i;
1104 flat_file[0] = '\0';
1106 for (i = 0; file_name[i] != NULL; i++) {
1107 strcat(flat_file, file_name[i]);
1108 strcat(flat_file, " ");
1110 filename = flat_file + (flat_file[1] == '|' ? 2 : 1);
1112 file = popen(filename, "r");
1113 if (!file) {
1114 werror(_("%s:could not open menu file"), filename);
1115 return NULL;
1117 parser = WMenuParserCreate(flat_file, file, DEF_CONFIG_PATHS);
1118 menu_parser_register_macros(parser);
1120 while (WMenuParserGetLine(parser, &title, &command, &params, &shortcut)) {
1122 if (command == NULL || !command[0]) {
1123 WMenuParserError(parser, _("missing command in menu config") );
1124 freeline(title, command, params, shortcut);
1125 break;
1127 if (strcasecmp(command, "MENU") == 0) {
1128 menu = wMenuCreate(scr, M_(title), True);
1129 menu->on_destroy = removeShortcutsForMenu;
1130 if (!parseCascade(scr, menu, parser)) {
1131 wMenuDestroy(menu, True);
1132 menu = NULL;
1134 freeline(title, command, params, shortcut);
1135 break;
1136 } else {
1137 WMenuParserError(parser, _("no title given for the root menu") );
1138 freeline(title, command, params, shortcut);
1139 break;
1142 freeline(title, command, params, shortcut);
1145 WMenuParserDelete(parser);
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 if (data->name)
1349 wfree(data->name);
1350 wfree(data);
1353 WM_ITERATE_ARRAY(files, data, iter) {
1354 /* executable: add as entry */
1355 length = strlen(path[data->index]) + strlen(data->name) + 6;
1356 if (command)
1357 length += strlen(command);
1359 buffer = malloc(length);
1360 if (!buffer) {
1361 werror(_("out of memory while constructing directory menu %s"), path[data->index]);
1362 break;
1365 have_space = strchr(path[data->index], ' ') != NULL || strchr(data->name, ' ') != NULL;
1366 if (command != NULL) {
1367 strcpy(buffer, command);
1368 strcat(buffer, " ");
1369 if (have_space)
1370 strcat(buffer, "\"");
1371 strcat(buffer, path[data->index]);
1372 } else {
1373 if (have_space) {
1374 buffer[0] = '"';
1375 buffer[1] = 0;
1376 strcat(buffer, path[data->index]);
1377 } else {
1378 strcpy(buffer, path[data->index]);
1381 strcat(buffer, "/");
1382 strcat(buffer, data->name);
1383 if (have_space)
1384 strcat(buffer, "\"");
1386 if (stripExtension) {
1387 char *ptr = strrchr(data->name, '.');
1388 if (ptr && ptr != data->name)
1389 *ptr = 0;
1391 addMenuEntry(menu, M_(data->name), NULL, "SHEXEC", buffer, path[data->index]);
1393 wfree(buffer);
1394 if (data->name)
1395 wfree(data->name);
1396 wfree(data);
1399 WMFreeArray(files);
1400 WMFreeArray(dirs);
1402 return menu;
1405 /************ Menu Configuration From WMRootMenu *************/
1407 static WMenu *makeDefaultMenu(WScreen * scr)
1409 WMenu *menu = NULL;
1411 menu = wMenuCreate(scr, _("Commands"), True);
1412 wMenuAddCallback(menu, M_("XTerm"), execCommand, "xterm");
1413 wMenuAddCallback(menu, M_("rxvt"), execCommand, "rxvt");
1414 wMenuAddCallback(menu, _("Restart"), restartCommand, NULL);
1415 wMenuAddCallback(menu, _("Exit..."), exitCommand, NULL);
1416 return menu;
1420 *----------------------------------------------------------------------
1421 * configureMenu--
1422 * Reads root menu configuration from defaults database.
1424 *----------------------------------------------------------------------
1426 static WMenu *configureMenu(WScreen * scr, WMPropList * definition, Bool includeGlobals)
1428 WMenu *menu = NULL;
1429 WMPropList *elem;
1430 int i, count;
1431 WMPropList *title, *command, *params;
1432 char *tmp, *mtitle;
1434 if (WMIsPLString(definition)) {
1435 struct stat stat_buf;
1436 char *path = NULL;
1437 Bool menu_is_default = False;
1439 /* menu definition is a string. Probably a path, so parse the file */
1441 tmp = wexpandpath(WMGetFromPLString(definition));
1443 path = getLocalizedMenuFile(tmp);
1445 if (!path)
1446 path = wfindfile(DEF_CONFIG_PATHS, tmp);
1448 if (!path) {
1449 path = wfindfile(DEF_CONFIG_PATHS, DEF_MENU_FILE);
1450 menu_is_default = True;
1453 if (!path) {
1454 werror(_("could not find menu file \"%s\" referenced in WMRootMenu"), tmp);
1455 wfree(tmp);
1456 return NULL;
1459 if (stat(path, &stat_buf) < 0) {
1460 werror(_("could not access menu \"%s\" referenced in WMRootMenu"), path);
1461 wfree(path);
1462 wfree(tmp);
1463 return NULL;
1466 if (!scr->root_menu || stat_buf.st_mtime > scr->root_menu->timestamp
1467 /* if the pointer in WMRootMenu has changed */
1468 || WDRootMenu->timestamp > scr->root_menu->timestamp) {
1470 if (menu_is_default) {
1471 wwarning(_
1472 ("using default menu file \"%s\" as the menu referenced in WMRootMenu could not be found "),
1473 path);
1476 menu = readMenuFile(scr, path);
1477 if (menu)
1478 menu->timestamp = WMAX(stat_buf.st_mtime, WDRootMenu->timestamp);
1479 } else {
1480 menu = NULL;
1482 wfree(path);
1483 wfree(tmp);
1485 return menu;
1488 count = WMGetPropListItemCount(definition);
1489 if (count == 0)
1490 return NULL;
1492 elem = WMGetFromPLArray(definition, 0);
1493 if (!WMIsPLString(elem)) {
1494 tmp = WMGetPropListDescription(elem, False);
1495 wwarning(_("%s:format error in root menu configuration \"%s\""), "WMRootMenu", tmp);
1496 wfree(tmp);
1497 return NULL;
1499 mtitle = WMGetFromPLString(elem);
1501 menu = wMenuCreate(scr, M_(mtitle), False);
1502 menu->on_destroy = removeShortcutsForMenu;
1504 #ifdef GLOBAL_SUBMENU_FILE
1505 if (includeGlobals) {
1506 WMenu *submenu;
1507 WMenuEntry *mentry;
1509 submenu = readMenuFile(scr, GLOBAL_SUBMENU_FILE);
1511 if (submenu) {
1512 mentry = wMenuAddCallback(menu, submenu->frame->title, NULL, NULL);
1513 wMenuEntrySetCascade(menu, mentry, submenu);
1516 #endif
1518 for (i = 1; i < count; i++) {
1519 elem = WMGetFromPLArray(definition, i);
1520 #if 0
1521 if (WMIsPLString(elem)) {
1522 char *file;
1524 file = WMGetFromPLString(elem);
1527 #endif
1528 if (!WMIsPLArray(elem) || WMGetPropListItemCount(elem) < 2)
1529 goto error;
1531 if (WMIsPLArray(WMGetFromPLArray(elem, 1))) {
1532 WMenu *submenu;
1533 WMenuEntry *mentry;
1535 /* submenu */
1536 submenu = configureMenu(scr, elem, True);
1537 if (submenu) {
1538 mentry = wMenuAddCallback(menu, submenu->frame->title, NULL, NULL);
1539 wMenuEntrySetCascade(menu, mentry, submenu);
1541 } else {
1542 int idx = 0;
1543 WMPropList *shortcut;
1544 /* normal entry */
1546 title = WMGetFromPLArray(elem, idx++);
1547 shortcut = WMGetFromPLArray(elem, idx++);
1548 if (strcmp(WMGetFromPLString(shortcut), "SHORTCUT") == 0) {
1549 shortcut = WMGetFromPLArray(elem, idx++);
1550 command = WMGetFromPLArray(elem, idx++);
1551 } else {
1552 command = shortcut;
1553 shortcut = NULL;
1555 params = WMGetFromPLArray(elem, idx++);
1557 if (!title || !command)
1558 goto error;
1560 addMenuEntry(menu, M_(WMGetFromPLString(title)),
1561 shortcut ? WMGetFromPLString(shortcut) : NULL,
1562 WMGetFromPLString(command),
1563 params ? WMGetFromPLString(params) : NULL, "WMRootMenu");
1565 continue;
1567 error:
1568 tmp = WMGetPropListDescription(elem, False);
1569 wwarning(_("%s:format error in root menu configuration \"%s\""), "WMRootMenu", tmp);
1570 wfree(tmp);
1573 return menu;
1577 *----------------------------------------------------------------------
1578 * OpenRootMenu--
1579 * Opens the root menu, parsing the menu configuration from the
1580 * defaults database.
1581 * If the menu is already mapped and is not sticked to the
1582 * root window, it will be unmapped.
1584 * Side effects:
1585 * The menu may be remade.
1587 * Notes:
1588 * Construction of OPEN_MENU entries are delayed to the moment the
1589 * user map's them.
1590 *----------------------------------------------------------------------
1592 void OpenRootMenu(WScreen * scr, int x, int y, int keyboard)
1594 WMenu *menu = NULL;
1595 WMPropList *definition;
1597 static WMPropList *domain=NULL;
1599 if (!domain) {
1600 domain = WMCreatePLString("WMRootMenu");
1604 scr->flags.root_menu_changed_shortcuts = 0;
1605 scr->flags.added_workspace_menu = 0;
1606 scr->flags.added_windows_menu = 0;
1608 if (scr->root_menu && scr->root_menu->flags.mapped) {
1609 menu = scr->root_menu;
1610 if (!menu->flags.buttoned) {
1611 wMenuUnmap(menu);
1612 } else {
1613 wRaiseFrame(menu->frame->core);
1615 if (keyboard)
1616 wMenuMapAt(menu, 0, 0, True);
1617 else
1618 wMenuMapCopyAt(menu, x - menu->frame->core->width / 2, y);
1620 return;
1623 definition = WDRootMenu->dictionary;
1626 definition = PLGetDomain(domain);
1628 if (definition) {
1629 if (WMIsPLArray(definition)) {
1630 if (!scr->root_menu || WDRootMenu->timestamp > scr->root_menu->timestamp) {
1631 menu = configureMenu(scr, definition, True);
1632 if (menu)
1633 menu->timestamp = WDRootMenu->timestamp;
1635 } else
1636 menu = NULL;
1637 } else {
1638 menu = configureMenu(scr, definition, True);
1642 if (!menu) {
1643 /* menu hasn't changed or could not be read */
1644 if (!scr->root_menu) {
1645 wMessageDialog(scr, _("Error"),
1646 _("The applications menu could not be loaded. "
1647 "Look at the console output for a detailed "
1648 "description of the errors."), _("OK"), NULL, NULL);
1650 menu = makeDefaultMenu(scr);
1651 scr->root_menu = menu;
1653 menu = scr->root_menu;
1654 } else {
1655 /* new root menu */
1656 if (scr->root_menu) {
1657 wMenuDestroy(scr->root_menu, True);
1659 scr->root_menu = menu;
1661 if (menu) {
1662 int newx, newy;
1664 if (keyboard && x == 0 && y == 0) {
1665 newx = newy = 0;
1666 } else if (keyboard && x == scr->scr_width / 2 && y == scr->scr_height / 2) {
1667 newx = x - menu->frame->core->width / 2;
1668 newy = y - menu->frame->core->height / 2;
1669 } else {
1670 newx = x - menu->frame->core->width / 2;
1671 newy = y;
1673 wMenuMapAt(menu, newx, newy, keyboard);
1676 if (scr->flags.root_menu_changed_shortcuts)
1677 rebindKeygrabs(scr);