Improve dockapp recognition
[wmaker-crm.git] / src / rootmenu.c
blobfba8ee26058c3b83d1bffdc7afc11d3521bb65c0
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;
59 extern WDDomain *WDRootMenu;
60 extern Cursor wCursor[WCUR_LAST];
61 extern WPreferences wPreferences;
63 static WMenu *readMenuPipe(WScreen * scr, char **file_name);
64 static WMenu *readMenuFile(WScreen * scr, char *file_name);
65 static WMenu *readMenuDirectory(WScreen * scr, char *title, char **file_name, char *command);
67 typedef struct Shortcut {
68 struct Shortcut *next;
70 int modifier;
71 KeyCode keycode;
72 WMenuEntry *entry;
73 WMenu *menu;
74 } Shortcut;
76 static Shortcut *shortcutList = NULL;
79 * Syntax:
80 * # main menu
81 * "Menu Name" MENU
82 * "Title" EXEC command_to_exec -params
83 * "Submenu" MENU
84 * "Title" EXEC command_to_exec -params
85 * "Submenu" END
86 * "Workspaces" WORKSPACE_MENU
87 * "Title" built_in_command
88 * "Quit" EXIT
89 * "Quick Quit" EXIT QUICK
90 * "Menu Name" END
92 * Commands may be preceded by SHORTCUT key
94 * Built-in commands:
96 * INFO_PANEL - shows the Info Panel
97 * LEGAL_PANEL - shows the Legal info panel
98 * SHUTDOWN [QUICK] - closes the X server [without confirmation]
99 * REFRESH - forces the desktop to be repainted
100 * EXIT [QUICK] - exit the window manager [without confirmation]
101 * EXEC <program> - execute an external program
102 * SHEXEC <command> - execute a shell command
103 * WORKSPACE_MENU - places the workspace submenu
104 * ARRANGE_ICONS
105 * RESTART [<window manager>] - restarts the window manager
106 * SHOW_ALL - unhide all windows on workspace
107 * HIDE_OTHERS - hides all windows excep the focused one
108 * OPEN_MENU file - read menu data from file which must be a valid menu file.
109 * OPEN_MENU /some/dir [/some/other/dir ...] [WITH command -options]
110 * - read menu data from directory(ies) and
111 * eventually precede each with a command.
112 * OPEN_MENU | command
113 * - opens command and uses its stdout to construct and insert
114 * the resulting menu in current position. The output of
115 * command must be a valid menu description.
116 * The space between '|' and command is optional.
117 * || will do the same, but will not cache the contents.
118 * SAVE_SESSION - saves the current state of the desktop, which include
119 * all running applications, all their hints (geometry,
120 * position on screen, workspace they live on, the dock
121 * or clip from where they were launched, and
122 * if minimized, shaded or hidden. Also saves the current
123 * workspace the user is on. All will be restored on every
124 * start of windowmaker until another SAVE_SESSION or
125 * CLEAR_SESSION is used. If SaveSessionOnExit = Yes; in
126 * WindowMaker domain file, then saving is automatically
127 * done on every windowmaker exit, overwriting any
128 * SAVE_SESSION or CLEAR_SESSION (see below). Also save
129 * dock state now.
130 * CLEAR_SESSION - clears any previous saved session. This will not have
131 * any effect if SaveSessionOnExit is True.
135 #define M_QUICK 1
137 /* menu commands */
139 static void execCommand(WMenu * menu, WMenuEntry * entry)
141 char *cmdline;
143 cmdline = ExpandOptions(menu->frame->screen_ptr, (char *)entry->clientdata);
145 XGrabPointer(dpy, menu->frame->screen_ptr->root_win, True, 0,
146 GrabModeAsync, GrabModeAsync, None, wCursor[WCUR_WAIT], CurrentTime);
147 XSync(dpy, 0);
149 if (cmdline) {
150 ExecuteShellCommand(menu->frame->screen_ptr, cmdline);
151 wfree(cmdline);
153 XUngrabPointer(dpy, CurrentTime);
154 XSync(dpy, 0);
157 static void exitCommand(WMenu * menu, WMenuEntry * entry)
159 static int inside = 0;
160 int result;
162 /* prevent reentrant calls */
163 if (inside)
164 return;
165 inside = 1;
167 #define R_CANCEL 0
168 #define R_EXIT 1
170 result = R_CANCEL;
172 if ((long)entry->clientdata == M_QUICK) {
173 result = R_EXIT;
174 } else {
175 int r, oldSaveSessionFlag;
177 oldSaveSessionFlag = wPreferences.save_session_on_exit;
178 r = wExitDialog(menu->frame->screen_ptr, _("Exit"),
179 _("Exit window manager?"), _("Exit"), _("Cancel"), NULL);
181 if (r == WAPRDefault) {
182 result = R_EXIT;
183 } else if (r == WAPRAlternate) {
184 /* Don't modify the "save session on exit" flag if the
185 * user canceled the operation. */
186 wPreferences.save_session_on_exit = oldSaveSessionFlag;
189 if (result == R_EXIT)
190 Shutdown(WSExitMode);
192 #undef R_EXIT
193 #undef R_CANCEL
194 inside = 0;
197 static void shutdownCommand(WMenu * menu, WMenuEntry * entry)
199 static int inside = 0;
200 int result;
202 /* prevent reentrant calls */
203 if (inside)
204 return;
205 inside = 1;
207 #define R_CANCEL 0
208 #define R_CLOSE 1
209 #define R_KILL 2
211 result = R_CANCEL;
212 if ((long)entry->clientdata == M_QUICK)
213 result = R_CLOSE;
214 else {
216 int r, oldSaveSessionFlag;
218 oldSaveSessionFlag = wPreferences.save_session_on_exit;
220 r = wExitDialog(menu->frame->screen_ptr,
221 _("Kill X session"),
222 _("Kill Window System session?\n"
223 "(all applications will be closed)"), _("Kill"), _("Cancel"), NULL);
224 if (r == WAPRDefault) {
225 result = R_KILL;
226 } else if (r == WAPRAlternate) {
227 /* Don't modify the "save session on exit" flag if the
228 * user canceled the operation. */
229 wPreferences.save_session_on_exit = oldSaveSessionFlag;
234 if (result != R_CANCEL) {
236 Shutdown(WSKillMode);
239 #undef R_CLOSE
240 #undef R_CANCEL
241 #undef R_KILL
242 inside = 0;
245 static void restartCommand(WMenu * menu, WMenuEntry * entry)
247 Shutdown(WSRestartPreparationMode);
248 Restart((char *)entry->clientdata, False);
249 Restart(NULL, True);
252 static void refreshCommand(WMenu * menu, WMenuEntry * entry)
254 wRefreshDesktop(menu->frame->screen_ptr);
257 static void arrangeIconsCommand(WMenu * menu, WMenuEntry * entry)
259 wArrangeIcons(menu->frame->screen_ptr, True);
262 static void showAllCommand(WMenu * menu, WMenuEntry * entry)
264 wShowAllWindows(menu->frame->screen_ptr);
267 static void hideOthersCommand(WMenu * menu, WMenuEntry * entry)
269 wHideOtherApplications(menu->frame->screen_ptr->focused_window);
272 static void saveSessionCommand(WMenu * menu, WMenuEntry * entry)
274 if (!wPreferences.save_session_on_exit)
275 wSessionSaveState(menu->frame->screen_ptr);
277 wScreenSaveState(menu->frame->screen_ptr);
280 static void clearSessionCommand(WMenu * menu, WMenuEntry * entry)
282 wSessionClearState(menu->frame->screen_ptr);
283 wScreenSaveState(menu->frame->screen_ptr);
286 static void infoPanelCommand(WMenu * menu, WMenuEntry * entry)
288 wShowInfoPanel(menu->frame->screen_ptr);
291 static void legalPanelCommand(WMenu * menu, WMenuEntry * entry)
293 wShowLegalPanel(menu->frame->screen_ptr);
296 /********************************************************************/
298 static char *getLocalizedMenuFile(char *menu)
300 char *buffer, *ptr, *locale;
301 int len;
303 if (!Locale)
304 return NULL;
306 len = strlen(menu) + strlen(Locale) + 8;
307 buffer = wmalloc(len);
309 /* try menu.locale_name */
310 snprintf(buffer, len, "%s.%s", menu, Locale);
311 if (access(buffer, F_OK) == 0) {
312 return buffer;
315 /* position of locale in our buffer */
316 locale = buffer + strlen(menu) + 1;
318 /* check if it is in the form aa_bb.encoding and check for aa_bb */
319 ptr = strchr(locale, '.');
320 if (ptr) {
321 *ptr = 0;
322 if (access(buffer, F_OK) == 0) {
323 return buffer;
326 /* now check for aa */
327 ptr = strchr(locale, '_');
328 if (ptr) {
329 *ptr = 0;
330 if (access(buffer, F_OK) == 0) {
331 return buffer;
335 wfree(buffer);
337 return NULL;
340 Bool wRootMenuPerformShortcut(XEvent * event)
342 WScreen *scr = wScreenForRootWindow(event->xkey.root);
343 Shortcut *ptr;
344 int modifiers;
345 int done = 0;
347 /* ignore CapsLock */
348 modifiers = event->xkey.state & ValidModMask;
350 for (ptr = shortcutList; ptr != NULL; ptr = ptr->next) {
351 if (ptr->keycode == 0 || ptr->menu->menu->screen_ptr != scr)
352 continue;
354 if (ptr->keycode == event->xkey.keycode && ptr->modifier == modifiers) {
355 (*ptr->entry->callback) (ptr->menu, ptr->entry);
356 done = True;
360 return done;
363 void wRootMenuBindShortcuts(Window window)
365 Shortcut *ptr;
367 ptr = shortcutList;
368 while (ptr) {
369 if (ptr->modifier != AnyModifier) {
370 XGrabKey(dpy, ptr->keycode, ptr->modifier | LockMask,
371 window, True, GrabModeAsync, GrabModeAsync);
372 #ifdef NUMLOCK_HACK
373 wHackedGrabKey(ptr->keycode, ptr->modifier, window, True, GrabModeAsync, GrabModeAsync);
374 #endif
376 XGrabKey(dpy, ptr->keycode, ptr->modifier, window, True, GrabModeAsync, GrabModeAsync);
377 ptr = ptr->next;
381 static void rebindKeygrabs(WScreen * scr)
383 WWindow *wwin;
385 wwin = scr->focused_window;
387 while (wwin != NULL) {
388 XUngrabKey(dpy, AnyKey, AnyModifier, wwin->frame->core->window);
390 if (!WFLAGP(wwin, no_bind_keys)) {
391 wWindowSetKeyGrabs(wwin);
393 wwin = wwin->prev;
397 static void removeShortcutsForMenu(WMenu * menu)
399 Shortcut *ptr, *tmp;
400 Shortcut *newList = NULL;
402 ptr = shortcutList;
403 while (ptr != NULL) {
404 tmp = ptr->next;
405 if (ptr->menu == menu) {
406 wfree(ptr);
407 } else {
408 ptr->next = newList;
409 newList = ptr;
411 ptr = tmp;
413 shortcutList = newList;
414 menu->menu->screen_ptr->flags.root_menu_changed_shortcuts = 1;
417 static Bool addShortcut(char *file, char *shortcutDefinition, WMenu * menu, WMenuEntry * entry)
419 Shortcut *ptr;
420 KeySym ksym;
421 char *k;
422 char buf[MAX_SHORTCUT_LENGTH], *b;
424 ptr = wmalloc(sizeof(Shortcut));
426 strncpy(buf, shortcutDefinition, MAX_SHORTCUT_LENGTH);
427 b = (char *)buf;
429 /* get modifiers */
430 ptr->modifier = 0;
431 while ((k = strchr(b, '+')) != NULL) {
432 int mod;
434 *k = 0;
435 mod = wXModifierFromKey(b);
436 if (mod < 0) {
437 wwarning(_("%s: invalid key modifier \"%s\""), file, b);
438 wfree(ptr);
439 return False;
441 ptr->modifier |= mod;
443 b = k + 1;
446 /* get key */
447 ksym = XStringToKeysym(b);
449 if (ksym == NoSymbol) {
450 wwarning(_("%s:invalid kbd shortcut specification \"%s\" for entry %s"),
451 file, shortcutDefinition, entry->text);
452 wfree(ptr);
453 return False;
456 ptr->keycode = XKeysymToKeycode(dpy, ksym);
457 if (ptr->keycode == 0) {
458 wwarning(_("%s:invalid key in shortcut \"%s\" for entry %s"), file,
459 shortcutDefinition, entry->text);
460 wfree(ptr);
461 return False;
464 ptr->menu = menu;
465 ptr->entry = entry;
467 ptr->next = shortcutList;
468 shortcutList = ptr;
470 menu->menu->screen_ptr->flags.root_menu_changed_shortcuts = 1;
472 return True;
475 /*******************************/
477 static char *cropline(char *line)
479 char *end;
481 if (strlen(line) == 0)
482 return line;
484 end = &(line[strlen(line)]) - 1;
485 while (isspace(*line) && *line != 0)
486 line++;
487 while (end > line && isspace(*end)) {
488 *end = 0;
489 end--;
491 return line;
494 static char *next_token(char *line, char **next)
496 char *tmp, c;
497 char *ret;
499 *next = NULL;
500 while (*line == ' ' || *line == '\t')
501 line++;
503 tmp = line;
505 if (*tmp == '"') {
506 tmp++;
507 line++;
508 while (*tmp != 0 && *tmp != '"')
509 tmp++;
510 if (*tmp != '"') {
511 wwarning(_("%s: unmatched '\"' in menu file"), line);
512 return NULL;
514 } else {
515 do {
516 if (*tmp == '\\')
517 tmp++;
519 if (*tmp != 0)
520 tmp++;
522 } while (*tmp != 0 && *tmp != ' ' && *tmp != '\t');
525 c = *tmp;
526 *tmp = 0;
527 ret = wstrdup(line);
528 *tmp = c;
530 if (c == 0)
531 return ret;
532 else
533 tmp++;
535 /* skip blanks */
536 while (*tmp == ' ' || *tmp == '\t')
537 tmp++;
539 if (*tmp != 0)
540 *next = tmp;
542 return ret;
545 static void separateCommand(char *line, char ***file, char **command)
547 char *token, *tmp = line;
548 WMArray *array = WMCreateArray(4);
549 int count, i;
551 *file = NULL;
552 *command = NULL;
553 do {
554 token = next_token(tmp, &tmp);
555 if (token) {
556 if (strcmp(token, "WITH") == 0) {
557 if (tmp != NULL && *tmp != 0)
558 *command = wstrdup(tmp);
559 else
560 wwarning(_("%s: missing command"), line);
561 break;
563 WMAddToArray(array, token);
565 } while (token != NULL && tmp != NULL);
567 count = WMGetArrayItemCount(array);
568 if (count > 0) {
569 *file = wmalloc(sizeof(char *) * (count + 1));
570 (*file)[count] = NULL;
571 for (i = 0; i < count; i++) {
572 (*file)[i] = WMGetFromArray(array, i);
575 WMFreeArray(array);
578 static void constructMenu(WMenu * menu, WMenuEntry * entry)
580 WMenu *submenu;
581 struct stat stat_buf;
582 char **path;
583 char *cmd;
584 char *lpath = NULL;
585 int i, first = -1;
586 time_t last = 0;
588 separateCommand((char *)entry->clientdata, &path, &cmd);
589 if (path == NULL || *path == NULL || **path == 0) {
590 wwarning(_("invalid OPEN_MENU specification: %s"), (char *)entry->clientdata);
591 return;
594 if (path[0][0] == '|') {
595 /* pipe menu */
597 if (!menu->cascades[entry->cascade] || menu->cascades[entry->cascade]->timestamp == 0) {
598 /* parse pipe */
600 submenu = readMenuPipe(menu->frame->screen_ptr, path);
602 if (submenu != NULL) {
603 if (path[0][1] == '|')
604 submenu->timestamp = 0;
605 else
606 submenu->timestamp = 1; /* there's no automatic reloading */
608 } else {
609 submenu = NULL;
612 } else {
613 i = 0;
614 while (path[i] != NULL) {
615 char *tmp;
617 if (strcmp(path[i], "-noext") == 0) {
618 i++;
619 continue;
622 tmp = wexpandpath(path[i]);
623 wfree(path[i]);
624 lpath = getLocalizedMenuFile(tmp);
625 if (lpath) {
626 wfree(tmp);
627 path[i] = lpath;
628 lpath = NULL;
629 } else {
630 path[i] = tmp;
633 if (stat(path[i], &stat_buf) == 0) {
634 if (last < stat_buf.st_mtime)
635 last = stat_buf.st_mtime;
636 if (first < 0)
637 first = i;
638 } else {
639 wsyserror(_("%s:could not stat menu"), path[i]);
640 /*goto finish; */
643 i++;
646 if (first < 0) {
647 wsyserror(_("%s:could not stat menu:%s"), "OPEN_MENU", (char *)entry->clientdata);
648 goto finish;
650 stat(path[first], &stat_buf);
651 if (!menu->cascades[entry->cascade]
652 || menu->cascades[entry->cascade]->timestamp < last) {
654 if (S_ISDIR(stat_buf.st_mode)) {
655 /* menu directory */
656 submenu = readMenuDirectory(menu->frame->screen_ptr, entry->text, path, cmd);
657 if (submenu)
658 submenu->timestamp = last;
659 } else if (S_ISREG(stat_buf.st_mode)) {
660 /* menu file */
662 if (cmd || path[1])
663 wwarning(_("too many parameters in OPEN_MENU: %s"),
664 (char *)entry->clientdata);
666 submenu = readMenuFile(menu->frame->screen_ptr, path[first]);
667 if (submenu)
668 submenu->timestamp = stat_buf.st_mtime;
669 } else {
670 submenu = NULL;
672 } else {
673 submenu = NULL;
677 if (submenu) {
678 wMenuEntryRemoveCascade(menu, entry);
679 wMenuEntrySetCascade(menu, entry, submenu);
682 finish:
683 i = 0;
684 while (path[i] != NULL)
685 wfree(path[i++]);
686 wfree(path);
687 if (cmd)
688 wfree(cmd);
691 static void cleanupWorkspaceMenu(WMenu * menu)
693 if (menu->frame->screen_ptr->workspace_menu == menu)
694 menu->frame->screen_ptr->workspace_menu = NULL;
697 static WMenuEntry *addWorkspaceMenu(WScreen * scr, WMenu * menu, char *title)
699 WMenu *wsmenu;
700 WMenuEntry *entry;
702 if (scr->flags.added_workspace_menu) {
703 wwarning(_
704 ("There are more than one WORKSPACE_MENU commands in the applications menu. Only one is allowed."));
705 return NULL;
706 } else {
707 scr->flags.added_workspace_menu = 1;
709 wsmenu = wWorkspaceMenuMake(scr, True);
710 wsmenu->on_destroy = cleanupWorkspaceMenu;
712 scr->workspace_menu = wsmenu;
713 entry = wMenuAddCallback(menu, title, NULL, NULL);
714 wMenuEntrySetCascade(menu, entry, wsmenu);
716 wWorkspaceMenuUpdate(scr, wsmenu);
718 return entry;
721 static void cleanupWindowsMenu(WMenu * menu)
723 if (menu->frame->screen_ptr->switch_menu == menu)
724 menu->frame->screen_ptr->switch_menu = NULL;
727 static WMenuEntry *addWindowsMenu(WScreen * scr, WMenu * menu, char *title)
729 WMenu *wwmenu;
730 WWindow *wwin;
731 WMenuEntry *entry;
733 if (scr->flags.added_windows_menu) {
734 wwarning(_
735 ("There are more than one WINDOWS_MENU commands in the applications menu. Only one is allowed."));
736 return NULL;
737 } else {
738 scr->flags.added_windows_menu = 1;
740 wwmenu = wMenuCreate(scr, _("Window List"), False);
741 wwmenu->on_destroy = cleanupWindowsMenu;
742 scr->switch_menu = wwmenu;
743 wwin = scr->focused_window;
744 while (wwin) {
745 UpdateSwitchMenu(scr, wwin, ACTION_ADD);
747 wwin = wwin->prev;
749 entry = wMenuAddCallback(menu, title, NULL, NULL);
750 wMenuEntrySetCascade(menu, entry, wwmenu);
752 return entry;
755 static WMenuEntry *addMenuEntry(WMenu * menu, char *title, char *shortcut, char *command,
756 char *params, char *file_name)
758 WScreen *scr;
759 WMenuEntry *entry = NULL;
760 Bool shortcutOk = False;
762 if (!menu)
763 return NULL;
764 scr = menu->frame->screen_ptr;
765 if (strcmp(command, "OPEN_MENU") == 0) {
766 if (!params) {
767 wwarning(_("%s:missing parameter for menu command \"%s\""), file_name, command);
768 } else {
769 WMenu *dummy;
770 char *path;
772 path = wfindfile(DEF_CONFIG_PATHS, params);
773 if (!path) {
774 path = wstrdup(params);
776 dummy = wMenuCreate(scr, title, False);
777 dummy->on_destroy = removeShortcutsForMenu;
778 entry = wMenuAddCallback(menu, title, constructMenu, path);
779 entry->free_cdata = free;
780 wMenuEntrySetCascade(menu, entry, dummy);
782 } else if (strcmp(command, "EXEC") == 0) {
783 if (!params)
784 wwarning(_("%s:missing parameter for menu command \"%s\""), file_name, command);
785 else {
786 entry = wMenuAddCallback(menu, title, execCommand, wstrconcat("exec ", params));
787 entry->free_cdata = free;
788 shortcutOk = True;
790 } else if (strcmp(command, "SHEXEC") == 0) {
791 if (!params)
792 wwarning(_("%s:missing parameter for menu command \"%s\""), file_name, command);
793 else {
794 entry = wMenuAddCallback(menu, title, execCommand, wstrdup(params));
795 entry->free_cdata = free;
796 shortcutOk = True;
798 } else if (strcmp(command, "EXIT") == 0) {
800 if (params && strcmp(params, "QUICK") == 0)
801 entry = wMenuAddCallback(menu, title, exitCommand, (void *)M_QUICK);
802 else
803 entry = wMenuAddCallback(menu, title, exitCommand, NULL);
805 shortcutOk = True;
806 } else if (strcmp(command, "SHUTDOWN") == 0) {
808 if (params && strcmp(params, "QUICK") == 0)
809 entry = wMenuAddCallback(menu, title, shutdownCommand, (void *)M_QUICK);
810 else
811 entry = wMenuAddCallback(menu, title, shutdownCommand, NULL);
813 shortcutOk = True;
814 } else if (strcmp(command, "REFRESH") == 0) {
815 entry = wMenuAddCallback(menu, title, refreshCommand, NULL);
817 shortcutOk = True;
818 } else if (strcmp(command, "WORKSPACE_MENU") == 0) {
819 entry = addWorkspaceMenu(scr, menu, title);
821 shortcutOk = True;
822 } else if (strcmp(command, "WINDOWS_MENU") == 0) {
823 entry = addWindowsMenu(scr, menu, title);
825 shortcutOk = True;
826 } else if (strcmp(command, "ARRANGE_ICONS") == 0) {
827 entry = wMenuAddCallback(menu, title, arrangeIconsCommand, NULL);
829 shortcutOk = True;
830 } else if (strcmp(command, "HIDE_OTHERS") == 0) {
831 entry = wMenuAddCallback(menu, title, hideOthersCommand, NULL);
833 shortcutOk = True;
834 } else if (strcmp(command, "SHOW_ALL") == 0) {
835 entry = wMenuAddCallback(menu, title, showAllCommand, NULL);
837 shortcutOk = True;
838 } else if (strcmp(command, "RESTART") == 0) {
839 entry = wMenuAddCallback(menu, title, restartCommand, params ? wstrdup(params) : NULL);
840 entry->free_cdata = free;
841 shortcutOk = True;
842 } else if (strcmp(command, "SAVE_SESSION") == 0) {
843 entry = wMenuAddCallback(menu, title, saveSessionCommand, NULL);
845 shortcutOk = True;
846 } else if (strcmp(command, "CLEAR_SESSION") == 0) {
847 entry = wMenuAddCallback(menu, title, clearSessionCommand, NULL);
848 shortcutOk = True;
849 } else if (strcmp(command, "INFO_PANEL") == 0) {
850 entry = wMenuAddCallback(menu, title, infoPanelCommand, NULL);
851 shortcutOk = True;
852 } else if (strcmp(command, "LEGAL_PANEL") == 0) {
853 entry = wMenuAddCallback(menu, title, legalPanelCommand, NULL);
854 shortcutOk = True;
855 } else {
856 wwarning(_("%s:unknown command \"%s\" in menu config."), file_name, command);
858 return NULL;
861 if (shortcut && entry) {
862 if (!shortcutOk) {
863 wwarning(_("%s:can't add shortcut for entry \"%s\""), file_name, title);
864 } else {
865 if (addShortcut(file_name, shortcut, menu, entry)) {
867 entry->rtext = GetShortcutString(shortcut);
869 entry->rtext = wstrdup(shortcut);
875 return entry;
878 /******************* Menu Configuration From File *******************/
880 static void separateline(char *line, char *title, char *command, char *parameter, char *shortcut)
882 int l, i;
884 l = strlen(line);
886 *title = 0;
887 *command = 0;
888 *parameter = 0;
889 *shortcut = 0;
890 /* get the title */
891 while (isspace(*line) && (*line != 0))
892 line++;
893 if (*line == '"') {
894 line++;
895 i = 0;
896 while (line[i] != '"' && (line[i] != 0))
897 i++;
898 if (line[i] != '"')
899 return;
900 } else {
901 i = 0;
902 while (!isspace(line[i]) && (line[i] != 0))
903 i++;
905 strncpy(title, line, i);
906 title[i++] = 0;
907 line += i;
909 /* get the command or shortcut keyword */
910 while (isspace(*line) && (*line != 0))
911 line++;
912 if (*line == 0)
913 return;
914 i = 0;
915 while (!isspace(line[i]) && (line[i] != 0))
916 i++;
917 strncpy(command, line, i);
918 command[i++] = 0;
919 line += i;
921 if (strcmp(command, "SHORTCUT") == 0) {
922 /* get the shortcut key */
923 while (isspace(*line) && (*line != 0))
924 line++;
925 if (*line == '"') {
926 line++;
927 i = 0;
928 while (line[i] != '"' && (line[i] != 0))
929 i++;
930 if (line[i] != '"')
931 return;
932 } else {
933 i = 0;
934 while (!isspace(line[i]) && (line[i] != 0))
935 i++;
937 strncpy(shortcut, line, i);
938 shortcut[i++] = 0;
939 line += i;
941 *command = 0;
943 /* get the command */
944 while (isspace(*line) && (*line != 0))
945 line++;
946 if (*line == 0)
947 return;
948 i = 0;
949 while (!isspace(line[i]) && (line[i] != 0))
950 i++;
951 strncpy(command, line, i);
952 command[i++] = 0;
953 line += i;
956 /* get the parameters */
957 while (isspace(*line) && (*line != 0))
958 line++;
959 if (*line == 0)
960 return;
962 if (*line == '"') {
963 line++;
964 l = 0;
965 while (line[l] != 0 && line[l] != '"') {
966 parameter[l] = line[l];
967 l++;
969 parameter[l] = 0;
970 return;
973 l = strlen(line);
974 while (isspace(line[l]) && (l > 0))
975 l--;
976 strncpy(parameter, line, l);
977 parameter[l] = 0;
980 static WMenu *parseCascade(WScreen * scr, WMenu * menu, FILE * file, char *file_name)
982 char linebuf[MAXLINE];
983 char elinebuf[MAXLINE];
984 char title[MAXLINE];
985 char command[MAXLINE];
986 char shortcut[MAXLINE];
987 char params[MAXLINE];
988 char *line;
990 while (!feof(file)) {
991 int lsize, ok;
993 ok = 0;
994 fgets(linebuf, MAXLINE, file);
995 line = cropline(linebuf);
996 lsize = strlen(line);
997 do {
998 if (line[lsize - 1] == '\\') {
999 char *line2;
1000 int lsize2;
1001 fgets(elinebuf, MAXLINE, file);
1002 line2 = cropline(elinebuf);
1003 lsize2 = strlen(line2);
1004 if (lsize2 + lsize > MAXLINE) {
1005 wwarning(_("%s:maximal line size exceeded in menu config: %s"),
1006 file_name, line);
1007 ok = 2;
1008 } else {
1009 line[lsize - 1] = 0;
1010 lsize += lsize2 - 1;
1011 strcat(line, line2);
1013 } else {
1014 ok = 1;
1016 } while (!ok && !feof(file));
1017 if (ok == 2)
1018 continue;
1020 if (line[0] == 0 || line[0] == '#' || (line[0] == '/' && line[1] == '/'))
1021 continue;
1023 separateline(line, title, command, params, shortcut);
1025 if (!command[0]) {
1026 wwarning(_("%s:missing command in menu config: %s"), file_name, line);
1027 goto error;
1030 if (strcasecmp(command, "MENU") == 0) {
1031 WMenu *cascade;
1033 /* start submenu */
1035 cascade = wMenuCreate(scr, M_(title), False);
1036 cascade->on_destroy = removeShortcutsForMenu;
1037 if (parseCascade(scr, cascade, file, file_name) == NULL) {
1038 wMenuDestroy(cascade, True);
1039 } else {
1040 wMenuEntrySetCascade(menu, wMenuAddCallback(menu, M_(title), NULL, NULL), cascade);
1042 } else if (strcasecmp(command, "END") == 0) {
1043 /* end of menu */
1044 return menu;
1046 } else {
1047 /* normal items */
1048 addMenuEntry(menu, M_(title), shortcut[0] ? shortcut : NULL, command,
1049 params[0] ? params : NULL, file_name);
1053 wwarning(_("%s:syntax error in menu file:END declaration missing"), file_name);
1054 return menu;
1056 error:
1057 return menu;
1060 static WMenu *readMenuFile(WScreen * scr, char *file_name)
1062 WMenu *menu = NULL;
1063 FILE *file = NULL;
1064 char linebuf[MAXLINE];
1065 char title[MAXLINE];
1066 char shortcut[MAXLINE];
1067 char command[MAXLINE];
1068 char params[MAXLINE];
1069 char *line;
1070 #ifdef USECPP
1071 char *args;
1072 int cpp = 0;
1073 #endif
1075 #ifdef USECPP
1076 if (!wPreferences.flags.nocpp) {
1077 args = MakeCPPArgs(file_name);
1078 if (!args) {
1079 wwarning(_("could not make arguments for menu file preprocessor"));
1080 } else {
1081 snprintf(command, sizeof(command), "%s %s %s", CPP_PATH, args, file_name);
1082 wfree(args);
1083 file = popen(command, "r");
1084 if (!file) {
1085 wsyserror(_("%s:could not open/preprocess menu file"), file_name);
1086 } else {
1087 cpp = 1;
1091 #endif /* USECPP */
1093 if (!file) {
1094 file = fopen(file_name, "rb");
1095 if (!file) {
1096 wsyserror(_("%s:could not open menu file"), file_name);
1097 return NULL;
1101 while (!feof(file)) {
1102 if (!fgets(linebuf, MAXLINE, file))
1103 break;
1104 line = cropline(linebuf);
1105 if (line[0] == 0 || line[0] == '#' || (line[0] == '/' && line[1] == '/'))
1106 continue;
1108 separateline(line, title, command, params, shortcut);
1110 if (!command[0]) {
1111 wwarning(_("%s:missing command in menu config: %s"), file_name, line);
1112 break;
1114 if (strcasecmp(command, "MENU") == 0) {
1115 menu = wMenuCreate(scr, M_(title), True);
1116 menu->on_destroy = removeShortcutsForMenu;
1117 if (!parseCascade(scr, menu, file, file_name)) {
1118 wMenuDestroy(menu, True);
1120 break;
1121 } else {
1122 wwarning(_("%s:invalid menu file. MENU command is missing"), file_name);
1123 break;
1127 #ifdef CPP
1128 if (cpp) {
1129 if (pclose(file) == -1) {
1130 wsyserror(_("error reading preprocessed menu data"));
1132 } else {
1133 fclose(file);
1135 #else
1136 fclose(file);
1137 #endif
1139 return menu;
1142 /************ Menu Configuration From Pipe *************/
1144 static WMenu *readMenuPipe(WScreen * scr, char **file_name)
1146 WMenu *menu = NULL;
1147 FILE *file = NULL;
1148 char linebuf[MAXLINE];
1149 char title[MAXLINE];
1150 char command[MAXLINE];
1151 char params[MAXLINE];
1152 char shortcut[MAXLINE];
1153 char *line;
1154 char *filename;
1155 char flat_file[MAXLINE];
1156 int i;
1157 #ifdef USECPP
1158 char *args;
1159 int cpp = 0;
1160 #endif
1162 flat_file[0] = '\0';
1164 for (i = 0; file_name[i] != NULL; i++) {
1165 strcat(flat_file, file_name[i]);
1166 strcat(flat_file, " ");
1168 filename = flat_file + (flat_file[1] == '|' ? 2 : 1);
1170 #ifdef USECPP
1171 if (!wPreferences.flags.nocpp) {
1172 args = MakeCPPArgs(filename);
1173 if (!args) {
1174 wwarning(_("could not make arguments for menu file preprocessor"));
1175 } else {
1176 snprintf(command, sizeof(command), "%s | %s %s", filename, CPP_PATH, args);
1178 wfree(args);
1179 file = popen(command, "r");
1180 if (!file) {
1181 wsyserror(_("%s:could not open/preprocess menu file"), filename);
1182 } else {
1183 cpp = 1;
1187 #endif /* USECPP */
1189 if (!file) {
1190 file = popen(filename, "rb");
1192 if (!file) {
1193 wsyserror(_("%s:could not open menu file"), filename);
1194 return NULL;
1198 while (!feof(file)) {
1199 if (!fgets(linebuf, MAXLINE, file))
1200 break;
1201 line = cropline(linebuf);
1202 if (line[0] == 0 || line[0] == '#' || (line[0] == '/' && line[1] == '/'))
1203 continue;
1205 separateline(line, title, command, params, shortcut);
1207 if (!command[0]) {
1208 wwarning(_("%s:missing command in menu config: %s"), filename, line);
1209 break;
1211 if (strcasecmp(command, "MENU") == 0) {
1212 menu = wMenuCreate(scr, M_(title), True);
1213 menu->on_destroy = removeShortcutsForMenu;
1214 if (!parseCascade(scr, menu, file, filename)) {
1215 wMenuDestroy(menu, True);
1217 break;
1218 } else {
1219 wwarning(_("%s:no title given for the root menu"), filename);
1220 break;
1224 pclose(file);
1226 return menu;
1229 typedef struct {
1230 char *name;
1231 int index;
1232 } dir_data;
1234 static int myCompare(const void *d1, const void *d2)
1236 dir_data *p1 = *(dir_data **) d1;
1237 dir_data *p2 = *(dir_data **) d2;
1239 return strcmp(p1->name, p2->name);
1242 /************ Menu Configuration From Directory *************/
1244 static Bool isFilePackage(char *file)
1246 int l;
1248 /* check if the extension indicates this file is a
1249 * file package. For now, only recognize .themed */
1251 l = strlen(file);
1253 if (l > 7 && strcmp(&(file[l - 7]), ".themed") == 0) {
1254 return True;
1255 } else {
1256 return False;
1260 static WMenu *readMenuDirectory(WScreen * scr, char *title, char **path, char *command)
1262 DIR *dir;
1263 struct dirent *dentry;
1264 struct stat stat_buf;
1265 WMenu *menu = NULL;
1266 char *buffer;
1267 WMArray *dirs = NULL, *files = NULL;
1268 WMArrayIterator iter;
1269 int length, i, have_space = 0;
1270 dir_data *data;
1271 int stripExtension = 0;
1273 dirs = WMCreateArray(16);
1274 files = WMCreateArray(16);
1276 i = 0;
1277 while (path[i] != NULL) {
1278 if (strcmp(path[i], "-noext") == 0) {
1279 stripExtension = 1;
1280 i++;
1281 continue;
1284 dir = opendir(path[i]);
1285 if (!dir) {
1286 i++;
1287 continue;
1290 while ((dentry = readdir(dir))) {
1292 if (strcmp(dentry->d_name, ".") == 0 || strcmp(dentry->d_name, "..") == 0)
1293 continue;
1295 if (dentry->d_name[0] == '.')
1296 continue;
1298 buffer = malloc(strlen(path[i]) + strlen(dentry->d_name) + 4);
1299 if (!buffer) {
1300 wsyserror(_("out of memory while constructing directory menu %s"), path[i]);
1301 break;
1304 strcpy(buffer, path[i]);
1305 strcat(buffer, "/");
1306 strcat(buffer, dentry->d_name);
1308 if (stat(buffer, &stat_buf) != 0) {
1309 wsyserror(_("%s:could not stat file \"%s\" in menu directory"),
1310 path[i], dentry->d_name);
1311 } else {
1312 Bool isFilePack = False;
1314 data = NULL;
1315 if (S_ISDIR(stat_buf.st_mode)
1316 && !(isFilePack = isFilePackage(dentry->d_name))) {
1318 /* access always returns success for user root */
1319 if (access(buffer, X_OK) == 0) {
1320 /* Directory is accesible. Add to directory list */
1322 data = (dir_data *) wmalloc(sizeof(dir_data));
1323 data->name = wstrdup(dentry->d_name);
1324 data->index = i;
1326 WMAddToArray(dirs, data);
1328 } else if (S_ISREG(stat_buf.st_mode) || isFilePack) {
1329 /* Hack because access always returns X_OK success for user root */
1330 #define S_IXANY (S_IXUSR | S_IXGRP | S_IXOTH)
1331 if ((command != NULL && access(buffer, R_OK) == 0) ||
1332 (command == NULL && access(buffer, X_OK) == 0 &&
1333 (stat_buf.st_mode & S_IXANY))) {
1335 data = (dir_data *) wmalloc(sizeof(dir_data));
1336 data->name = wstrdup(dentry->d_name);
1337 data->index = i;
1339 WMAddToArray(files, data);
1343 wfree(buffer);
1346 closedir(dir);
1347 i++;
1350 if (!WMGetArrayItemCount(dirs) && !WMGetArrayItemCount(files)) {
1351 WMFreeArray(dirs);
1352 WMFreeArray(files);
1353 return NULL;
1356 WMSortArray(dirs, myCompare);
1357 WMSortArray(files, myCompare);
1359 menu = wMenuCreate(scr, M_(title), False);
1360 menu->on_destroy = removeShortcutsForMenu;
1362 WM_ITERATE_ARRAY(dirs, data, iter) {
1363 /* New directory. Use same OPEN_MENU command that was used
1364 * for the current directory. */
1365 length = strlen(path[data->index]) + strlen(data->name) + 6;
1366 if (stripExtension)
1367 length += 7;
1368 if (command)
1369 length += strlen(command) + 6;
1370 buffer = malloc(length);
1371 if (!buffer) {
1372 wsyserror(_("out of memory while constructing directory menu %s"), path[data->index]);
1373 break;
1376 buffer[0] = '\0';
1377 if (stripExtension)
1378 strcat(buffer, "-noext ");
1380 have_space = strchr(path[data->index], ' ') != NULL || strchr(data->name, ' ') != NULL;
1382 if (have_space)
1383 strcat(buffer, "\"");
1384 strcat(buffer, path[data->index]);
1386 strcat(buffer, "/");
1387 strcat(buffer, data->name);
1388 if (have_space)
1389 strcat(buffer, "\"");
1390 if (command) {
1391 strcat(buffer, " WITH ");
1392 strcat(buffer, command);
1395 addMenuEntry(menu, M_(data->name), NULL, "OPEN_MENU", buffer, path[data->index]);
1397 wfree(buffer);
1398 if (data->name)
1399 wfree(data->name);
1400 wfree(data);
1403 WM_ITERATE_ARRAY(files, data, iter) {
1404 /* executable: add as entry */
1405 length = strlen(path[data->index]) + strlen(data->name) + 6;
1406 if (command)
1407 length += strlen(command);
1409 buffer = malloc(length);
1410 if (!buffer) {
1411 wsyserror(_("out of memory while constructing directory menu %s"), path[data->index]);
1412 break;
1415 have_space = strchr(path[data->index], ' ') != NULL || strchr(data->name, ' ') != NULL;
1416 if (command != NULL) {
1417 strcpy(buffer, command);
1418 strcat(buffer, " ");
1419 if (have_space)
1420 strcat(buffer, "\"");
1421 strcat(buffer, path[data->index]);
1422 } else {
1423 if (have_space) {
1424 buffer[0] = '"';
1425 buffer[1] = 0;
1426 strcat(buffer, path[data->index]);
1427 } else {
1428 strcpy(buffer, path[data->index]);
1431 strcat(buffer, "/");
1432 strcat(buffer, data->name);
1433 if (have_space)
1434 strcat(buffer, "\"");
1436 if (stripExtension) {
1437 char *ptr = strrchr(data->name, '.');
1438 if (ptr && ptr != data->name)
1439 *ptr = 0;
1441 addMenuEntry(menu, M_(data->name), NULL, "SHEXEC", buffer, path[data->index]);
1443 wfree(buffer);
1444 if (data->name)
1445 wfree(data->name);
1446 wfree(data);
1449 WMFreeArray(files);
1450 WMFreeArray(dirs);
1452 return menu;
1455 /************ Menu Configuration From WMRootMenu *************/
1457 static WMenu *makeDefaultMenu(WScreen * scr)
1459 WMenu *menu = NULL;
1461 menu = wMenuCreate(scr, _("Commands"), True);
1462 wMenuAddCallback(menu, M_("XTerm"), execCommand, "xterm");
1463 wMenuAddCallback(menu, M_("rxvt"), execCommand, "rxvt");
1464 wMenuAddCallback(menu, _("Restart"), restartCommand, NULL);
1465 wMenuAddCallback(menu, _("Exit..."), exitCommand, NULL);
1466 return menu;
1470 *----------------------------------------------------------------------
1471 * configureMenu--
1472 * Reads root menu configuration from defaults database.
1474 *----------------------------------------------------------------------
1476 static WMenu *configureMenu(WScreen * scr, WMPropList * definition)
1478 WMenu *menu = NULL;
1479 WMPropList *elem;
1480 int i, count;
1481 WMPropList *title, *command, *params;
1482 char *tmp, *mtitle;
1484 if (WMIsPLString(definition)) {
1485 struct stat stat_buf;
1486 char *path = NULL;
1487 Bool menu_is_default = False;
1489 /* menu definition is a string. Probably a path, so parse the file */
1491 tmp = wexpandpath(WMGetFromPLString(definition));
1493 path = getLocalizedMenuFile(tmp);
1495 if (!path)
1496 path = wfindfile(DEF_CONFIG_PATHS, tmp);
1498 if (!path) {
1499 path = wfindfile(DEF_CONFIG_PATHS, DEF_MENU_FILE);
1500 menu_is_default = True;
1503 if (!path) {
1504 wsyserror(_("could not find menu file \"%s\" referenced in WMRootMenu"), tmp);
1505 wfree(tmp);
1506 return NULL;
1509 if (stat(path, &stat_buf) < 0) {
1510 wsyserror(_("could not access menu \"%s\" referenced in WMRootMenu"), path);
1511 wfree(path);
1512 wfree(tmp);
1513 return NULL;
1516 if (!scr->root_menu || stat_buf.st_mtime > scr->root_menu->timestamp
1517 /* if the pointer in WMRootMenu has changed */
1518 || WDRootMenu->timestamp > scr->root_menu->timestamp) {
1520 if (menu_is_default) {
1521 wwarning(_
1522 ("using default menu file \"%s\" as the menu referenced in WMRootMenu could not be found "),
1523 path);
1526 menu = readMenuFile(scr, path);
1527 if (menu)
1528 menu->timestamp = WMAX(stat_buf.st_mtime, WDRootMenu->timestamp);
1529 } else {
1530 menu = NULL;
1532 wfree(path);
1533 wfree(tmp);
1535 return menu;
1538 count = WMGetPropListItemCount(definition);
1539 if (count == 0)
1540 return NULL;
1542 elem = WMGetFromPLArray(definition, 0);
1543 if (!WMIsPLString(elem)) {
1544 tmp = WMGetPropListDescription(elem, False);
1545 wwarning(_("%s:format error in root menu configuration \"%s\""), "WMRootMenu", tmp);
1546 wfree(tmp);
1547 return NULL;
1549 mtitle = WMGetFromPLString(elem);
1551 menu = wMenuCreate(scr, M_(mtitle), False);
1552 menu->on_destroy = removeShortcutsForMenu;
1554 #ifdef GLOBAL_SUBMENU_FILE
1556 WMenu *submenu;
1557 WMenuEntry *mentry;
1559 submenu = readMenuFile(scr, GLOBAL_SUBMENU_FILE);
1561 if (submenu) {
1562 mentry = wMenuAddCallback(menu, submenu->frame->title, NULL, NULL);
1563 wMenuEntrySetCascade(menu, mentry, submenu);
1566 #endif
1568 for (i = 1; i < count; i++) {
1569 elem = WMGetFromPLArray(definition, i);
1570 #if 0
1571 if (WMIsPLString(elem)) {
1572 char *file;
1574 file = WMGetFromPLString(elem);
1577 #endif
1578 if (!WMIsPLArray(elem) || WMGetPropListItemCount(elem) < 2)
1579 goto error;
1581 if (WMIsPLArray(WMGetFromPLArray(elem, 1))) {
1582 WMenu *submenu;
1583 WMenuEntry *mentry;
1585 /* submenu */
1586 submenu = configureMenu(scr, elem);
1587 if (submenu) {
1588 mentry = wMenuAddCallback(menu, submenu->frame->title, NULL, NULL);
1589 wMenuEntrySetCascade(menu, mentry, submenu);
1591 } else {
1592 int idx = 0;
1593 WMPropList *shortcut;
1594 /* normal entry */
1596 title = WMGetFromPLArray(elem, idx++);
1597 shortcut = WMGetFromPLArray(elem, idx++);
1598 if (strcmp(WMGetFromPLString(shortcut), "SHORTCUT") == 0) {
1599 shortcut = WMGetFromPLArray(elem, idx++);
1600 command = WMGetFromPLArray(elem, idx++);
1601 } else {
1602 command = shortcut;
1603 shortcut = NULL;
1605 params = WMGetFromPLArray(elem, idx++);
1607 if (!title || !command)
1608 goto error;
1610 addMenuEntry(menu, M_(WMGetFromPLString(title)),
1611 shortcut ? WMGetFromPLString(shortcut) : NULL,
1612 WMGetFromPLString(command),
1613 params ? WMGetFromPLString(params) : NULL, "WMRootMenu");
1615 continue;
1617 error:
1618 tmp = WMGetPropListDescription(elem, False);
1619 wwarning(_("%s:format error in root menu configuration \"%s\""), "WMRootMenu", tmp);
1620 wfree(tmp);
1623 return menu;
1627 *----------------------------------------------------------------------
1628 * OpenRootMenu--
1629 * Opens the root menu, parsing the menu configuration from the
1630 * defaults database.
1631 * If the menu is already mapped and is not sticked to the
1632 * root window, it will be unmapped.
1634 * Side effects:
1635 * The menu may be remade.
1637 * Notes:
1638 * Construction of OPEN_MENU entries are delayed to the moment the
1639 * user map's them.
1640 *----------------------------------------------------------------------
1642 void OpenRootMenu(WScreen * scr, int x, int y, int keyboard)
1644 WMenu *menu = NULL;
1645 WMPropList *definition;
1647 static WMPropList *domain=NULL;
1649 if (!domain) {
1650 domain = WMCreatePLString("WMRootMenu");
1654 scr->flags.root_menu_changed_shortcuts = 0;
1655 scr->flags.added_workspace_menu = 0;
1656 scr->flags.added_windows_menu = 0;
1658 if (scr->root_menu && scr->root_menu->flags.mapped) {
1659 menu = scr->root_menu;
1660 if (!menu->flags.buttoned) {
1661 wMenuUnmap(menu);
1662 } else {
1663 wRaiseFrame(menu->frame->core);
1665 if (keyboard)
1666 wMenuMapAt(menu, 0, 0, True);
1667 else
1668 wMenuMapCopyAt(menu, x - menu->frame->core->width / 2, y);
1670 return;
1673 definition = WDRootMenu->dictionary;
1676 definition = PLGetDomain(domain);
1678 if (definition) {
1679 if (WMIsPLArray(definition)) {
1680 if (!scr->root_menu || WDRootMenu->timestamp > scr->root_menu->timestamp) {
1681 menu = configureMenu(scr, definition);
1682 if (menu)
1683 menu->timestamp = WDRootMenu->timestamp;
1685 } else
1686 menu = NULL;
1687 } else {
1688 menu = configureMenu(scr, definition);
1692 if (!menu) {
1693 /* menu hasn't changed or could not be read */
1694 if (!scr->root_menu) {
1695 wMessageDialog(scr, _("Error"),
1696 _("The applications menu could not be loaded. "
1697 "Look at the console output for a detailed "
1698 "description of the errors."), _("OK"), NULL, NULL);
1700 menu = makeDefaultMenu(scr);
1701 scr->root_menu = menu;
1703 menu = scr->root_menu;
1704 } else {
1705 /* new root menu */
1706 if (scr->root_menu) {
1707 wMenuDestroy(scr->root_menu, True);
1709 scr->root_menu = menu;
1711 if (menu) {
1712 int newx, newy;
1714 if (keyboard && x == 0 && y == 0) {
1715 newx = newy = 0;
1716 } else if (keyboard && x == scr->scr_width / 2 && y == scr->scr_height / 2) {
1717 newx = x - menu->frame->core->width / 2;
1718 newy = y - menu->frame->core->height / 2;
1719 } else {
1720 newx = x - menu->frame->core->width / 2;
1721 newy = y;
1723 wMenuMapAt(menu, newx, newy, keyboard);
1726 if (scr->flags.root_menu_changed_shortcuts)
1727 rebindKeygrabs(scr);