1 /* -*-c-*- */
2 /* This program is free software; you can redistribute it and/or modify
3 * it under the terms of the GNU General Public License as published by
4 * the Free Software Foundation; either version 2 of the License, or
5 * (at your option) any later version.
6 *
7 * This program is distributed in the hope that it will be useful,
8 * but WITHOUT ANY WARRANTY; without even the implied warranty of
9 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
10 * GNU General Public License for more details.
11 *
12 * You should have received a copy of the GNU General Public License
13 * along with this program; if not, see: <http://www.gnu.org/licenses/>
14 */
15
16 /* IMPORTANT NOTE: Do *not* use any constant numbers in this file. All values
17 * have to be #defined in the section below or defaults.h to ensure full
18 * control over the menus. */
19
20 /* ---------------------------- included header files ---------------------- */
21
22 #include "config.h"
23
24 #include <stdio.h>
25
26 #include "libs/Parse.h"
27 #include "libs/Strings.h"
28 #include "fvwm.h"
29 #include "functions.h"
30 #include "repeat.h"
31 #include "misc.h"
32 #include "move_resize.h"
33 #include "screen.h"
34 #include "menus.h"
35 #include "menudim.h"
36 #include "menuroot.h"
37 #include "menustyle.h"
38 #include "menuparameters.h"
39
40 /* ---------------------------- local definitions -------------------------- */
41
42 /* ---------------------------- local macros ------------------------------- */
43
44 /* ---------------------------- imports ------------------------------------ */
45
46 /* ---------------------------- included code files ------------------------ */
47
48 /* ---------------------------- local types -------------------------------- */
49
50 /* ---------------------------- forward declarations ----------------------- */
51
52 /* ---------------------------- local variables ---------------------------- */
53
54 /* ---------------------------- exported variables (globals) --------------- */
55
56 /* ---------------------------- local functions ---------------------------- */
57
menu_func(F_CMD_ARGS,Bool fStaysUp)58 static void menu_func(F_CMD_ARGS, Bool fStaysUp)
59 {
60 struct MenuRoot *menu;
61 char *ret_action = NULL;
62 struct MenuOptions mops;
63 char *menu_name = NULL;
64 struct MenuParameters mp;
65 struct MenuReturn mret;
66 FvwmWindow * const fw = exc->w.fw;
67 const Window w = exc->w.w;
68 const exec_context_t *exc2;
69
70 memset(&mops, 0, sizeof(mops));
71 memset(&mret, 0, sizeof(MenuReturn));
72 action = GetNextToken(action,&menu_name);
73 action = get_menu_options(
74 action, w, fw, NULL, NULL, NULL, &mops);
75 while (action && *action && isspace((unsigned char)*action))
76 {
77 action++;
78 }
79 if (action && *action == 0)
80 {
81 action = NULL;
82 }
83 menu = menus_find_menu(menu_name);
84 if (menu == NULL)
85 {
86 if (menu_name)
87 {
88 fvwm_debug(__func__, "No such menu %s",menu_name);
89 free(menu_name);
90 }
91 return;
92 }
93 if (menu_name &&
94 set_repeat_data(
95 menu_name, (fStaysUp) ? REPEAT_MENU : REPEAT_POPUP,NULL))
96 {
97 free(menu_name);
98 }
99
100 memset(&mp, 0, sizeof(mp));
101 mp.menu = menu;
102 exc2 = exc_clone_context(exc, NULL, 0);
103 mp.pexc = &exc2;
104 MR_IS_TEAR_OFF_MENU(menu) = 0;
105 mp.flags.has_default_action = (action != NULL);
106 mp.flags.is_sticky = fStaysUp;
107 mp.flags.is_submenu = False;
108 mp.flags.is_already_mapped = False;
109 mp.flags.is_triggered_by_keypress =
110 (exc->x.etrigger->type == KeyPress);
111 mp.pops = &mops;
112 mp.ret_paction = &ret_action;
113 do_menu(&mp, &mret);
114 if (mret.rc == MENU_DOUBLE_CLICKED && action)
115 {
116 execute_function(cond_rc, exc2, action, 0);
117 }
118 if (ret_action != NULL)
119 {
120 free(ret_action);
121 }
122 exc_destroy_context(exc2);
123
124 return;
125 }
126
127 /* ---------------------------- interface functions ------------------------ */
128
129 /* ---------------------------- builtin commands --------------------------- */
130
131 /* the function for the "Popup" command */
CMD_Popup(F_CMD_ARGS)132 void CMD_Popup(F_CMD_ARGS)
133 {
134 menu_func(F_PASS_ARGS, False);
135
136 return;
137 }
138
139 /* the function for the "Menu" command */
CMD_Menu(F_CMD_ARGS)140 void CMD_Menu(F_CMD_ARGS)
141 {
142 menu_func(F_PASS_ARGS, True);
143
144 return;
145 }
146
CMD_AddToMenu(F_CMD_ARGS)147 void CMD_AddToMenu(F_CMD_ARGS)
148 {
149 MenuRoot *mr;
150 MenuRoot *mrPrior;
151 char *token, *rest,*item;
152
153 token = PeekToken(action, &rest);
154 if (!token)
155 {
156 return;
157 }
158 mr = menus_find_menu(token);
159 if (mr && MR_MAPPED_COPIES(mr) != 0)
160 {
161 fvwm_debug(__func__, "menu %s is in use", token);
162 return;
163 }
164 mr = FollowMenuContinuations(menus_find_menu(token), &mrPrior);
165 if (mr == NULL)
166 {
167 mr = NewMenuRoot(token);
168 }
169
170 /* Set + state to last menu */
171 set_last_added_item(ADDED_MENU, mr);
172
173 rest = GetNextToken(rest, &item);
174 AddToMenu(mr, item, rest, True /* pixmap scan */, True, False);
175 if (item)
176 {
177 free(item);
178 }
179
180 return;
181 }
182
CMD_DestroyMenu(F_CMD_ARGS)183 void CMD_DestroyMenu(F_CMD_ARGS)
184 {
185 MenuRoot *mr;
186 MenuRoot *mrContinuation;
187 Bool do_recreate = False;
188 char *token;
189
190 token = PeekToken(action, &action);
191 if (!token)
192 {
193 return;
194 }
195 if (StrEquals(token, "recreate"))
196 {
197 do_recreate = True;
198 token = PeekToken(action, NULL);
199 }
200 mr = menus_find_menu(token);
201 if (Scr.last_added_item.type == ADDED_MENU)
202 {
203 set_last_added_item(ADDED_NONE, NULL);
204 }
205 while (mr)
206 {
207 /* save continuation before destroy */
208 mrContinuation = MR_CONTINUATION_MENU(mr);
209 if (!DestroyMenu(mr, do_recreate, True))
210 {
211 return;
212 }
213 /* Don't recreate the continuations */
214 do_recreate = False;
215 mr = mrContinuation;
216 }
217
218 return;
219 }
220
CMD_DestroyMenuStyle(F_CMD_ARGS)221 void CMD_DestroyMenuStyle(F_CMD_ARGS)
222 {
223 MenuStyle *ms = NULL;
224 char *name = NULL;
225
226 name = PeekToken(action, NULL);
227 if (name == NULL)
228 {
229 fvwm_debug(__func__, "needs one parameter");
230 return;
231 }
232
233 ms = menustyle_find(name);
234 if (ms == NULL)
235 {
236 return;
237 }
238 else if (ms == menustyle_get_default_style())
239 {
240 fvwm_debug(__func__,
241 "cannot destroy default menu style. "
242 "To reset the default menu style use\n %s",
243 DEFAULT_MENU_STYLE);
244 return;
245 }
246 else if (ST_USAGE_COUNT(ms) != 0)
247 {
248 fvwm_debug(__func__, "menu style %s is in use",
249 name);
250 return;
251 }
252 else
253 {
254 menustyle_free(ms);
255 }
256 menus_remove_style_from_menus(ms);
257
258 return;
259 }
260
CMD_ChangeMenuStyle(F_CMD_ARGS)261 void CMD_ChangeMenuStyle(F_CMD_ARGS)
262 {
263 char *name = NULL;
264 char *menuname = NULL;
265 MenuStyle *ms = NULL;
266 MenuRoot *mr = NULL;
267
268 name = PeekToken(action, &action);
269 if (name == NULL)
270 {
271 fvwm_debug(__func__,
272 "needs at least two parameters");
273 return;
274 }
275
276 ms = menustyle_find(name);
277 if (ms == NULL)
278 {
279 fvwm_debug(__func__, "cannot find style %s", name);
280 return;
281 }
282
283 menuname = PeekToken(action, &action);
284 while (menuname && *menuname)
285 {
286 mr = menus_find_menu(menuname);
287 if (mr == NULL)
288 {
289 fvwm_debug(__func__, "cannot find menu %s",
290 menuname);
291 break;
292 }
293 if (MR_MAPPED_COPIES(mr) != 0)
294 {
295 fvwm_debug(__func__, "menu %s is in use",
296 menuname);
297 }
298 else
299 {
300 MR_STYLE(mr) = ms;
301 MR_IS_UPDATED(mr) = 1;
302 }
303 menuname = PeekToken(action, &action);
304 }
305
306 return;
307 }
308