1 /* rootmenu.c- user defined menu
3 * Window Maker window manager
5 * Copyright (c) 1997, 1998 Alfredo K. Kojima
7 * This program is free software; you can redistribute it and/or modify
8 * it under the terms of the GNU General Public License as published by
9 * the Free Software Foundation; either version 2 of the License, or
10 * (at your option) any later version.
12 * This program is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 * GNU General Public License for more details.
17 * You should have received a copy of the GNU General Public License
18 * along with this program; if not, write to the Free Software
19 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307,
33 #include <sys/types.h>
40 #include <X11/Xutil.h>
41 #include <X11/Xatom.h>
43 #include "WindowMaker.h"
50 #include "workspace.h"
54 #include "xmodifier.h"
62 extern WDDomain
*WDRootMenu
;
64 extern Cursor wCursor
[WCUR_LAST
];
66 extern Time LastTimestamp
;
68 extern WPreferences wPreferences
;
70 extern int wScreenCount
;
72 static WMenu
*readMenuPipe(WScreen
*scr
, char **file_name
);
73 static WMenu
*readMenuFile(WScreen
*scr
, char *file_name
);
74 static WMenu
*readMenuDirectory(WScreen
*scr
, char *title
, char **file_name
,
78 typedef struct Shortcut
{
79 struct Shortcut
*next
;
89 static Shortcut
*shortcutList
= NULL
;
96 * "Title" EXEC command_to_exec -params
98 * "Title" EXEC command_to_exec -params
100 * "Workspaces" WORKSPACE_MENU
101 * "Title" built_in_command
103 * "Quick Quit" EXIT QUICK
106 * Commands may be preceded by SHORTCUT key
110 * INFO_PANEL - shows the Info Panel
111 * LEGAL_PANEL - shows the Legal info panel
112 * SHUTDOWN [QUICK] - closes the X server [without confirmation]
113 * REFRESH - forces the desktop to be repainted
114 * EXIT [QUICK] - exit the window manager [without confirmation]
115 * EXEC <program> - execute an external program
116 * WORKSPACE_MENU - places the workspace submenu
118 * RESTART [<window manager>] - restarts the window manager
119 * SHOW_ALL - unhide all windows on workspace
120 * HIDE_OTHERS - hides all windows excep the focused one
121 * OPEN_MENU file - read menu data from file which must be a valid menu file.
122 * OPEN_MENU /some/dir [/some/other/dir ...] [WITH command -options]
123 * - read menu data from directory(ies) and
124 * eventually precede each with a command.
125 * OPEN_MENU | command
126 * - opens command and uses its stdout to construct and insert
127 * the resulting menu in current position. The output of
128 * command must be a valid menu description.
129 * The space between '|' and command is optional.
130 * SAVE_SESSION - saves the current state of the desktop, which include
131 * all running applications, all their hints (geometry,
132 * position on screen, workspace they live on, the dock
133 * or clip from where they were launched, and
134 * if minimized, shaded or hidden. Also saves the current
135 * workspace the user is on. All will be restored on every
136 * start of windowmaker until another SAVE_SESSION or
137 * CLEAR_SESSION is used. If SaveSessionOnExit = Yes; in
138 * WindowMaker domain file, then saving is automatically
139 * done on every windowmaker exit, overwriting any
140 * SAVE_SESSION or CLEAR_SESSION (see below).
141 * CLEAR_SESSION - clears any previous saved session. This will not have
142 * any effect if SaveSessionOnExit is True.
146 #define MAX(a,b) ((a)>(b) ? (a) : (b))
154 execCommand(WMenu
*menu
, WMenuEntry
*entry
)
158 cmdline
= ExpandOptions(menu
->frame
->screen_ptr
, (char*)entry
->clientdata
);
160 XGrabPointer(dpy
, menu
->frame
->screen_ptr
->root_win
, True
, 0,
161 GrabModeAsync
, GrabModeAsync
, None
, wCursor
[WCUR_WAIT
],
166 ExecuteShellCommand(menu
->frame
->screen_ptr
, cmdline
);
169 XUngrabPointer(dpy
, CurrentTime
);
175 exitCommand(WMenu
*menu
, WMenuEntry
*entry
)
177 static int inside
= 0;
179 /* prevent reentrant calls */
184 if ((int)entry
->clientdata
==M_QUICK
185 || wMessageDialog(menu
->frame
->screen_ptr
, _("Exit"),
186 _("Exit window manager?"),
187 _("Exit"), _("Cancel"), NULL
)==WAPRDefault
) {
189 printf("Exiting WindowMaker.\n");
191 Shutdown(WSExitMode
);
198 shutdownCommand(WMenu
*menu
, WMenuEntry
*entry
)
200 static int inside
= 0;
203 /* prevent reentrant calls */
214 if ((int)entry
->clientdata
==M_QUICK
)
218 if (wSessionIsManaged()) {
221 r
= wMessageDialog(menu
->frame
->screen_ptr
,
222 _("Close X session"),
223 _("Close Window System session?\n"
224 "Kill might close applications with unsaved data."),
225 _("Close"), _("Kill"), _("Cancel"));
228 else if (r
==WAPRAlternate
)
235 r
= wMessageDialog(menu
->frame
->screen_ptr
,
237 _("Kill Window System session?\n"
238 "(all applications will be closed)"),
239 _("Kill"), _("Cancel"), NULL
);
245 if (result
!=R_CANCEL
) {
247 if (result
== R_CLOSE
) {
248 Shutdown(WSLogoutMode
);
252 Shutdown(WSKillMode
);
263 restartCommand(WMenu
*menu
, WMenuEntry
*entry
)
265 Shutdown(WSRestartPreparationMode
);
266 Restart((char*)entry
->clientdata
);
271 refreshCommand(WMenu
*menu
, WMenuEntry
*entry
)
273 wRefreshDesktop(menu
->frame
->screen_ptr
);
278 arrangeIconsCommand(WMenu
*menu
, WMenuEntry
*entry
)
280 wArrangeIcons(menu
->frame
->screen_ptr
, True
);
284 showAllCommand(WMenu
*menu
, WMenuEntry
*entry
)
286 wShowAllWindows(menu
->frame
->screen_ptr
);
290 hideOthersCommand(WMenu
*menu
, WMenuEntry
*entry
)
292 wHideOtherApplications(menu
->frame
->screen_ptr
->focused_window
);
297 saveSessionCommand(WMenu
*menu
, WMenuEntry
*entry
)
299 wSessionSaveState(menu
->frame
->screen_ptr
);
304 clearSessionCommand(WMenu
*menu
, WMenuEntry
*entry
)
306 wSessionClearState(menu
->frame
->screen_ptr
);
311 infoPanelCommand(WMenu
*menu
, WMenuEntry
*entry
)
313 wShowInfoPanel(menu
->frame
->screen_ptr
);
318 legalPanelCommand(WMenu
*menu
, WMenuEntry
*entry
)
320 wShowLegalPanel(menu
->frame
->screen_ptr
);
325 /********************************************************************/
328 raiseMenus(WMenu
*menu
)
332 if (menu
->flags
.mapped
) {
333 wRaiseFrame(menu
->frame
->core
);
335 for (i
=0; i
<menu
->cascade_no
; i
++) {
336 if (menu
->cascades
[i
])
337 raiseMenus(menu
->cascades
[i
]);
344 wRootMenuPerformShortcut(XEvent
*event
)
350 /* ignore CapsLock */
351 modifiers
= event
->xkey
.state
& ValidModMask
;
353 for (ptr
= shortcutList
; ptr
!=NULL
; ptr
= ptr
->next
) {
357 if (ptr
->keycode
==event
->xkey
.keycode
&& (ptr
->modifier
==modifiers
)) {
358 (*ptr
->entry
->callback
)(ptr
->menu
, ptr
->entry
);
367 wRootMenuBindShortcuts(Window window
)
373 if (ptr
->modifier
!=AnyModifier
) {
374 XGrabKey(dpy
, ptr
->keycode
, ptr
->modifier
|LockMask
,
375 window
, True
, GrabModeAsync
, GrabModeAsync
);
377 wHackedGrabKey(ptr
->keycode
, ptr
->modifier
,
378 window
, True
, GrabModeAsync
, GrabModeAsync
);
381 XGrabKey(dpy
, ptr
->keycode
, ptr
->modifier
, window
, True
,
382 GrabModeAsync
, GrabModeAsync
);
389 rebindKeygrabs(WScreen
*scr
)
393 wwin
= scr
->focused_window
;
396 XUngrabKey(dpy
, AnyKey
, AnyModifier
, wwin
->frame
->core
->window
);
398 if (!WFLAGP(wwin
, no_bind_keys
)) {
399 wWindowSetKeyGrabs(wwin
);
407 removeShortcutsForMenu(WMenu
*menu
)
410 Shortcut
*newList
= NULL
;
415 if (ptr
->menu
== menu
) {
423 shortcutList
= newList
;
424 menu
->menu
->screen_ptr
->flags
.root_menu_changed_shortcuts
= 1;
429 addShortcut(char *file
, char *shortcutDefinition
, WMenu
*menu
,
437 ptr
= wmalloc(sizeof(Shortcut
));
439 strcpy(buf
, shortcutDefinition
);
444 while ((k
= strchr(b
, '+'))!=NULL
) {
448 mod
= wXModifierFromKey(b
);
450 wwarning(_("%s:invalid key modifier \"%s\""), file
, b
);
454 ptr
->modifier
|= mod
;
460 ksym
= XStringToKeysym(b
);
462 if (ksym
==NoSymbol
) {
463 wwarning(_("%s:invalid kbd shortcut specification \"%s\" for entry %s"),
464 file
, shortcutDefinition
, entry
->text
);
469 ptr
->keycode
= XKeysymToKeycode(dpy
, ksym
);
470 if (ptr
->keycode
==0) {
471 wwarning(_("%s:invalid key in shortcut \"%s\" for entry %s"), file
,
472 shortcutDefinition
, entry
->text
);
480 ptr
->next
= shortcutList
;
483 menu
->menu
->screen_ptr
->flags
.root_menu_changed_shortcuts
= 1;
489 /*******************************/
499 end
= &(line
[strlen(line
)])-1;
500 while (isspace(*line
) && *line
!=0) line
++;
501 while (end
>line
&& isspace(*end
)) {
510 next_token(char *line
, char **next
)
516 while (*line
==' ' || *line
=='\t') line
++;
522 while (*tmp
!=0 && *tmp
!='"') tmp
++;
524 wwarning(_("%s: unmatched '\"' in menu file"), line
);
535 } while (*tmp
!=0 && *tmp
!=' ' && *tmp
!='\t');
549 while (*tmp
==' ' || *tmp
=='\t') tmp
++;
559 separateCommand(char *line
, char ***file
, char **command
)
561 char *token
, *tmp
= line
;
562 LinkedList
*list
= NULL
;
568 token
= next_token(tmp
, &tmp
);
570 if (strcmp(token
, "WITH")==0) {
571 if (tmp
!=NULL
&& *tmp
!=0)
572 *command
= wstrdup(tmp
);
574 wwarning(_("%s: missing command"), line
);
577 list
= list_cons(token
, list
);
579 } while (token
!=NULL
&& tmp
!=NULL
);
581 count
= list_length(list
);
583 *file
= wmalloc(sizeof(char*)*(count
+1));
585 (*file
)[count
] = NULL
;
587 (*file
)[--i
] = list
->head
;
588 list_remove_head(&list
);
595 constructMenu(WMenu
*menu
, WMenuEntry
*entry
)
598 struct stat stat_buf
;
605 separateCommand((char*)entry
->clientdata
, &path
, &cmd
);
606 if (!path
|| *path
==NULL
|| **path
==0) {
607 wwarning(_("invalid OPEN_MENU specification: %s"),
608 (char*)entry
->clientdata
);
612 if (path
[0][0]=='|') {
615 if (!menu
->cascades
[entry
->cascade
] ||
616 menu
->cascades
[entry
->cascade
]->timestamp
== 0) {
619 submenu
= readMenuPipe(menu
->frame
->screen_ptr
, path
);
621 /* there's no automatic reloading */
623 submenu
->timestamp
= 1;
630 while(path
[i
] != NULL
) {
632 Bool statted
= False
;
634 if (strcmp(path
[i
], "-noext")==0) {
639 tmp
= wexpandpath(path
[i
]);
644 lpath
= wmalloc(strlen(path
[i
])+32);
646 strcpy(lpath
, path
[i
]);
648 strcat(lpath
, Locale
);
649 if (stat(lpath
, &stat_buf
)<0) {
653 lpath
[strlen(lpath
)-(i
-2)]=0;
654 if (stat(lpath
, &stat_buf
)==0) {
674 if (statted
|| stat(path
[i
], &stat_buf
)==0) {
675 if (last
< stat_buf
.st_mtime
)
676 last
= stat_buf
.st_mtime
;
680 wsyserror(_("%s:could not stat menu"), path
[i
]);
688 wsyserror(_("%s:could not stat menu:%s"), "OPEN_MENU",
689 (char*)entry
->clientdata
);
692 stat(path
[first
], &stat_buf
);
693 if (!menu
->cascades
[entry
->cascade
]
694 || menu
->cascades
[entry
->cascade
]->timestamp
< last
) {
696 if (S_ISDIR(stat_buf
.st_mode
)) {
698 submenu
= readMenuDirectory(menu
->frame
->screen_ptr
,
699 entry
->text
, path
, cmd
);
701 submenu
->timestamp
= last
;
702 } else if (S_ISREG(stat_buf
.st_mode
)) {
706 wwarning(_("too many parameters in OPEN_MENU: %s"),
707 (char*)entry
->clientdata
);
709 submenu
= readMenuFile(menu
->frame
->screen_ptr
, path
[first
]);
711 submenu
->timestamp
= stat_buf
.st_mtime
;
721 wMenuEntryRemoveCascade(menu
, entry
);
722 wMenuEntrySetCascade(menu
, entry
, submenu
);
727 while (path
[i
]!=NULL
)
736 addWorkspaceMenu(WScreen
*scr
, WMenu
*menu
, char *title
)
741 if (scr
->flags
.added_workspace_menu
) {
742 wwarning(_("There are more than one WORKSPACE_MENU commands in the applications menu. Only one is allowed."));
745 scr
->flags
.added_workspace_menu
= 1;
747 wsmenu
= wWorkspaceMenuMake(scr
, True
);
748 scr
->workspace_menu
= wsmenu
;
749 entry
= wMenuAddCallback(menu
, title
, NULL
, NULL
);
750 wMenuEntrySetCascade(menu
, entry
, wsmenu
);
752 wWorkspaceMenuUpdate(scr
, wsmenu
);
759 addMenuEntry(WMenu
*menu
, char *title
, char *shortcut
, char *command
,
760 char *params
, char *file_name
)
763 WMenuEntry
*entry
= NULL
;
764 Bool shortcutOk
= False
;
768 scr
= menu
->frame
->screen_ptr
;
769 if (strcmp(command
, "OPEN_MENU")==0) {
771 wwarning(_("%s:missing parameter for menu command \"%s\""),
777 path
= wfindfile(DEF_CONFIG_PATHS
, params
);
779 path
= wstrdup(params
);
781 dummy
= wMenuCreate(scr
, title
, False
);
782 dummy
->on_destroy
= removeShortcutsForMenu
;
783 entry
= wMenuAddCallback(menu
, title
, constructMenu
, path
);
784 entry
->free_cdata
= free
;
785 wMenuEntrySetCascade(menu
, entry
, dummy
);
787 } else if (strcmp(command
, "EXEC")==0) {
789 wwarning(_("%s:missing parameter for menu command \"%s\""),
792 entry
= wMenuAddCallback(menu
, title
, execCommand
, wstrdup(params
));
793 entry
->free_cdata
= free
;
796 } else if (strcmp(command
, "EXIT")==0) {
798 if (params
&& strcmp(params
, "QUICK")==0)
799 entry
= wMenuAddCallback(menu
, title
, exitCommand
, (void*)M_QUICK
);
801 entry
= wMenuAddCallback(menu
, title
, exitCommand
, NULL
);
804 } else if (strcmp(command
, "SHUTDOWN")==0) {
806 if (params
&& strcmp(params
, "QUICK")==0)
807 entry
= wMenuAddCallback(menu
, title
, shutdownCommand
,
810 entry
= wMenuAddCallback(menu
, title
, shutdownCommand
, NULL
);
813 } else if (strcmp(command
, "REFRESH")==0) {
814 entry
= wMenuAddCallback(menu
, title
, refreshCommand
, NULL
);
817 } else if (strcmp(command
, "WORKSPACE_MENU")==0) {
818 entry
= addWorkspaceMenu(scr
, menu
, title
);
821 } else if (strcmp(command
, "ARRANGE_ICONS")==0) {
822 entry
= wMenuAddCallback(menu
, title
, arrangeIconsCommand
, NULL
);
825 } else if (strcmp(command
, "HIDE_OTHERS")==0) {
826 entry
= wMenuAddCallback(menu
, title
, hideOthersCommand
, NULL
);
829 } else if (strcmp(command
, "SHOW_ALL")==0) {
830 entry
= wMenuAddCallback(menu
, title
, showAllCommand
, NULL
);
833 } else if (strcmp(command
, "RESTART")==0) {
834 entry
= wMenuAddCallback(menu
, title
, restartCommand
,
835 params
? wstrdup(params
) : NULL
);
836 entry
->free_cdata
= free
;
838 } else if (strcmp(command
, "SAVE_SESSION")==0) {
839 entry
= wMenuAddCallback(menu
, title
, saveSessionCommand
, NULL
);
842 } else if (strcmp(command
, "CLEAR_SESSION")==0) {
843 entry
= wMenuAddCallback(menu
, title
, clearSessionCommand
, NULL
);
845 } else if (strcmp(command
, "INFO_PANEL")==0) {
846 entry
= wMenuAddCallback(menu
, title
, infoPanelCommand
, NULL
);
848 } else if (strcmp(command
, "LEGAL_PANEL")==0) {
849 entry
= wMenuAddCallback(menu
, title
, legalPanelCommand
, NULL
);
852 wwarning(_("%s:unknown command \"%s\" in menu config."), file_name
,
858 if (shortcut
&& entry
) {
860 wwarning(_("%s:can't add shortcut for entry \"%s\""), file_name
,
863 if (addShortcut(file_name
, shortcut
, menu
, entry
)) {
865 entry
->rtext
= GetShortcutString(shortcut
);
867 entry->rtext = wstrdup(shortcut);
878 /******************* Menu Configuration From File *******************/
881 separateline(char *line
, char *title
, char *command
, char *parameter
,
893 while (isspace(*line
) && (*line
!=0)) line
++;
897 while (line
[i
]!='"' && (line
[i
]!=0)) i
++;
902 while (!isspace(line
[i
]) && (line
[i
]!=0)) i
++;
904 strncpy(title
, line
, i
);
908 /* get the command or shortcut keyword */
909 while (isspace(*line
) && (*line
!=0)) line
++;
913 while (!isspace(line
[i
]) && (line
[i
]!=0)) i
++;
914 strncpy(command
, line
, i
);
918 if (strcmp(command
, "SHORTCUT")==0) {
919 /* get the shortcut key */
920 while (isspace(*line
) && (*line
!=0)) line
++;
924 while (line
[i
]!='"' && (line
[i
]!=0)) i
++;
929 while (!isspace(line
[i
]) && (line
[i
]!=0)) i
++;
931 strncpy(shortcut
, line
, i
);
937 /* get the command */
938 while (isspace(*line
) && (*line
!=0)) line
++;
942 while (!isspace(line
[i
]) && (line
[i
]!=0)) i
++;
943 strncpy(command
, line
, i
);
948 /* get the parameters */
949 while (isspace(*line
) && (*line
!=0)) line
++;
956 while (line
[l
]!=0 && line
[l
]!='"') {
957 parameter
[l
] = line
[l
];
965 while (isspace(line
[l
]) && (l
>0)) l
--;
966 strncpy(parameter
, line
, l
);
972 parseCascade(WScreen
*scr
, WMenu
*menu
, FILE *file
, char *file_name
)
974 char linebuf
[MAXLINE
];
975 char elinebuf
[MAXLINE
];
977 char command
[MAXLINE
];
978 char shortcut
[MAXLINE
];
979 char params
[MAXLINE
];
982 while (!IsEof(file
)) {
986 fgets(linebuf
, MAXLINE
, file
);
987 line
= cropline(linebuf
);
988 lsize
= strlen(line
);
990 if (line
[lsize
-1]=='\\') {
993 fgets(elinebuf
, MAXLINE
, file
);
994 line2
=cropline(elinebuf
);
995 lsize2
=strlen(line2
);
996 if (lsize2
+lsize
>MAXLINE
) {
997 wwarning(_("%s:maximal line size exceeded in menu config: %s"),
1003 strcat(line
, line2
);
1008 } while (!ok
&& !IsEof(file
));
1012 if (line
[0]==0 || line
[0]=='#' || (line
[0]=='/' && line
[1]=='/'))
1016 separateline(line
, title
, command
, params
, shortcut
);
1019 wwarning(_("%s:missing command in menu config: %s"), file_name
,
1024 if (strcasecmp(command
, "MENU")==0) {
1029 cascade
= wMenuCreate(scr
, title
, False
);
1030 cascade
->on_destroy
= removeShortcutsForMenu
;
1031 if (parseCascade(scr
, cascade
, file
, file_name
)==NULL
) {
1032 wMenuDestroy(cascade
, True
);
1034 wMenuEntrySetCascade(menu
,
1035 wMenuAddCallback(menu
, title
, NULL
, NULL
),
1038 } else if (strcasecmp(command
, "END")==0) {
1044 addMenuEntry(menu
, title
, shortcut
[0] ? shortcut
: NULL
, command
,
1045 params
[0] ? params
: NULL
, file_name
);
1049 wwarning(_("%s:syntax error in menu file:END declaration missing"),
1059 readMenuFile(WScreen
*scr
, char *file_name
)
1063 char linebuf
[MAXLINE
];
1064 char title
[MAXLINE
];
1065 char shortcut
[MAXLINE
];
1066 char command
[MAXLINE
];
1067 char params
[MAXLINE
];
1075 if (!wPreferences
.flags
.nocpp
) {
1076 args
= MakeCPPArgs(file_name
);
1078 wwarning(_("could not make arguments for menu file preprocessor"));
1080 sprintf(command
, "%s %s %s", CPP_PATH
, args
, file_name
);
1082 file
= popen(command
, "r");
1084 wsyserror(_("%s:could not open/preprocess menu file"),
1094 file
= fopen(file_name
, "r");
1096 wsyserror(_("%s:could not open menu file"), file_name
);
1101 while (!IsEof(file
)) {
1102 if (!fgets(linebuf
, MAXLINE
, file
))
1104 line
= cropline(linebuf
);
1105 if (line
[0]==0 || line
[0]=='#' || (line
[0]=='/' && line
[1]=='/'))
1108 separateline(line
, title
, command
, params
, shortcut
);
1111 wwarning(_("%s:missing command in menu config: %s"), file_name
,
1115 if (strcasecmp(command
, "MENU")==0) {
1116 menu
= wMenuCreate(scr
, title
, True
);
1117 menu
->on_destroy
= removeShortcutsForMenu
;
1118 if (!parseCascade(scr
, menu
, file
, file_name
)) {
1119 wMenuDestroy(menu
, True
);
1123 wwarning(_("%s:invalid menu file. MENU command is missing"),
1131 if (pclose(file
)==-1) {
1132 wsyserror(_("error reading preprocessed menu data"));
1144 /************ Menu Configuration From Pipe *************/
1147 readMenuPipe(WScreen
*scr
, char **file_name
)
1151 char linebuf
[MAXLINE
];
1152 char title
[MAXLINE
];
1153 char command
[MAXLINE
];
1154 char params
[MAXLINE
];
1155 char shortcut
[MAXLINE
];
1158 char flat_file
[MAXLINE
];
1165 flat_file
[0] = '\0';
1167 for(i
= 0 ; file_name
[i
] != NULL
; i
++) {
1168 strcat(flat_file
, file_name
[i
]);
1169 strcat(flat_file
, " ");
1171 filename
= flat_file
+1;
1174 if (!wPreferences
.flags
.nocpp
) {
1175 args
= MakeCPPArgs(filename
);
1177 wwarning(_("could not make arguments for menu file preprocessor"));
1179 sprintf(command
, "%s | %s %s", filename
, CPP_PATH
, args
);
1182 file
= popen(command
, "r");
1184 wsyserror(_("%s:could not open/preprocess menu file"), filename
);
1194 file
= popen(filename
, "r");
1197 wsyserror(_("%s:could not open menu file"), filename
);
1202 while (!IsEof(file
)) {
1203 if (!fgets(linebuf
, MAXLINE
, file
))
1205 line
= cropline(linebuf
);
1206 if (line
[0]==0 || line
[0]=='#' || (line
[0]=='/' && line
[1]=='/'))
1209 separateline(line
, title
, command
, params
, shortcut
);
1212 wwarning(_("%s:missing command in menu config: %s"), file_name
,
1216 if (strcasecmp(command
, "MENU")==0) {
1217 menu
= wMenuCreate(scr
, title
, True
);
1218 menu
->on_destroy
= removeShortcutsForMenu
;
1219 if (!parseCascade(scr
, menu
, file
, filename
)) {
1220 wMenuDestroy(menu
, True
);
1224 wwarning(_("%s:no title given for the root menu"), filename
);
1243 myCompare(dir_data
*d1
, dir_data
*d2
)
1245 return strcmp(d1
->name
, d2
->name
);
1249 /************ Menu Configuration From Directory *************/
1252 isFilePackage(char *file
)
1256 /* check if the extension indicates this file is a
1257 * file package. For now, only recognize .themed */
1261 if (l
> 7 && strcmp(&(file
[l
-7]), ".themed")==0) {
1270 readMenuDirectory(WScreen
*scr
, char *title
, char **path
, char *command
)
1273 struct dirent
*dentry
;
1274 struct stat stat_buf
;
1277 LinkedList
*dirs
= NULL
, *files
= NULL
;
1278 int length
, i
, have_space
=0;
1280 int stripExtension
= 0;
1283 while (path
[i
]!=NULL
) {
1284 if (strcmp(path
[i
], "-noext")==0) {
1290 dir
= opendir(path
[i
]);
1296 while ((dentry
= readdir(dir
))) {
1298 if (strcmp(dentry
->d_name
, ".")==0 ||
1299 strcmp(dentry
->d_name
, "..")==0)
1302 if (dentry
->d_name
[0] == '.')
1305 buffer
= wmalloc(strlen(path
[i
])+strlen(dentry
->d_name
)+4);
1307 wsyserror(_("out of memory while constructing directory menu %s"),
1312 strcpy(buffer
, path
[i
]);
1313 strcat(buffer
, "/");
1314 strcat(buffer
, dentry
->d_name
);
1316 if (stat(buffer
, &stat_buf
)!=0) {
1317 wsyserror(_("%s:could not stat file \"%s\" in menu directory"),
1318 path
[i
], dentry
->d_name
);
1320 Bool isFilePack
= False
;
1323 if (S_ISDIR(stat_buf
.st_mode
)
1324 && !(isFilePack
= isFilePackage(dentry
->d_name
))) {
1326 /* access always returns success for user root */
1327 if (access(buffer
, X_OK
)==0) {
1328 /* Directory is accesible. Add to directory list */
1330 data
= (dir_data
*) wmalloc(sizeof(dir_data
));
1331 data
->name
= wstrdup(dentry
->d_name
);
1334 list_insert_sorted(data
, &dirs
, (int(*)())myCompare
);
1336 } else if (S_ISREG(stat_buf
.st_mode
) || isFilePack
) {
1337 /* Hack because access always returns X_OK success for user root */
1338 #define S_IXANY (S_IXUSR | S_IXGRP | S_IXOTH)
1339 if ((command
!=NULL
&& access(buffer
, R_OK
)==0) ||
1340 (command
==NULL
&& access(buffer
, X_OK
)==0 &&
1341 (stat_buf
.st_mode
& S_IXANY
))) {
1343 data
= (dir_data
*) wmalloc(sizeof(dir_data
));
1344 data
->name
= wstrdup(dentry
->d_name
);
1347 list_insert_sorted(data
, &files
, (int(*)())myCompare
);
1358 if (!dirs
&& !files
)
1361 menu
= wMenuCreate(scr
, title
, False
);
1362 menu
->on_destroy
= removeShortcutsForMenu
;
1364 while (dirs
!= NULL
) {
1365 /* New directory. Use same OPEN_MENU command that was used
1366 * for the current directory. */
1367 dir_data
*d
= (dir_data
*)dirs
->head
;
1369 length
= strlen(path
[d
->index
])+strlen(d
->name
)+6;
1371 length
+= strlen(command
) + 6;
1372 buffer
= wmalloc(length
);
1374 wsyserror(_("out of memory while constructing directory menu %s"),
1379 have_space
= strchr(path
[d
->index
], ' ')!=NULL
||
1380 strchr(d
->name
, ' ')!=NULL
;
1384 strcat(buffer
, path
[d
->index
]);
1386 strcpy(buffer
, path
[d
->index
]);
1388 strcat(buffer
, "/");
1389 strcat(buffer
, d
->name
);
1391 strcat(buffer
, "\"");
1393 strcat(buffer
, " WITH ");
1394 strcat(buffer
, command
);
1397 addMenuEntry(menu
, d
->name
, NULL
, "OPEN_MENU", buffer
, path
[d
->index
]);
1405 list_remove_head(&dirs
);
1408 while (files
!= NULL
) {
1409 /* executable: add as entry */
1410 dir_data
*f
= (dir_data
*) files
->head
;;
1412 length
= strlen(path
[f
->index
])+strlen(f
->name
)+6;
1414 length
+= strlen(command
);
1416 buffer
= wmalloc(length
);
1418 wsyserror(_("out of memory while constructing directory menu %s"),
1423 have_space
= strchr(path
[f
->index
], ' ')!=NULL
||
1424 strchr(f
->name
, ' ')!=NULL
;
1425 if (command
!=NULL
) {
1426 strcpy(buffer
, command
);
1427 strcat(buffer
, " ");
1429 strcat(buffer
, "\"");
1430 strcat(buffer
, path
[f
->index
]);
1435 strcat(buffer
, path
[f
->index
]);
1437 strcpy(buffer
, path
[f
->index
]);
1440 strcat(buffer
, "/");
1441 strcat(buffer
, f
->name
);
1443 strcat(buffer
, "\"");
1445 if (stripExtension
) {
1446 char *ptr
= strrchr(f
->name
, '.');
1447 if (ptr
&& ptr
!=f
->name
)
1450 addMenuEntry(menu
, f
->name
, NULL
, "EXEC", buffer
, path
[f
->index
]);
1458 list_remove_head(&files
);
1465 /************ Menu Configuration From WMRootMenu *************/
1468 makeDefaultMenu(WScreen
*scr
)
1472 menu
= wMenuCreate(scr
, _("Commands"), True
);
1473 wMenuAddCallback(menu
, "XTerm", execCommand
, "xterm");
1474 wMenuAddCallback(menu
, "rxvt", execCommand
, "rxvt");
1475 wMenuAddCallback(menu
, _("Restart"), restartCommand
, NULL
);
1476 wMenuAddCallback(menu
, _("Exit..."), exitCommand
, NULL
);
1485 *----------------------------------------------------------------------
1487 * Reads root menu configuration from defaults database.
1489 *----------------------------------------------------------------------
1492 configureMenu(WScreen
*scr
, proplist_t definition
)
1497 proplist_t title
, command
, params
;
1501 if (PLIsString(definition
)) {
1502 struct stat stat_buf
;
1504 Bool menu_is_default
= False
;
1506 /* menu definition is a string. Probably a path, so parse the file */
1508 tmp
= wexpandpath(PLGetString(definition
));
1511 path
= wmalloc(strlen(tmp
)+32);
1515 strcat(path
, Locale
);
1517 /* look for menu.xy */
1518 if (stat(path
, &stat_buf
)<0) {
1522 path
[strlen(path
)-(i
-2)]=0;
1523 /* look for menu.xy_zw */
1524 if (stat(path
, &stat_buf
)<0) {
1526 /* If did not find any localized menus, try
1527 * only menu. This can also mean that
1528 * the path in WMRootMenu was already the
1529 * path for the localized menu (eg: menu = "menu.ab")
1541 path
= wfindfile(DEF_CONFIG_PATHS
, tmp
);
1544 path
= wfindfile(DEF_CONFIG_PATHS
, DEF_MENU_FILE
);
1545 menu_is_default
= True
;
1549 wsyserror(_("could not find menu file \"%s\" referenced in WMRootMenu"),
1555 if (stat(path
, &stat_buf
)<0) {
1556 wsyserror(_("could not access menu \"%s\" referenced in WMRootMenu"), path
);
1562 if (!scr
->root_menu
|| stat_buf
.st_mtime
> scr
->root_menu
->timestamp
1563 /* if the pointer in WMRootMenu has changed */
1564 || WDRootMenu
->timestamp
> scr
->root_menu
->timestamp
) {
1566 if (menu_is_default
) {
1567 wwarning(_("using default menu file \"%s\" as the menu referenced in WMRootMenu could not be found "),
1571 menu
= readMenuFile(scr
, path
);
1573 menu
->timestamp
= MAX(stat_buf
.st_mtime
, WDRootMenu
->timestamp
);
1583 count
= PLGetNumberOfElements(definition
);
1587 elem
= PLGetArrayElement(definition
, 0);
1588 if (!PLIsString(elem
)) {
1589 tmp
= PLGetDescription(elem
);
1590 wwarning(_("%s:format error in root menu configuration \"%s\""),
1595 mtitle
= PLGetString(elem
);
1597 menu
= wMenuCreate(scr
, mtitle
, False
);
1598 menu
->on_destroy
= removeShortcutsForMenu
;
1600 #ifdef GLOBAL_SUBMENU_FILE
1605 submenu
= readMenuFile(scr
, GLOBAL_SUBMENU_FILE
);
1608 mentry
= wMenuAddCallback(menu
, submenu
->frame
->title
, NULL
, NULL
);
1609 wMenuEntrySetCascade(menu
, mentry
, submenu
);
1614 for (i
=1; i
<count
; i
++) {
1615 elem
= PLGetArrayElement(definition
, i
);
1617 if (PLIsString(elem
)) {
1620 file
= PLGetString(elem
);
1624 if (!PLIsArray(elem
) || PLGetNumberOfElements(elem
) < 2)
1627 if (PLIsArray(PLGetArrayElement(elem
,1))) {
1632 submenu
= configureMenu(scr
, elem
);
1634 mentry
= wMenuAddCallback(menu
, submenu
->frame
->title
, NULL
,
1636 wMenuEntrySetCascade(menu
, mentry
, submenu
);
1643 title
= PLGetArrayElement(elem
, idx
++);
1644 shortcut
= PLGetArrayElement(elem
, idx
++);
1645 if (strcmp(PLGetString(shortcut
), "SHORTCUT")==0) {
1646 shortcut
= PLGetArrayElement(elem
, idx
++);
1647 command
= PLGetArrayElement(elem
, idx
++);
1652 params
= PLGetArrayElement(elem
, idx
++);
1654 if (!title
|| !command
)
1657 addMenuEntry(menu
, PLGetString(title
),
1658 shortcut
? PLGetString(shortcut
) : NULL
,
1659 PLGetString(command
),
1660 params
? PLGetString(params
) : NULL
, "WMRootMenu");
1665 tmp
= PLGetDescription(elem
);
1666 wwarning(_("%s:format error in root menu configuration \"%s\""),
1682 *----------------------------------------------------------------------
1684 * Opens the root menu, parsing the menu configuration from the
1685 * defaults database.
1686 * If the menu is already mapped and is not sticked to the
1687 * root window, it will be unmapped.
1690 * The menu may be remade.
1693 * Construction of OPEN_MENU entries are delayed to the moment the
1695 *----------------------------------------------------------------------
1698 OpenRootMenu(WScreen
*scr
, int x
, int y
, int keyboard
)
1701 proplist_t definition
;
1703 static proplist_t domain=NULL;
1706 domain = PLMakeString("WMRootMenu");
1710 scr
->flags
.root_menu_changed_shortcuts
= 0;
1711 scr
->flags
.added_workspace_menu
= 0;
1713 if (scr
->root_menu
&& scr
->root_menu
->flags
.mapped
) {
1714 menu
= scr
->root_menu
;
1715 if (!menu
->flags
.buttoned
) {
1718 wRaiseFrame(menu
->frame
->core
);
1721 wMenuMapAt(menu
, 0, 0, True
);
1723 wMenuMapCopyAt(menu
, x
-menu
->frame
->core
->width
/2,
1724 y
-menu
->frame
->top_width
/2);
1730 definition
= WDRootMenu
->dictionary
;
1733 definition = PLGetDomain(domain);
1736 if (PLIsArray(definition
)) {
1738 || WDRootMenu
->timestamp
> scr
->root_menu
->timestamp
) {
1739 menu
= configureMenu(scr
, definition
);
1741 menu
->timestamp
= WDRootMenu
->timestamp
;
1746 menu
= configureMenu(scr
, definition
);
1751 /* menu hasn't changed or could not be read */
1752 if (!scr
->root_menu
) {
1753 menu
= makeDefaultMenu(scr
);
1754 scr
->root_menu
= menu
;
1756 menu
= scr
->root_menu
;
1760 wMenuDestroy(scr
->root_menu
, True
);
1761 scr
->root_menu
= menu
;
1764 wMenuMapAt(menu
, x
-menu
->frame
->core
->width
/2, y
-menu
->frame
->top_width
/2,
1768 if (scr
->flags
.root_menu_changed_shortcuts
)
1769 rebindKeygrabs(scr
);