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