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 /* ---------------------------- included header files ---------------------- */
17 
18 #include "config.h"
19 
20 #include <stdio.h>
21 #include <unistd.h>
22 #include <sys/types.h>
23 #include <sys/stat.h>
24 #include <fcntl.h>
25 #include <errno.h>
26 
27 #include "libs/fvwm_x11.h"
28 #include "libs/fvwmlib.h"
29 #include "libs/fvwmsignal.h"
30 #include "libs/cJSON.h"
31 #include "libs/setpgrp.h"
32 #include "libs/Grab.h"
33 #include "libs/Parse.h"
34 #include "libs/ColorUtils.h"
35 #include "libs/Graphics.h"
36 #include "libs/wild.h"
37 #include "libs/envvar.h"
38 #include "libs/ClientMsg.h"
39 #include "libs/Picture.h"
40 #include "libs/PictureUtils.h"
41 #include "libs/FGettext.h"
42 #include "libs/charmap.h"
43 #include "libs/wcontext.h"
44 #include "libs/Flocale.h"
45 #include "libs/FEvent.h"
46 #include "libs/Ficonv.h"
47 #include "fvwm.h"
48 #include "externs.h"
49 #include "colorset.h"
50 #include "bindings.h"
51 #include "misc.h"
52 #include "cursor.h"
53 #include "functions.h"
54 #include "commands.h"
55 #include "screen.h"
56 #include "builtins.h"
57 #include "module_interface.h"
58 #include "borders.h"
59 #include "frame.h"
60 #include "events.h"
61 #include "ewmh.h"
62 #include "virtual.h"
63 #include "decorations.h"
64 #include "add_window.h"
65 #include "update.h"
66 #include "style.h"
67 #include "move_resize.h"
68 #include "menus.h"
69 #include "infostore.h"
70 #include "focus.h"
71 
72 /* ---------------------------- local definitions -------------------------- */
73 
74 static void status_init_pipe(void);
75 
76 /* ---------------------------- local macros ------------------------------- */
77 
78 /* ---------------------------- imports ------------------------------------ */
79 
80 extern float rgpctMovementDefault[32];
81 extern int cpctMovementDefault;
82 extern int cmsDelayDefault;
83 
84 /* ---------------------------- included code files ------------------------ */
85 
86 /* ---------------------------- local types -------------------------------- */
87 typedef enum {FakeMouseEvent, FakeKeyEvent} FakeEventType;
88 /* ---------------------------- forward declarations ----------------------- */
89 
90 /* ---------------------------- local variables ---------------------------- */
91 
92 static char *exec_shell_name="/bin/sh";
93 
94 /* button state strings must match the enumerated states */
95 static char *button_states[BS_MaxButtonStateName + 1] =
96 {
97 	"ActiveUp",
98 	"ActiveDown",
99 	"InactiveUp",
100 	"InactiveDown",
101 	"ToggledActiveUp",
102 	"ToggledActiveDown",
103 	"ToggledInactiveUp",
104 	"ToggledInactiveDown",
105 	"Active",
106 	"Inactive",
107 	"ToggledActive",
108 	"ToggledInactive",
109 	"AllNormal",
110 	"AllToggled",
111 	"AllActive",
112 	"AllInactive",
113 	"AllUp",
114 	"AllDown",
115 	"AllActiveUp",
116 	"AllActiveDown",
117 	"AllInactiveUp",
118 	"AllInactiveDown",
119 	NULL
120 };
121 
122 /* ---------------------------- exported variables (globals) --------------- */
123 
124 char *ModulePath = FVWM_MODULEDIR;
125 int moduleTimeout = DEFAULT_MODULE_TIMEOUT;
126 static FILE *status_fp;
127 
128 /* ---------------------------- local functions ---------------------------- */
129 
130 void
status_send(void)131 status_send(void)
132 {
133 	cJSON		*msg = NULL, *screens = NULL;
134 	cJSON		*desk_doc[1024], *individual_d[1024];
135 	int 		 m_count, d_count;
136 	FvwmWindow	*fw_cur;
137 	DesktopsInfo 	*di;
138 	struct monitor	*m, *m_cur;
139 	char		*as_json = NULL;
140 
141 	if (status_fp == NULL || !Scr.flags.are_windows_captured)
142 		return;
143 
144 	memset(individual_d, 0, sizeof(cJSON));
145 	memset(desk_doc, 0, sizeof(cJSON));
146 
147 	if ((msg = cJSON_CreateObject()) == NULL)
148 		return;
149 
150 	m_cur = monitor_get_current();
151 
152 	cJSON_AddNumberToObject(msg, "version", 2);
153 	cJSON_AddStringToObject(msg, "current_screen", m_cur->si->name);
154 	cJSON_AddStringToObject(msg, "desktop_mode",
155 	    monitor_mode == MONITOR_TRACKING_G && is_tracking_shared ? "shared" :
156 	    monitor_mode == MONITOR_TRACKING_G ? "global" :
157 	    monitor_mode == MONITOR_TRACKING_M ? "per-monitor" :
158 	    "unknown");
159 
160 	screens = cJSON_AddObjectToObject(msg, "screens");
161 
162 	d_count = 0, m_count = 0;
163 	TAILQ_FOREACH(m, &monitor_q, entry) {
164 		cJSON	*this_desktop;
165 		if ((desk_doc[d_count] = cJSON_CreateObject()) == NULL)
166 			goto out;
167 
168 		this_desktop = cJSON_AddObjectToObject(desk_doc[d_count],
169 		    "desktops");
170 
171 		di = m->Desktops->next;
172 		while (di != NULL) {
173 			if ((individual_d[d_count] = cJSON_CreateObject()) == NULL)
174 				goto out;
175 			cJSON_AddNumberToObject(individual_d[d_count], "number",
176 				di->desk);
177 			cJSON_AddBoolToObject(individual_d[d_count], "is_current",
178 				di->desk == m->virtual_scr.CurrentDesk);
179 			cJSON_AddBoolToObject(individual_d[d_count], "is_urgent",
180 				desk_get_fw_urgent(m, di->desk));
181 			cJSON_AddNumberToObject(individual_d[d_count],
182 				"number_of_clients", desk_get_fw_count(m, di->desk));
183 			cJSON_AddItemToObject(this_desktop, di->name, individual_d[d_count]);
184 
185 			di = di->next;
186 		}
187 
188 		fw_cur = get_focus_window();
189 		if (fw_cur != NULL && fw_cur->m == m) {
190 			cJSON_AddStringToObject(desk_doc[d_count],
191 			    "current_client", fw_cur->visible_name);
192 		}
193 
194 		cJSON_AddItemToObject(screens, m->si->name, desk_doc[d_count]);
195 
196 		d_count++;
197 		m_count++;
198 	}
199 	if ((as_json = cJSON_PrintUnformatted(msg)) == NULL)
200 		goto out;
201 
202 	fflush(status_fp);
203 	fprintf(status_fp, "%s\n", as_json);
204 	fflush(status_fp);
205 
206 out:
207 	cJSON_free(as_json);
208 	cJSON_Delete(msg);
209 }
210 
211 #define PIPENAME "fvwm3.pipe"
212 #define STATUSENV "FVWM_STATUS_PIPE"
status_init_pipe(void)213 static void status_init_pipe(void)
214 {
215 	char	*tmpdir, *pipename, *addenv;
216 	int	 status_fd = -1;
217 
218 	if ((tmpdir = getenv("TMPDIR")) == NULL)
219 		tmpdir = "/tmp";
220 
221 	asprintf(&pipename, "%s/%s", tmpdir, PIPENAME);
222 
223 	unlink(pipename);
224 	if ((mkfifo(pipename, 0666) == -1)) {
225 		fvwm_debug(__func__, "mkfifo: %s", strerror(errno));
226 		free(pipename);
227 		return;
228 	}
229 
230 	if ((status_fd = open(pipename, O_RDWR|O_NONBLOCK)) == -1) {
231 		fvwm_debug(__func__, "Couldn't open pipe '%s': %s", pipename,
232 			strerror(errno));
233 		free(pipename);
234 		return;
235 	}
236 
237 	if ((status_fp = fdopen(status_fd, "w")) == NULL) {
238 		fvwm_debug(__func__, "Error opening pipe: %s", strerror(errno));
239 		free(pipename);
240 		return;
241 	}
242 
243 	xasprintf(&addenv, "%s=%s", STATUSENV, pipename);
244 	flib_putenv(STATUSENV, addenv);
245 	free(addenv);
246 
247 	fvwm_debug(__func__, "Pipe opened: %s (fd: %d)", pipename,
248 		fileno(status_fp));
249 
250 	free(pipename);
251 }
252 
253 /** Prepend rather than replace the image path.
254     Used for obsolete PixmapPath and IconPath **/
obsolete_imagepaths(const char * pre_path)255 static void obsolete_imagepaths( const char* pre_path )
256 {
257 	char* tmp = stripcpy( pre_path );
258 	char* path = alloca(strlen( tmp ) + strlen(PictureGetImagePath()) + 2 );
259 
260 	strcpy( path, tmp );
261 	free( tmp );
262 
263 	strcat( path, ":" );
264 	strcat( path, PictureGetImagePath() );
265 
266 	PictureSetImagePath( path );
267 
268 	return;
269 }
270 
271 /*
272  *
273  * Reads a title button description (veliaa@rpi.edu)
274  *
275  */
ReadTitleButton(char * s,TitleButton * tb,Bool append,int button)276 static char *ReadTitleButton(
277 	char *s, TitleButton *tb, Bool append, int button)
278 {
279 	char *end = NULL;
280 	char *spec;
281 	char *t;
282 	int i;
283 	int bs;
284 	int bs_start, bs_end;
285 	int pstyle = 0;
286 	DecorFace tmpdf;
287 
288 	Bool multiple;
289 	int use_mask = 0;
290 	int set_mask = 0;
291 
292 	s = SkipSpaces(s, NULL, 0);
293 	t = GetNextTokenIndex(s, button_states, 0, &bs);
294 	if (bs != BS_All)
295 	{
296 		s = SkipSpaces(t, NULL, 0);
297 	}
298 
299 	if (bs == BS_All)
300 	{
301 		use_mask = 0;
302 		set_mask = 0;
303 	}
304 	else if (bs == BS_Active)
305 	{
306 		use_mask = BS_MASK_INACTIVE | BS_MASK_TOGGLED;
307 		set_mask = 0;
308 	}
309 	else if (bs == BS_Inactive)
310 	{
311 		use_mask = BS_MASK_INACTIVE | BS_MASK_TOGGLED;
312 		set_mask = BS_MASK_INACTIVE;
313 	}
314 	else if (bs == BS_ToggledActive)
315 	{
316 		use_mask = BS_MASK_INACTIVE | BS_MASK_TOGGLED;
317 		set_mask = BS_MASK_TOGGLED;
318 	}
319 	else if (bs == BS_ToggledInactive)
320 	{
321 		use_mask = BS_MASK_INACTIVE | BS_MASK_TOGGLED;
322 		set_mask = BS_MASK_INACTIVE | BS_MASK_TOGGLED;
323 	}
324 	else if (bs == BS_AllNormal)
325 	{
326 		use_mask = BS_MASK_TOGGLED;
327 		set_mask = 0;
328 	}
329 	else if (bs == BS_AllToggled)
330 	{
331 		use_mask = BS_MASK_TOGGLED;
332 		set_mask = BS_MASK_TOGGLED;
333 	}
334 	else if (bs == BS_AllActive)
335 	{
336 		use_mask = BS_MASK_INACTIVE;
337 		set_mask = 0;
338 	}
339 	else if (bs == BS_AllInactive)
340 	{
341 		use_mask = BS_MASK_INACTIVE;
342 		set_mask = BS_MASK_INACTIVE;
343 	}
344 	else if (bs == BS_AllUp)
345 	{
346 		use_mask = BS_MASK_DOWN;
347 		set_mask = 0;
348 	}
349 	else if (bs == BS_AllDown)
350 	{
351 		use_mask = BS_MASK_DOWN;
352 		set_mask = BS_MASK_DOWN;
353 	}
354 	else if (bs == BS_AllActiveUp)
355 	{
356 		use_mask = BS_MASK_INACTIVE | BS_MASK_DOWN;
357 		set_mask = 0;
358 	}
359 	else if (bs == BS_AllActiveDown)
360 	{
361 		use_mask = BS_MASK_INACTIVE | BS_MASK_DOWN;
362 		set_mask = BS_MASK_DOWN;
363 	}
364 	else if (bs == BS_AllInactiveUp)
365 	{
366 		use_mask = BS_MASK_INACTIVE | BS_MASK_DOWN;
367 		set_mask = BS_MASK_INACTIVE;
368 	}
369 	else if (bs == BS_AllInactiveDown)
370 	{
371 		use_mask = BS_MASK_INACTIVE | BS_MASK_DOWN;
372 		set_mask = BS_MASK_INACTIVE | BS_MASK_DOWN;
373 	}
374 
375 	if ((bs & BS_MaxButtonStateMask) == bs)
376 	{
377 		multiple = False;
378 		bs_start = bs;
379 		bs_end = bs;
380 	}
381 	else
382 	{
383 		multiple = True;
384 		bs_start = 0;
385 		bs_end = BS_MaxButtonState - 1;
386 		for (i = bs_start; (i & use_mask) != set_mask && i <= bs_end;
387 			i++)
388 		{
389 			bs_start++;
390 		}
391 	}
392 
393 	if (*s == '(')
394 	{
395 		int len;
396 		pstyle = 1;
397 		if (!(end = strchr(++s, ')')))
398 		{
399 			fvwm_debug(__func__,
400 				   "missing parenthesis: %s", s);
401 			return NULL;
402 		}
403 		s = SkipSpaces(s, NULL, 0);
404 		len = end - s + 1;
405 		/* TA:  FIXME!  xasprintf() */
406 		spec = fxmalloc(len);
407 		strncpy(spec, s, len - 1);
408 		spec[len - 1] = 0;
409 	}
410 	else
411 	{
412 		spec = s;
413 	}
414 
415 	spec = SkipSpaces(spec, NULL, 0);
416 	/* setup temporary in case button read fails */
417 	memset(&tmpdf, 0, sizeof(DecorFace));
418 	DFS_FACE_TYPE(tmpdf.style) = SimpleButton;
419 
420 	if (strncmp(spec, "--", 2) == 0)
421 	{
422 		/* only change flags */
423 		Bool verbose = True;
424 		for (i = bs_start; i <= bs_end; ++i)
425 		{
426 			if (multiple && (i & use_mask) != set_mask)
427 			{
428 				continue;
429 			}
430 			ReadDecorFace(spec, &TB_STATE(*tb)[i], button, verbose);
431 			verbose = False;
432 		}
433 	}
434 	else if (ReadDecorFace(spec, &tmpdf, button, True))
435 	{
436 		if (append)
437 		{
438 			DecorFace *head = &TB_STATE(*tb)[bs_start];
439 			DecorFace *tail = head;
440 			DecorFace *next;
441 
442 			while (tail->next)
443 			{
444 				tail = tail->next;
445 			}
446 			tail->next = fxmalloc(sizeof(DecorFace));
447 			memcpy(tail->next, &tmpdf, sizeof(DecorFace));
448 			if (DFS_FACE_TYPE(tail->next->style) == VectorButton &&
449 			    DFS_FACE_TYPE((&TB_STATE(*tb)[bs_start])->style) ==
450 			    DefaultVectorButton)
451 			{
452 				/* override the default vector style */
453 				memcpy(
454 					&tail->next->style, &head->style,
455 					sizeof(DecorFaceStyle));
456 				DFS_FACE_TYPE(tail->next->style) = VectorButton;
457 				next = head->next;
458 				head->next = NULL;
459 				FreeDecorFace(dpy, head);
460 				memcpy(head, next, sizeof(DecorFace));
461 				free(next);
462 			}
463 			for (i = bs_start + 1; i <= bs_end; ++i)
464 			{
465 				if (multiple && (i & use_mask) != set_mask)
466 				{
467 					continue;
468 				}
469 				head = &TB_STATE(*tb)[i];
470 				tail = head;
471 				while (tail->next)
472 				{
473 					tail = tail->next;
474 				}
475 				tail->next = fxcalloc(1, sizeof(DecorFace));
476 				DFS_FACE_TYPE(tail->next->style) =
477 					SimpleButton;
478 				tail->next->next = NULL;
479 				ReadDecorFace(spec, tail->next, button, False);
480 				if (DFS_FACE_TYPE(tail->next->style) ==
481 				    VectorButton &&
482 				    DFS_FACE_TYPE((&TB_STATE(*tb)[i])->style) ==
483 				    DefaultVectorButton)
484 				{
485 					/* override the default vector style */
486 					memcpy(
487 						&tail->next->style,
488 						&head->style,
489 						sizeof(DecorFaceStyle));
490 					DFS_FACE_TYPE(tail->next->style) =
491 						VectorButton;
492 					next = head->next;
493 					head->next = NULL;
494 					FreeDecorFace(dpy, head);
495 					memcpy(head, next, sizeof(DecorFace));
496 					free(next);
497 				}
498 			}
499 		}
500 		else
501 		{
502 			FreeDecorFace(dpy, &TB_STATE(*tb)[bs_start]);
503 			memcpy(
504 				&(TB_STATE(*tb)[bs_start]), &tmpdf,
505 				sizeof(DecorFace));
506 			for (i = bs_start + 1; i <= bs_end; ++i)
507 			{
508 				if (multiple && (i & use_mask) != set_mask)
509 				{
510 					continue;
511 				}
512 				ReadDecorFace(
513 					spec, &TB_STATE(*tb)[i], button, False);
514 			}
515 		}
516 	}
517 	if (pstyle)
518 	{
519 		free(spec);
520 		end++;
521 		end = SkipSpaces(end, NULL, 0);
522 	}
523 
524 	return end;
525 }
526 
527 /* Remove the given decor from all windows */
__remove_window_decors(F_CMD_ARGS,FvwmDecor * d)528 static void __remove_window_decors(F_CMD_ARGS, FvwmDecor *d)
529 {
530 	const exec_context_t *exc2;
531 	exec_context_changes_t ecc;
532 	FvwmWindow *t;
533 
534 	for (t = Scr.FvwmRoot.next; t; t = t->next)
535 	{
536 		if (t->decor == d)
537 		{
538 			/* remove the extra title height now because we delete
539 			 * the current decor before calling ChangeDecor(). */
540 			t->g.frame.height -= t->decor->title_height;
541 			t->decor = NULL;
542 			ecc.w.fw = t;
543 			ecc.w.wcontext = C_WINDOW;
544 			exc2 = exc_clone_context(
545 				exc, &ecc, ECC_FW | ECC_WCONTEXT);
546 			execute_function(
547 				cond_rc, exc2, "ChangeDecor Default", 0);
548 			exc_destroy_context(exc2);
549 		}
550 	}
551 
552 	return;
553 }
554 
do_title_style(F_CMD_ARGS,Bool do_add)555 static void do_title_style(F_CMD_ARGS, Bool do_add)
556 {
557 	char *parm;
558 	char *prev;
559 	FvwmDecor *decor = Scr.cur_decor ? Scr.cur_decor : &Scr.DefaultDecor;
560 
561 	Scr.flags.do_need_window_update = 1;
562 	decor->flags.has_changed = 1;
563 	decor->titlebar.flags.has_changed = 1;
564 
565 	for (prev = action ; (parm = PeekToken(action, &action)); prev = action)
566 	{
567 		if (!do_add && StrEquals(parm,"centered"))
568 		{
569 			TB_JUSTIFICATION(decor->titlebar) = JUST_CENTER;
570 		}
571 		else if (!do_add && StrEquals(parm,"leftjustified"))
572 		{
573 			TB_JUSTIFICATION(decor->titlebar) = JUST_LEFT;
574 		}
575 		else if (!do_add && StrEquals(parm,"rightjustified"))
576 		{
577 			TB_JUSTIFICATION(decor->titlebar) = JUST_RIGHT;
578 		}
579 		else if (!do_add && StrEquals(parm,"height"))
580 		{
581 			int height = 0;
582 			int next = 0;
583 
584 			if (!action ||
585 			    sscanf(action, "%d%n", &height, &next) <= 0 ||
586 			    height < MIN_FONT_HEIGHT ||
587 			    height > MAX_FONT_HEIGHT)
588 			{
589 				if (height != 0)
590 				{
591 					fvwm_debug(__func__,
592 						   "bad height argument (height"
593 						   " must be from 5 to 256)");
594 					height = 0;
595 				}
596 			}
597 			if (decor->title_height != height ||
598 			    decor->min_title_height != 0)
599 			{
600 				decor->title_height = height;
601 				decor->min_title_height = 0;
602 				decor->flags.has_title_height_changed = 1;
603 			}
604 			if (action)
605 				action += next;
606 		}
607 		else if (!do_add && StrEquals(parm,"MinHeight"))
608 		{
609 			int height = 0;
610 			int next = 0;
611 
612 			if (!action ||
613 			    sscanf(action, "%d%n", &height, &next) <= 0 ||
614 			    height < MIN_FONT_HEIGHT ||
615 			    height > MAX_FONT_HEIGHT)
616 			{
617 				if (height < MIN_FONT_HEIGHT)
618 					height = MIN_FONT_HEIGHT;
619 				else if (height > MAX_FONT_HEIGHT)
620 					height = 0;
621 			}
622 			if (decor->min_title_height != height)
623 			{
624 				decor->title_height = 0;
625 				decor->min_title_height = height;
626 				decor->flags.has_title_height_changed = 1;
627 			}
628 			if (action)
629 				action += next;
630 		}
631 		else
632 		{
633 			action = ReadTitleButton(
634 				prev, &decor->titlebar, do_add, -1);
635 		}
636 	}
637 
638 	return;
639 }
640 
641 /*
642  *
643  * Reads a multi-pixmap titlebar config. (tril@igs.net)
644  *
645  */
ReadMultiPixmapDecor(char * s,DecorFace * df)646 static char *ReadMultiPixmapDecor(char *s, DecorFace *df)
647 {
648 	static char *pm_names[TBMP_NUM_PIXMAPS+1] =
649 		{
650 			"Main",
651 			"LeftMain",
652 			"RightMain",
653 			"LeftButtons",
654 			"RightButtons",
655 			"UnderText",
656 			"LeftOfText",
657 			"RightOfText",
658 			"LeftEnd",
659 			"RightEnd",
660 			"Buttons",
661 			NULL
662 		};
663 	FvwmPicture **pm;
664 	FvwmAcs *acs;
665 	Pixel *pixels;
666 	char *token;
667 	Bool stretched;
668 	Bool load_pixmap = False;
669 	int pm_id, i = 0;
670 	FvwmPictureAttributes fpa;
671 
672 	df->style.face_type = MultiPixmap;
673 	df->u.mp.pixmaps = pm = fxcalloc(TBMP_NUM_PIXMAPS, sizeof(FvwmPicture*));
674 	df->u.mp.acs = acs = fxmalloc(TBMP_NUM_PIXMAPS * sizeof(FvwmAcs));
675 	df->u.mp.pixels = pixels = fxmalloc(TBMP_NUM_PIXMAPS * sizeof(Pixel));
676 	for(i=0; i < TBMP_NUM_PIXMAPS; i++)
677 	{
678 		acs[i].cs = -1;
679 		acs[i].alpha_percent = 100;
680 	}
681 	s = GetNextTokenIndex(s, pm_names, 0, &pm_id);
682 	while (pm_id >= 0)
683 	{
684 		stretched = False;
685 		load_pixmap = False;
686 		s = DoPeekToken(s, &token, ",()", NULL, NULL);
687 		if (StrEquals(token, "stretched"))
688 		{
689 			stretched = True;
690 			s = DoPeekToken(s, &token, ",", NULL, NULL);
691 		}
692 		else if (StrEquals(token, "tiled"))
693 		{
694 			s = DoPeekToken(s, &token, ",", NULL, NULL);
695 		}
696 		if (!token)
697 		{
698 			break;
699 		}
700 		if (pm[pm_id] || acs[pm_id].cs >= 0 ||
701 		    (df->u.mp.solid_flags & (1 << pm_id)))
702 		{
703 			fvwm_debug(__func__,
704 				   "Ignoring: already-specified %s",
705 				   pm_names[i]);
706 			continue;
707 		}
708 		if (stretched)
709 		{
710 			df->u.mp.stretch_flags |= (1 << pm_id);
711 		}
712 		if (strncasecmp (token, "Colorset", 8) == 0)
713 		{
714 			int val;
715 			char *tmp;
716 
717 			tmp = DoPeekToken(s, &token, ",", NULL, NULL);
718 			if (!GetIntegerArguments(token, NULL, &val, 1) ||
719 			    val < 0)
720 			{
721 				fvwm_debug(__func__,
722 					   "Colorset should take one or two "
723 					   "positive integers as argument");
724 			}
725 			else
726 			{
727 				acs[pm_id].cs = val;
728 				alloc_colorset(val);
729 				s = tmp;
730 				tmp = DoPeekToken(s, &token, ",", NULL, NULL);
731 				if (GetIntegerArguments(token, NULL, &val, 1))
732 				{
733 					acs[pm_id].alpha_percent =
734 						max(0, min(100,val));
735 					s = tmp;
736 				}
737 			}
738 		}
739 		else if (strncasecmp(token, "TiledPixmap", 11) == 0)
740 		{
741 			s = DoPeekToken(s, &token, ",", NULL, NULL);
742 			load_pixmap = True;
743 		}
744 		else if (strncasecmp(token, "AdjustedPixmap", 14) == 0)
745 		{
746 			s = DoPeekToken(s, &token, ",", NULL, NULL);
747 			load_pixmap = True;
748 			df->u.mp.stretch_flags |= (1 << pm_id);
749 		}
750 		else if (strncasecmp(token, "Solid", 5) == 0)
751 		{
752 			s = DoPeekToken(s, &token, ",", NULL, NULL);
753 			if (token)
754 			{
755 				df->u.mp.pixels[pm_id] = GetColor(token);
756 				df->u.mp.solid_flags |= (1 << pm_id);
757 			}
758 		}
759 		else
760 		{
761 			load_pixmap = True;
762 		}
763 		if (load_pixmap && token)
764 		{
765 			fpa.mask = (Pdepth <= 8)? FPAM_DITHER:0; /* ? */
766 			pm[pm_id] = PCacheFvwmPicture(
767 				dpy, Scr.NoFocusWin, NULL, token, fpa);
768 			if (!pm[pm_id])
769 			{
770 				fvwm_debug(__func__,
771 					   "Pixmap '%s' could not be loaded",
772 					   token);
773 			}
774 		}
775 		if (pm_id == TBMP_BUTTONS)
776 		{
777 			if (pm[TBMP_LEFT_BUTTONS])
778 			{
779 				PDestroyFvwmPicture(dpy, pm[TBMP_LEFT_BUTTONS]);
780 			}
781 			if (pm[TBMP_RIGHT_BUTTONS])
782 			{
783 				PDestroyFvwmPicture(dpy, pm[TBMP_RIGHT_BUTTONS]);
784 			}
785 			df->u.mp.stretch_flags &= ~(1 << TBMP_LEFT_BUTTONS);
786 			df->u.mp.stretch_flags &= ~(1 << TBMP_RIGHT_BUTTONS);
787 			df->u.mp.solid_flags &= ~(1 << TBMP_LEFT_BUTTONS);
788 			df->u.mp.solid_flags &= ~(1 << TBMP_RIGHT_BUTTONS);
789 			if (pm[TBMP_BUTTONS])
790 			{
791 				pm[TBMP_LEFT_BUTTONS] =
792 					PCloneFvwmPicture(pm[TBMP_BUTTONS]);
793 				acs[TBMP_LEFT_BUTTONS].cs = -1;
794 				pm[TBMP_RIGHT_BUTTONS] =
795 					PCloneFvwmPicture(pm[TBMP_BUTTONS]);
796 				acs[TBMP_RIGHT_BUTTONS].cs = -1;
797 			}
798 			else
799 			{
800 				pm[TBMP_RIGHT_BUTTONS] =
801 					pm[TBMP_LEFT_BUTTONS] = NULL;
802 				acs[TBMP_RIGHT_BUTTONS].cs =
803 					acs[TBMP_LEFT_BUTTONS].cs =
804 					acs[TBMP_BUTTONS].cs;
805 				acs[TBMP_RIGHT_BUTTONS].alpha_percent =
806 					acs[TBMP_LEFT_BUTTONS].alpha_percent =
807 					acs[TBMP_BUTTONS].alpha_percent;
808 				pixels[TBMP_LEFT_BUTTONS] =
809 					pixels[TBMP_RIGHT_BUTTONS] =
810 					pixels[TBMP_BUTTONS];
811 			}
812 			if (stretched)
813 			{
814 				df->u.mp.stretch_flags |=
815 					(1 << TBMP_LEFT_BUTTONS) |
816 					(1 << TBMP_RIGHT_BUTTONS);
817 			}
818 			if (df->u.mp.solid_flags & (1 << TBMP_BUTTONS))
819 			{
820 				df->u.mp.solid_flags |=
821 					(1 << TBMP_LEFT_BUTTONS);
822 				df->u.mp.solid_flags |=
823 					(1 << TBMP_RIGHT_BUTTONS);
824 			}
825 			if (pm[TBMP_BUTTONS])
826 			{
827 				PDestroyFvwmPicture(dpy, pm[TBMP_BUTTONS]);
828 				pm[TBMP_BUTTONS] = NULL;
829 			}
830 			acs[TBMP_BUTTONS].cs = -1;
831 			df->u.mp.solid_flags &= ~(1 << TBMP_BUTTONS);
832 		}
833 		s = SkipSpaces(s, NULL, 0);
834 		s = GetNextTokenIndex(s, pm_names, 0, &pm_id);
835 	}
836 
837 	if (!(pm[TBMP_MAIN] || acs[TBMP_MAIN].cs >= 0 ||
838 	      (df->u.mp.solid_flags & TBMP_MAIN))
839 	    &&
840 	    !(pm[TBMP_LEFT_MAIN] || acs[TBMP_LEFT_MAIN].cs >= 0 ||
841 	      (df->u.mp.solid_flags & TBMP_LEFT_MAIN))
842 	      &&
843 	    !(pm[TBMP_RIGHT_MAIN] || acs[TBMP_RIGHT_MAIN].cs >= 0 ||
844 	      (df->u.mp.solid_flags & TBMP_RIGHT_MAIN)))
845 	{
846 		fvwm_debug(__func__,
847 			   "No Main pixmap/colorset/solid found for TitleStyle "
848 			   "MultiPixmap  (you must specify either Main, "
849 			   "or both LeftMain and RightMain)");
850 		for (i=0; i < TBMP_NUM_PIXMAPS; i++)
851 		{
852 			if (pm[i])
853 			{
854 				PDestroyFvwmPicture(dpy, pm[i]);
855 			}
856 			else if (!!(df->u.mp.solid_flags & i))
857 			{
858 				PictureFreeColors(
859 					dpy, Pcmap, &df->u.mp.pixels[i], 1, 0,
860 					False);
861 			}
862 		}
863 		free(pm);
864 		free(acs);
865 		free(pixels);
866 		return NULL;
867 	}
868 
869 	return s;
870 }
871 
872 /*
873  *
874  *  DestroyFvwmDecor -- frees all memory assocated with an FvwmDecor
875  *      structure, but does not free the FvwmDecor itself
876  *
877  */
DestroyFvwmDecor(FvwmDecor * decor)878 static void DestroyFvwmDecor(FvwmDecor *decor)
879 {
880 	int i;
881 	/* reset to default button set (frees allocated mem) */
882 	DestroyAllButtons(decor);
883 	for (i = 0; i < BS_MaxButtonState; ++i)
884 	{
885 		FreeDecorFace(dpy, &TB_STATE(decor->titlebar)[i]);
886 	}
887 	FreeDecorFace(dpy, &decor->BorderStyle.active);
888 	FreeDecorFace(dpy, &decor->BorderStyle.inactive);
889 	if (decor->tag)
890 	{
891 		free(decor->tag);
892 		decor->tag = NULL;
893 	}
894 
895 	return;
896 }
897 
SetLayerButtonFlag(int layer,int multi,int set,FvwmDecor * decor,TitleButton * tb)898 static void SetLayerButtonFlag(
899 	int layer, int multi, int set, FvwmDecor *decor, TitleButton *tb)
900 {
901 	int i;
902 	int start = 0;
903 	int add = 2;
904 
905 	if (multi)
906 	{
907 		if (multi == 2)
908 		{
909 			start = 1;
910 		}
911 		else if (multi == 3)
912 		{
913 			add = 1;
914 		}
915 		for (i = start; i < NUMBER_OF_TITLE_BUTTONS; i += add)
916 		{
917 			if (set)
918 			{
919 				TB_FLAGS(decor->buttons[i]).has_layer = 1;
920 				TB_LAYER(decor->buttons[i]) = layer;
921 			}
922 			else
923 			{
924 				TB_FLAGS(decor->buttons[i]).has_layer = 0;
925 			}
926 		}
927 	}
928 	else
929 	{
930 		if (set)
931 		{
932 			TB_FLAGS(*tb).has_layer = 1;
933 			TB_LAYER(*tb) = layer;
934 		}
935 		else
936 		{
937 			TB_FLAGS(*tb).has_layer = 0;
938 		}
939 	}
940 
941 	return;
942 }
943 
944 /*
945  *
946  * Changes a button decoration style (changes by veliaa@rpi.edu)
947  *
948  */
SetMWMButtonFlag(mwm_flags flag,int multi,int set,FvwmDecor * decor,TitleButton * tb)949 static void SetMWMButtonFlag(
950 	mwm_flags flag, int multi, int set, FvwmDecor *decor, TitleButton *tb)
951 {
952 	int i;
953 	int start = 0;
954 	int add = 2;
955 
956 	if (multi)
957 	{
958 		if (multi == 2)
959 		{
960 			start = 1;
961 		}
962 		else if (multi == 3)
963 		{
964 			add = 1;
965 		}
966 		for (i = start; i < NUMBER_OF_TITLE_BUTTONS; i += add)
967 		{
968 			if (set)
969 			{
970 				TB_MWM_DECOR_FLAGS(decor->buttons[i]) |= flag;
971 			}
972 			else
973 			{
974 				TB_MWM_DECOR_FLAGS(decor->buttons[i]) &= ~flag;
975 			}
976 		}
977 	}
978 	else
979 	{
980 		if (set)
981 		{
982 			TB_MWM_DECOR_FLAGS(*tb) |= flag;
983 		}
984 		else
985 		{
986 			TB_MWM_DECOR_FLAGS(*tb) &= ~flag;
987 		}
988 	}
989 
990 	return;
991 }
992 
do_button_style(F_CMD_ARGS,Bool do_add)993 static void do_button_style(F_CMD_ARGS, Bool do_add)
994 {
995 	int i;
996 	int multi = 0;
997 	int button = 0;
998 	int do_return;
999 	char *text = NULL;
1000 	char *prev = NULL;
1001 	char *parm = NULL;
1002 	TitleButton *tb = NULL;
1003 	FvwmDecor *decor = Scr.cur_decor ? Scr.cur_decor : &Scr.DefaultDecor;
1004 
1005 	parm = PeekToken(action, &text);
1006 	if (parm && isdigit(*parm))
1007 	{
1008 		button = atoi(parm);
1009 		button = BUTTON_INDEX(button);
1010 	}
1011 
1012 	if (parm == NULL || button >= NUMBER_OF_TITLE_BUTTONS || button < 0)
1013 	{
1014 		fvwm_debug(__func__, "Bad button style (1) in line %s",
1015 			   action);
1016 		return;
1017 	}
1018 
1019 	Scr.flags.do_need_window_update = 1;
1020 
1021 	do_return = 0;
1022 	if (!isdigit(*parm))
1023 	{
1024 		if (StrEquals(parm,"left"))
1025 		{
1026 			multi = 1; /* affect all left buttons */
1027 		}
1028 		else if (StrEquals(parm,"right"))
1029 		{
1030 			multi = 2; /* affect all right buttons */
1031 		}
1032 		else if (StrEquals(parm,"all"))
1033 		{
1034 			multi = 3; /* affect all buttons */
1035 		}
1036 		else
1037 		{
1038 			/* we're either resetting buttons or an invalid button
1039 			 * set was specified */
1040 			if (StrEquals(parm,"reset"))
1041 			{
1042 				ResetAllButtons(decor);
1043 			}
1044 			else
1045 			{
1046 				fvwm_debug(__func__,
1047 					   "Bad button style (2) in line %s",
1048 					   action);
1049 			}
1050 			multi = 3;
1051 			do_return = 1;
1052 		}
1053 	}
1054 	/* mark button style and decor as changed */
1055 	decor->flags.has_changed = 1;
1056 	if (multi == 0)
1057 	{
1058 		/* a single button was specified */
1059 		tb = &decor->buttons[button];
1060 		TB_FLAGS(*tb).has_changed = 1;
1061 	}
1062 	else
1063 	{
1064 		for (i = 0; i < NUMBER_OF_TITLE_BUTTONS; ++i)
1065 		{
1066 			if (((multi & 1) && !(i & 1)) ||
1067 			    ((multi & 2) && (i & 1)))
1068 			{
1069 				TB_FLAGS(decor->buttons[i]).has_changed = 1;
1070 			}
1071 		}
1072 	}
1073 	if (do_return == 1)
1074 	{
1075 		return;
1076 	}
1077 	for (prev = text; (parm = PeekToken(text, &text)); prev = text)
1078 	{
1079 		if (!do_add && strcmp(parm,"-") == 0)
1080 		{
1081 			char *tok;
1082 			text = GetNextToken(text, &tok);
1083 			while (tok)
1084 			{
1085 				int set = 1;
1086 				char *old_tok = NULL;
1087 
1088 				if (*tok == '!')
1089 				{
1090 					/* flag negate */
1091 					set = 0;
1092 					old_tok = tok;
1093 					tok++;
1094 				}
1095 				if (StrEquals(tok,"Clear"))
1096 				{
1097 					if (multi)
1098 					{
1099 						for (i = 0;
1100 						     i < NUMBER_OF_TITLE_BUTTONS; ++i)
1101 						{
1102 							if (((multi & 1) &&
1103 							     !(i & 1)) ||
1104 							    ((multi & 2) &&
1105 							     (i & 1)))
1106 							{
1107 								TB_JUSTIFICATION(decor->buttons[i]) =
1108 									(set) ? JUST_CENTER : JUST_RIGHT;
1109 								memset(&TB_FLAGS(decor->buttons[i]), (set) ? 0 : 0xff,
1110 								       sizeof(TB_FLAGS(decor->buttons[i])));
1111 								/* ? not very useful if set == 0 ? */
1112 							}
1113 						}
1114 					}
1115 					else
1116 					{
1117 						TB_JUSTIFICATION(*tb) = (set) ?
1118 							JUST_CENTER :
1119 							JUST_RIGHT;
1120 						memset(&TB_FLAGS(*tb), (set) ?
1121 						       0 : 0xff,
1122 						       sizeof(TB_FLAGS(*tb)));
1123 						/* ? not very useful if
1124 						 * set == 0 ? */
1125 					}
1126 				}
1127 				else if (StrEquals(tok, "MWMDecorMenu"))
1128 				{
1129 					SetMWMButtonFlag(
1130 						MWM_DECOR_MENU, multi, set,
1131 						decor, tb);
1132 				}
1133 				else if (StrEquals(tok, "MWMDecorMin"))
1134 				{
1135 					SetMWMButtonFlag(
1136 						MWM_DECOR_MINIMIZE, multi, set,
1137 						decor, tb);
1138 				}
1139 				else if (StrEquals(tok, "MWMDecorMax"))
1140 				{
1141 					SetMWMButtonFlag(
1142 						MWM_DECOR_MAXIMIZE, multi, set,
1143 						decor, tb);
1144 				}
1145 				else if (StrEquals(tok, "MWMDecorShade"))
1146 				{
1147 					SetMWMButtonFlag(
1148 						MWM_DECOR_SHADE, multi, set,
1149 						decor, tb);
1150 				}
1151 				else if (StrEquals(tok, "MWMDecorStick"))
1152 				{
1153 					SetMWMButtonFlag(
1154 						MWM_DECOR_STICK, multi, set,
1155 						decor, tb);
1156 				}
1157 				else if (StrEquals(tok, "MwmDecorLayer"))
1158 				{
1159 					int layer, got_number;
1160 					char *ltok;
1161 					text = GetNextToken(text, &ltok);
1162 					if (ltok)
1163 					{
1164 						got_number =
1165 							(sscanf(ltok, "%d",
1166 								&layer) == 1);
1167 						free (ltok);
1168 					}
1169 					else
1170 					{
1171 						got_number = 0;
1172 					}
1173 					if (!ltok || !got_number)
1174 					{
1175 						fvwm_debug(__func__,
1176 							   "could not read"
1177 							   " integer value for"
1178 							   " layer -- line: %s",
1179 							   text);
1180 					}
1181 					else
1182 					{
1183 						SetLayerButtonFlag(
1184 							layer, multi, set,
1185 							decor, tb);
1186 					}
1187 
1188 				}
1189 				else
1190 				{
1191 					fvwm_debug(__func__,
1192 						   "unknown title button flag"
1193 						   " %s -- line: %s", tok,
1194 						   text);
1195 				}
1196 				if (set)
1197 				{
1198 					free(tok);
1199 				}
1200 				else
1201 				{
1202 					free(old_tok);
1203 				}
1204 				text = GetNextToken(text, &tok);
1205 			}
1206 			break;
1207 		}
1208 		else
1209 		{
1210 			if (multi)
1211 			{
1212 				for (i = 0; i < NUMBER_OF_TITLE_BUTTONS; ++i)
1213 				{
1214 					if (((multi & 1) && !(i & 1)) ||
1215 					    ((multi & 2) && (i & 1)))
1216 					{
1217 						text = ReadTitleButton(
1218 							prev,
1219 							&decor->buttons[i],
1220 							do_add, i);
1221 					}
1222 				}
1223 			}
1224 			else if (!(text = ReadTitleButton(
1225 					   prev, tb, do_add, button)))
1226 			{
1227 				break;
1228 			}
1229 		}
1230 	}
1231 
1232 	return;
1233 }
1234 
1235 static
update_decorface_colorset(DecorFace * df,int cset)1236 int update_decorface_colorset(DecorFace *df, int cset)
1237 {
1238 	DecorFace *tdf;
1239 	int has_changed = 0;
1240 
1241 	for(tdf = df; tdf != NULL; tdf = tdf->next)
1242 	{
1243 		if (DFS_FACE_TYPE(tdf->style) == ColorsetButton &&
1244 		    tdf->u.acs.cs == cset)
1245 		{
1246 			tdf->flags.has_changed = 1;
1247 			has_changed = 1;
1248 		}
1249 		else if (DFS_FACE_TYPE(tdf->style) == MultiPixmap)
1250 		{
1251 			int i;
1252 
1253 			for (i = 0; i < TBMP_NUM_PIXMAPS; i++)
1254 			{
1255 				if (tdf->u.mp.acs[i].cs == cset)
1256 				{
1257 					tdf->flags.has_changed = 1;
1258 					has_changed = 1;
1259 				}
1260 			}
1261 		}
1262 }
1263 
1264 	return has_changed;
1265 }
1266 
1267 static
update_titlebutton_colorset(TitleButton * tb,int cset)1268 int update_titlebutton_colorset(TitleButton *tb, int cset)
1269 {
1270 	int i;
1271 	int has_changed = 0;
1272 
1273 	for(i = 0; i < BS_MaxButtonState; i++)
1274 	{
1275 		tb->state[i].flags.has_changed =
1276 			update_decorface_colorset(&(tb->state[i]), cset);
1277 		has_changed |= tb->state[i].flags.has_changed;
1278 	}
1279 	return has_changed;
1280 }
1281 
1282 static
update_decors_colorset(int cset)1283 void update_decors_colorset(int cset)
1284 {
1285 	int i;
1286 	FvwmDecor *decor = &Scr.DefaultDecor;
1287 
1288 	for(decor = &Scr.DefaultDecor; decor != NULL; decor = decor->next)
1289 	{
1290 		for(i = 0; i < NUMBER_OF_TITLE_BUTTONS; i++)
1291 		{
1292 			decor->flags.has_changed |= update_titlebutton_colorset(
1293 				&(decor->buttons[i]), cset);
1294 		}
1295 		decor->flags.has_changed |= update_titlebutton_colorset(
1296 			&(decor->titlebar), cset);
1297 		decor->flags.has_changed |= update_decorface_colorset(
1298 			&(decor->BorderStyle.active), cset);
1299 		decor->flags.has_changed |= update_decorface_colorset(
1300 			&(decor->BorderStyle.inactive), cset);
1301 		if (decor->flags.has_changed)
1302 		{
1303 			Scr.flags.do_need_window_update = 1;
1304 		}
1305 	}
1306 }
1307 
__parse_vector_line_one_coord(char ** ret_action,int * pcoord,int * poff,char * action)1308 static Bool __parse_vector_line_one_coord(
1309 	char **ret_action, int *pcoord, int *poff, char *action)
1310 {
1311 	int offset;
1312 	int n;
1313 
1314 	*ret_action = action;
1315 	n = sscanf(action, "%d%n", pcoord, &offset);
1316 	if (n < 1)
1317 	{
1318 		return False;
1319 	}
1320 	action += offset;
1321 	/* check for offest */
1322 	if (*action == '+' || *action == '-')
1323 	{
1324 		n = sscanf(action, "%dp%n", poff, &offset);
1325 		if (n < 1)
1326 		{
1327 			return False;
1328 		}
1329 		if (*poff < -128)
1330 		{
1331 			*poff = -128;
1332 		}
1333 		else if (*poff > 127)
1334 		{
1335 			*poff = 127;
1336 		}
1337 		action += offset;
1338 	}
1339 	else
1340 	{
1341 		*poff = 0;
1342 	}
1343 	*ret_action = action;
1344 
1345 	return True;
1346 }
1347 
__parse_vector_line(char ** ret_action,int * px,int * py,int * pxoff,int * pyoff,int * pc,char * action)1348 static Bool __parse_vector_line(
1349 	char **ret_action, int *px, int *py, int *pxoff, int *pyoff, int *pc,
1350 	char *action)
1351 {
1352 	Bool is_valid = True;
1353 	int offset;
1354 	int n;
1355 
1356 	*ret_action = action;
1357 	if (__parse_vector_line_one_coord(&action, px, pxoff, action) == False)
1358 	{
1359 		return False;
1360 	}
1361 	if (*action != 'x')
1362 	{
1363 		return False;
1364 	}
1365 	action++;
1366 	if (__parse_vector_line_one_coord(&action, py, pyoff, action) == False)
1367 	{
1368 		return False;
1369 	}
1370 	if (*action != '@')
1371 	{
1372 		return False;
1373 	}
1374 	action++;
1375 	/* read the line style */
1376 	n = sscanf(action, "%d%n", pc, &offset);
1377 	if (n < 1)
1378 	{
1379 		return False;
1380 	}
1381 	action += offset;
1382 	*ret_action = action;
1383 
1384 	return is_valid;
1385 }
1386 
1387 /* ---------------------------- interface functions ------------------------ */
1388 
refresh_window(Window w,Bool window_update)1389 void refresh_window(Window w, Bool window_update)
1390 {
1391 	XSetWindowAttributes attributes;
1392 	unsigned long valuemask;
1393 
1394 	valuemask = CWOverrideRedirect | CWBackingStore | CWSaveUnder |
1395 		CWBackPixmap;
1396 	attributes.override_redirect = True;
1397 	attributes.save_under = False;
1398 	attributes.background_pixmap = None;
1399 	attributes.backing_store = NotUseful;
1400 	w = XCreateWindow(
1401 		dpy, w, 0, 0, monitor_get_all_widths(),
1402 		monitor_get_all_heights(), 0,
1403 		CopyFromParent, CopyFromParent, CopyFromParent, valuemask,
1404 		&attributes);
1405 	XMapWindow(dpy, w);
1406 	if (Scr.flags.do_need_window_update && window_update)
1407 	{
1408 		flush_window_updates();
1409 	}
1410 	XDestroyWindow(dpy, w);
1411 	XSync(dpy, 0);
1412 	handle_all_expose();
1413 
1414 	return;
1415 }
1416 
ApplyDefaultFontAndColors(void)1417 void ApplyDefaultFontAndColors(void)
1418 {
1419 	XGCValues gcv;
1420 	unsigned long gcm;
1421 	int cset = Scr.DefaultColorset;
1422 
1423 	/* make GC's */
1424 	gcm = GCFunction|GCLineWidth|GCForeground|GCBackground;
1425 	gcv.function = GXcopy;
1426 	if (Scr.DefaultFont->font)
1427 	{
1428 		gcm |= GCFont;
1429 		gcv.font = Scr.DefaultFont->font->fid;
1430 	}
1431 	gcv.line_width = 0;
1432 	if (cset >= 0)
1433 	{
1434 		gcv.foreground = Colorset[cset].fg;
1435 		gcv.background = Colorset[cset].bg;
1436 	}
1437 	else
1438 	{
1439 		gcv.foreground = Scr.StdFore;
1440 		gcv.background = Scr.StdBack;
1441 	}
1442 	if (Scr.StdGC)
1443 	{
1444 		XChangeGC(dpy, Scr.StdGC, gcm, &gcv);
1445 	}
1446 	else
1447 	{
1448 		Scr.StdGC = fvwmlib_XCreateGC(dpy, Scr.NoFocusWin, gcm, &gcv);
1449 	}
1450 
1451 	gcm = GCFunction|GCLineWidth|GCForeground;
1452 	if (cset >= 0)
1453 	{
1454 		gcv.foreground = Colorset[cset].hilite;
1455 	}
1456 	else
1457 	{
1458 		gcv.foreground = Scr.StdHilite;
1459 	}
1460 	if (Scr.StdReliefGC)
1461 	{
1462 		XChangeGC(dpy, Scr.StdReliefGC, gcm, &gcv);
1463 	}
1464 	else
1465 	{
1466 		Scr.StdReliefGC = fvwmlib_XCreateGC(
1467 			dpy, Scr.NoFocusWin, gcm, &gcv);
1468 	}
1469 	if (cset >= 0)
1470 	{
1471 		gcv.foreground = Colorset[cset].shadow;
1472 	}
1473 	else
1474 	{
1475 		gcv.foreground = Scr.StdShadow;
1476 	}
1477 	if (Scr.StdShadowGC)
1478 	{
1479 		XChangeGC(dpy, Scr.StdShadowGC, gcm, &gcv);
1480 	}
1481 	else
1482 	{
1483 		Scr.StdShadowGC = fvwmlib_XCreateGC(
1484 			dpy, Scr.NoFocusWin, gcm, &gcv);
1485 	}
1486 	/* update the geometry window for move/resize */
1487 	if (Scr.SizeWindow.win != None)
1488 	{
1489 		resize_geometry_window();
1490 	}
1491 	UpdateAllMenuStyles();
1492 
1493 	return;
1494 }
1495 
FreeDecorFace(Display * dpy,DecorFace * df)1496 void FreeDecorFace(Display *dpy, DecorFace *df)
1497 {
1498 	int i;
1499 
1500 	switch (DFS_FACE_TYPE(df->style))
1501 	{
1502 	case GradientButton:
1503 		if (df->u.grad.d_pixels != NULL && df->u.grad.d_npixels)
1504 		{
1505 			PictureFreeColors(
1506 				dpy, Pcmap, df->u.grad.d_pixels,
1507 				df->u.grad.d_npixels, 0, False);
1508 			free(df->u.grad.d_pixels);
1509 		}
1510 		else if (Pdepth <= 8 && df->u.grad.xcs != NULL &&
1511 			 df->u.grad.npixels > 0 && !df->u.grad.do_dither)
1512 		{
1513 			Pixel *p;
1514 			int i;
1515 
1516 			p = fxmalloc(df->u.grad.npixels * sizeof(Pixel));
1517 			for(i=0; i < df->u.grad.npixels; i++)
1518 			{
1519 				p[i] = df->u.grad.xcs[i].pixel;
1520 			}
1521 			PictureFreeColors(
1522 				dpy, Pcmap, p, df->u.grad.npixels, 0, False);
1523 			free(p);
1524 		}
1525 		if (df->u.grad.xcs != NULL)
1526 		{
1527 			free(df->u.grad.xcs);
1528 		}
1529 		break;
1530 
1531 	case PixmapButton:
1532 	case TiledPixmapButton:
1533 	case StretchedPixmapButton:
1534 	case AdjustedPixmapButton:
1535 	case ShrunkPixmapButton:
1536 		if (df->u.p)
1537 		{
1538 			PDestroyFvwmPicture(dpy, df->u.p);
1539 		}
1540 		break;
1541 
1542 	case MultiPixmap:
1543 		if (df->u.mp.pixmaps)
1544 		{
1545 			for (i = 0; i < TBMP_NUM_PIXMAPS; i++)
1546 			{
1547 				if (df->u.mp.pixmaps[i])
1548 				{
1549 					PDestroyFvwmPicture(
1550 						dpy, df->u.mp.pixmaps[i]);
1551 				}
1552 				else if (!!(df->u.mp.solid_flags & i))
1553 				{
1554 					PictureFreeColors(
1555 						dpy, Pcmap, &df->u.mp.pixels[i],
1556 						1, 0, False);
1557 				}
1558 			}
1559 			free(df->u.mp.pixmaps);
1560 		}
1561 		if (df->u.mp.acs)
1562 		{
1563 			free(df->u.mp.acs);
1564 		}
1565 		if (df->u.mp.pixels)
1566 		{
1567 			free(df->u.mp.pixels);
1568 		}
1569 		break;
1570 	case VectorButton:
1571 	case DefaultVectorButton:
1572 		if (df->u.vector.x)
1573 		{
1574 			free (df->u.vector.x);
1575 		}
1576 		if (df->u.vector.y)
1577 		{
1578 			free (df->u.vector.y);
1579 		}
1580 		/* free offsets for coord */
1581 		if (df->u.vector.xoff)
1582 		{
1583 			free(df->u.vector.xoff);
1584 		}
1585 		if (df->u.vector.yoff)
1586 		{
1587 			free(df->u.vector.yoff);
1588 		}
1589 		if (df->u.vector.c)
1590 		{
1591 			free (df->u.vector.c);
1592 		}
1593 		break;
1594 	default:
1595 		/* see below */
1596 		break;
1597 	}
1598 	/* delete any compound styles */
1599 	if (df->next)
1600 	{
1601 		FreeDecorFace(dpy, df->next);
1602 		free(df->next);
1603 	}
1604 	df->next = NULL;
1605 	memset(&df->style, 0, sizeof(df->style));
1606 	memset(&df->u, 0, sizeof(df->u));
1607 	DFS_FACE_TYPE(df->style) = SimpleButton;
1608 
1609 	return;
1610 }
1611 
1612 /*
1613  *
1614  * Reads a button face line into a structure (veliaa@rpi.edu)
1615  *
1616  */
ReadDecorFace(char * s,DecorFace * df,int button,int verbose)1617 Bool ReadDecorFace(char *s, DecorFace *df, int button, int verbose)
1618 {
1619 	int offset;
1620 	char style[256], *file;
1621 	char *action = s;
1622 
1623 	/* some variants of scanf do not increase the assign count when %n is
1624 	 * used, so a return value of 1 is no error. */
1625 	if (sscanf(s, "%255s%n", style, &offset) < 1)
1626 	{
1627 		if (verbose)
1628 		{
1629 			fvwm_debug(__func__, "error in face `%s'", s);
1630 		}
1631 		return False;
1632 	}
1633 	style[255] = 0;
1634 
1635 	if (strncasecmp(style, "--", 2) != 0)
1636 	{
1637 		s += offset;
1638 
1639 		FreeDecorFace(dpy, df);
1640 
1641 		/* determine button style */
1642 		if (strncasecmp(style,"Simple",6)==0)
1643 		{
1644 			memset(&df->style, 0, sizeof(df->style));
1645 			DFS_FACE_TYPE(df->style) = SimpleButton;
1646 		}
1647 		else if (strncasecmp(style,"Default",7)==0)
1648 		{
1649 			int b = -1, n = sscanf(s, "%d%n", &b, &offset);
1650 
1651 			if (n < 1)
1652 			{
1653 				if (button == -1)
1654 				{
1655 					if (verbose)
1656 					{
1657 						fvwm_debug(__func__,
1658 							   "need default button"
1659 							   " number to load");
1660 					}
1661 					return False;
1662 				}
1663 				b = button;
1664 			}
1665 			else
1666 			{
1667 				b = BUTTON_INDEX(b);
1668 				s += offset;
1669 			}
1670 			if (b >= 0 && b < NUMBER_OF_TITLE_BUTTONS)
1671 			{
1672 				LoadDefaultButton(df, b);
1673 			}
1674 			else
1675 			{
1676 				if (verbose)
1677 				{
1678 					fvwm_debug(__func__,
1679 						   "button number out of range:"
1680 						   " %d", b);
1681 				}
1682 				return False;
1683 			}
1684 		}
1685 		else if (strncasecmp(style,"Vector",6)==0 ||
1686 			 (strlen(style)<=2 && isdigit(*style)))
1687 		{
1688 			/* normal coordinate list button style */
1689 			int i, num_coords, num;
1690 			struct vector_coords *vc = &df->u.vector;
1691 
1692 			/* get number of points */
1693 			if (strncasecmp(style,"Vector",6)==0)
1694 			{
1695 				num = sscanf(s,"%d%n",&num_coords,&offset);
1696 				s += offset;
1697 			}
1698 			else
1699 			{
1700 				num = sscanf(style,"%d",&num_coords);
1701 			}
1702 
1703 			if (num < 1 || num_coords<2 ||
1704 			    num_coords > MAX_TITLE_BUTTON_VECTOR_LINES)
1705 			{
1706 				if (verbose)
1707 				{
1708 					fvwm_debug(__func__,
1709 						   "Bad button style (2) in line:"
1710 						   " %s",action);
1711 				}
1712 				return False;
1713 			}
1714 
1715 			vc->num = num_coords;
1716 			vc->use_fgbg = 0;
1717 			vc->x = fxmalloc(sizeof(char) * num_coords);
1718 			vc->y = fxmalloc(sizeof(char) * num_coords);
1719 			vc->xoff = fxmalloc(sizeof(char) * num_coords);
1720 			vc->yoff = fxmalloc(sizeof(char) * num_coords);
1721 			vc->c = fxmalloc(sizeof(char) * num_coords);
1722 
1723 			/* get the points */
1724 			for (i = 0; i < vc->num; ++i)
1725 			{
1726 				int x;
1727 				int y;
1728 				int xoff = 0;
1729 				int yoff = 0;
1730 				int c;
1731 
1732 				if (__parse_vector_line(
1733 					    &s, &x, &y, &xoff, &yoff, &c, s) ==
1734 				    False)
1735 				{
1736 					break;
1737 				}
1738 				if (x < 0)
1739 				{
1740 					x = 0;
1741 				}
1742 				if (x > 100)
1743 				{
1744 					x = 100;
1745 				}
1746 				if (y < 0)
1747 				{
1748 					y = 0;
1749 				}
1750 				if (y > 100)
1751 				{
1752 					y = 100;
1753 				}
1754 				if (c < 0 || c > 4)
1755 				{
1756 					c = 4;
1757 				}
1758 				vc->x[i] = x;
1759 				vc->y[i] = y;
1760 				vc->c[i] = c;
1761 				vc->xoff[i] = xoff;
1762 				vc->yoff[i] = yoff;
1763 				if (c == 2 || c == 3)
1764 				{
1765 					vc->use_fgbg = 1;
1766 				}
1767 			}
1768 			if (i < vc->num)
1769 			{
1770 				if (verbose)
1771 				{
1772 					fvwm_debug(__func__,
1773 						   "Bad button style (3) in line"
1774 						   " %s", action);
1775 				}
1776 				free(vc->x);
1777 				free(vc->y);
1778 				free(vc->c);
1779 				free(vc->xoff);
1780 				free(vc->yoff);
1781 				vc->x = NULL;
1782 				vc->y = NULL;
1783 				vc->c = NULL;
1784 				vc->xoff = NULL;
1785 				vc->yoff = NULL;
1786 				return False;
1787 			}
1788 			memset(&df->style, 0, sizeof(df->style));
1789 			DFS_FACE_TYPE(df->style) = VectorButton;
1790 		}
1791 		else if (strncasecmp(style,"Solid",5)==0)
1792 		{
1793 			s = GetNextToken(s, &file);
1794 			if (file)
1795 			{
1796 				memset(&df->style, 0, sizeof(df->style));
1797 				DFS_FACE_TYPE(df->style) = SolidButton;
1798 				df->u.back = GetColor(file);
1799 				free(file);
1800 			}
1801 			else
1802 			{
1803 				if (verbose)
1804 				{
1805 					fvwm_debug(__func__,
1806 						   "no color given for Solid"
1807 						   " face type: %s", action);
1808 				}
1809 				return False;
1810 			}
1811 		}
1812 		else if (strncasecmp(style+1, "Gradient", 8)==0)
1813 		{
1814 			char **s_colors;
1815 			int npixels, nsegs, *perc;
1816 			XColor *xcs;
1817 			Bool do_dither = False;
1818 
1819 			if (!IsGradientTypeSupported(style[0]))
1820 			{
1821 				return False;
1822 			}
1823 			/* translate the gradient string into an array of
1824 			 * colors etc */
1825 			npixels = ParseGradient(
1826 				s, &s, &s_colors, &perc, &nsegs);
1827 			while (*s && isspace(*s))
1828 			{
1829 				s++;
1830 			}
1831 			if (npixels <= 0)
1832 			{
1833 				return False;
1834 			}
1835 			/* grab the colors */
1836 			if (Pdepth <= 16)
1837 			{
1838 				do_dither = True;
1839 			}
1840 			xcs = AllocAllGradientColors(
1841 				s_colors, perc, nsegs, npixels, do_dither);
1842 			if (xcs == None)
1843 				return False;
1844 			df->u.grad.xcs = xcs;
1845 			df->u.grad.npixels = npixels;
1846 			df->u.grad.do_dither = do_dither;
1847 			df->u.grad.d_pixels = NULL;
1848 			memset(&df->style, 0, sizeof(df->style));
1849 			DFS_FACE_TYPE(df->style) = GradientButton;
1850 			df->u.grad.gradient_type = toupper(style[0]);
1851 		}
1852 		else if (strncasecmp(style,"Pixmap",6)==0
1853 			 || strncasecmp(style,"TiledPixmap",11)==0
1854 			 || strncasecmp(style,"StretchedPixmap",15)==0
1855 			 || strncasecmp(style,"AdjustedPixmap",14)==0
1856 			 || strncasecmp(style,"ShrunkPixmap",12)==0)
1857 		{
1858 			FvwmPictureAttributes fpa;
1859 
1860 			s = GetNextToken(s, &file);
1861 			fpa.mask = (Pdepth <= 8)? FPAM_DITHER:0; /* ? */
1862 			df->u.p = PCacheFvwmPicture(
1863 				dpy, Scr.NoFocusWin, NULL, file, fpa);
1864 			if (df->u.p == NULL)
1865 			{
1866 				if (file)
1867 				{
1868 					if (verbose)
1869 					{
1870 						fvwm_debug(__func__,
1871 							   "couldn't load pixmap"
1872 							   " %s", file);
1873 					}
1874 					free(file);
1875 				}
1876 				return False;
1877 			}
1878 			if (file)
1879 			{
1880 				free(file);
1881 				file = NULL;
1882 			}
1883 
1884 			memset(&df->style, 0, sizeof(df->style));
1885 			if (strncasecmp(style,"Tiled",5)==0)
1886 			{
1887 				DFS_FACE_TYPE(df->style) = TiledPixmapButton;
1888 			}
1889 			else if (strncasecmp(style,"Stretched",9)==0)
1890 			{
1891 				DFS_FACE_TYPE(df->style) =
1892 					StretchedPixmapButton;
1893 			}
1894 			else if (strncasecmp(style,"Adjusted",8)==0)
1895 			{
1896 				DFS_FACE_TYPE(df->style) =
1897 					AdjustedPixmapButton;
1898 			}
1899 			else if (strncasecmp(style,"Shrunk",6)==0)
1900 			{
1901 				DFS_FACE_TYPE(df->style) =
1902 					ShrunkPixmapButton;
1903 			}
1904 			else
1905 			{
1906 				DFS_FACE_TYPE(df->style) = PixmapButton;
1907 			}
1908 		}
1909 		else if (strncasecmp(style,"MultiPixmap",11)==0)
1910 		{
1911 			if (button != -1)
1912 			{
1913 				if (verbose)
1914 				{
1915 					fvwm_debug(__func__,
1916 						   "MultiPixmap is only valid"
1917 						   " for TitleStyle");
1918 				}
1919 				return False;
1920 			}
1921 			s = ReadMultiPixmapDecor(s, df);
1922 			if (!s)
1923 			{
1924 				return False;
1925 			}
1926 		}
1927 		else if (FMiniIconsSupported &&
1928 			 strncasecmp (style, "MiniIcon", 8) == 0)
1929 		{
1930 			memset(&df->style, 0, sizeof(df->style));
1931 			DFS_FACE_TYPE(df->style) = MiniIconButton;
1932 			/* pixmap read in when the window is created */
1933 			df->u.p = NULL;
1934 		}
1935 		else if (strncasecmp (style, "Colorset", 8) == 0)
1936 		{
1937 			int val[2];
1938 			int n;
1939 
1940 			n = GetIntegerArguments(s, NULL, val, 2);
1941 			if (n == 0)
1942 			{
1943 			}
1944 			memset(&df->style, 0, sizeof(df->style));
1945 			if (n > 0 && val[0] >= 0)
1946 			{
1947 
1948 				df->u.acs.cs = val[0];
1949 				alloc_colorset(val[0]);
1950 				DFS_FACE_TYPE(df->style) = ColorsetButton;
1951 			}
1952 			df->u.acs.alpha_percent = 100;
1953 			if (n > 1)
1954 			{
1955 				df->u.acs.alpha_percent =
1956 					max(0, min(100,val[1]));
1957 			}
1958 			s = SkipNTokens(s, n);
1959 		}
1960 		else
1961 		{
1962 			if (verbose)
1963 			{
1964 				fvwm_debug(__func__,
1965 					   "unknown style %s: %s", style,
1966 					   action);
1967 			}
1968 			return False;
1969 		}
1970 	}
1971 
1972 	/* Process button flags ("--" signals start of flags,
1973 	   it is also checked for above) */
1974 	s = GetNextToken(s, &file);
1975 	if (file && (strcmp(file,"--")==0))
1976 	{
1977 		char *tok;
1978 		s = GetNextToken(s, &tok);
1979 		while (tok && *tok)
1980 		{
1981 			int set = 1;
1982 			char *old_tok = NULL;
1983 
1984 			if (*tok == '!')
1985 			{ /* flag negate */
1986 				set = 0;
1987 				old_tok = tok;
1988 				tok++;
1989 			}
1990 			if (StrEquals(tok,"Clear"))
1991 			{
1992 				memset(&DFS_FLAGS(df->style), (set) ? 0 : 0xff,
1993 				       sizeof(DFS_FLAGS(df->style)));
1994 				/* ? what is set == 0 good for ? */
1995 			}
1996 			else if (StrEquals(tok,"Left"))
1997 			{
1998 				if (set)
1999 				{
2000 					DFS_H_JUSTIFICATION(df->style) =
2001 						JUST_LEFT;
2002 				}
2003 				else
2004 				{
2005 					DFS_H_JUSTIFICATION(df->style) =
2006 						JUST_RIGHT;
2007 				}
2008 			}
2009 			else if (StrEquals(tok,"Right"))
2010 			{
2011 				if (set)
2012 				{
2013 					DFS_H_JUSTIFICATION(df->style) =
2014 						JUST_RIGHT;
2015 				}
2016 				else
2017 				{
2018 					DFS_H_JUSTIFICATION(df->style) =
2019 						JUST_LEFT;
2020 				}
2021 			}
2022 			else if (StrEquals(tok,"Centered"))
2023 			{
2024 				DFS_H_JUSTIFICATION(df->style) = JUST_CENTER;
2025 				DFS_V_JUSTIFICATION(df->style) = JUST_CENTER;
2026 			}
2027 			else if (StrEquals(tok,"Top"))
2028 			{
2029 				if (set)
2030 				{
2031 					DFS_V_JUSTIFICATION(df->style) =
2032 						JUST_TOP;
2033 				}
2034 				else
2035 				{
2036 					DFS_V_JUSTIFICATION(df->style) =
2037 						JUST_BOTTOM;
2038 				}
2039 			}
2040 			else if (StrEquals(tok,"Bottom"))
2041 			{
2042 				if (set)
2043 				{
2044 					DFS_V_JUSTIFICATION(df->style) =
2045 						JUST_BOTTOM;
2046 				}
2047 				else
2048 				{
2049 					DFS_V_JUSTIFICATION(df->style) =
2050 						JUST_TOP;
2051 				}
2052 			}
2053 			else if (StrEquals(tok,"Flat"))
2054 			{
2055 				if (set)
2056 				{
2057 					DFS_BUTTON_RELIEF(df->style) =
2058 						DFS_BUTTON_IS_FLAT;
2059 				}
2060 				else if (DFS_BUTTON_RELIEF(df->style) ==
2061 					 DFS_BUTTON_IS_FLAT)
2062 				{
2063 					DFS_BUTTON_RELIEF(df->style) =
2064 						DFS_BUTTON_IS_UP;
2065 				}
2066 			}
2067 			else if (StrEquals(tok,"Sunk"))
2068 			{
2069 				if (set)
2070 				{
2071 					DFS_BUTTON_RELIEF(df->style) =
2072 						DFS_BUTTON_IS_SUNK;
2073 				}
2074 				else if (DFS_BUTTON_RELIEF(df->style) ==
2075 					 DFS_BUTTON_IS_SUNK)
2076 				{
2077 					DFS_BUTTON_RELIEF(df->style) =
2078 						DFS_BUTTON_IS_UP;
2079 				}
2080 			}
2081 			else if (StrEquals(tok,"Raised"))
2082 			{
2083 				if (set)
2084 				{
2085 					DFS_BUTTON_RELIEF(df->style) =
2086 						DFS_BUTTON_IS_UP;
2087 				}
2088 				else
2089 				{
2090 					DFS_BUTTON_RELIEF(df->style) =
2091 						DFS_BUTTON_IS_SUNK;
2092 				}
2093 			}
2094 			else if (StrEquals(tok,"UseTitleStyle"))
2095 			{
2096 				if (set)
2097 				{
2098 					DFS_USE_TITLE_STYLE(df->style) = 1;
2099 					DFS_USE_BORDER_STYLE(df->style) = 0;
2100 				}
2101 				else
2102 					DFS_USE_TITLE_STYLE(df->style) = 0;
2103 			}
2104 			else if (StrEquals(tok,"HiddenHandles"))
2105 			{
2106 				DFS_HAS_HIDDEN_HANDLES(df->style) = !!set;
2107 			}
2108 			else if (StrEquals(tok,"NoInset"))
2109 			{
2110 				DFS_HAS_NO_INSET(df->style) = !!set;
2111 			}
2112 			else if (StrEquals(tok,"UseBorderStyle"))
2113 			{
2114 				if (set)
2115 				{
2116 					DFS_USE_BORDER_STYLE(df->style) = 1;
2117 					DFS_USE_TITLE_STYLE(df->style) = 0;
2118 				}
2119 				else
2120 				{
2121 					DFS_USE_BORDER_STYLE(df->style) = 0;
2122 				}
2123 			}
2124 			else if (verbose)
2125 			{
2126 				fvwm_debug(__func__,
2127 					   "unknown button face flag '%s'"
2128 					   " -- line: %s", tok, action);
2129 			}
2130 			if (set)
2131 			{
2132 				free(tok);
2133 			}
2134 			else
2135 			{
2136 				free(old_tok);
2137 			}
2138 			s = GetNextToken(s, &tok);
2139 		}
2140 	}
2141 	if (file)
2142 	{
2143 		free(file);
2144 	}
2145 
2146 	return True;
2147 }
2148 
2149 /*
2150  *
2151  * Diverts a style definition to an FvwmDecor structure (veliaa@rpi.edu)
2152  *
2153  */
AddToDecor(F_CMD_ARGS,FvwmDecor * decor)2154 void AddToDecor(F_CMD_ARGS, FvwmDecor *decor)
2155 {
2156 	if (!action)
2157 	{
2158 		return;
2159 	}
2160 	while (*action && isspace((unsigned char)*action))
2161 	{
2162 		++action;
2163 	}
2164 	if (!*action)
2165 	{
2166 		return;
2167 	}
2168 	Scr.cur_decor = decor;
2169 	execute_function(cond_rc, exc, action, 0);
2170 	Scr.cur_decor = NULL;
2171 
2172 	return;
2173 }
2174 
2175 /*
2176  *
2177  *  InitFvwmDecor -- initializes an FvwmDecor structure to defaults
2178  *
2179  */
InitFvwmDecor(FvwmDecor * decor)2180 void InitFvwmDecor(FvwmDecor *decor)
2181 {
2182 	int i;
2183 	DecorFace tmpdf;
2184 
2185 	/* zero out the structures */
2186 	memset(decor, 0, sizeof (FvwmDecor));
2187 	memset(&tmpdf, 0, sizeof(DecorFace));
2188 
2189 	/* initialize title-bar button styles */
2190 	DFS_FACE_TYPE(tmpdf.style) = SimpleButton;
2191 	for (i = 0; i < NUMBER_OF_TITLE_BUTTONS; ++i)
2192 	{
2193 		int j = 0;
2194 		for (; j < BS_MaxButtonState; ++j)
2195 		{
2196 			TB_STATE(decor->buttons[i])[j] = tmpdf;
2197 		}
2198 	}
2199 	/* reset to default button set */
2200 	ResetAllButtons(decor);
2201 	/* initialize title-bar styles */
2202 	for (i = 0; i < BS_MaxButtonState; ++i)
2203 	{
2204 		DFS_FACE_TYPE(
2205 			TB_STATE(decor->titlebar)[i].style) = SimpleButton;
2206 	}
2207 
2208 	/* initialize border texture styles */
2209 	DFS_FACE_TYPE(decor->BorderStyle.active.style) = SimpleButton;
2210 	DFS_FACE_TYPE(decor->BorderStyle.inactive.style) = SimpleButton;
2211 
2212 	return;
2213 }
2214 
reset_decor_changes(void)2215 void reset_decor_changes(void)
2216 {
2217 	FvwmDecor *decor;
2218 	for (decor = &Scr.DefaultDecor; decor; decor = decor->next)
2219 	{
2220 		decor->flags.has_changed = 0;
2221 		decor->flags.has_title_height_changed = 0;
2222 	}
2223 	/* todo: must reset individual change flags too */
2224 
2225 	return;
2226 }
2227 
update_fvwm_colorset(int cset)2228 void update_fvwm_colorset(int cset)
2229 {
2230 	if (cset == Scr.DefaultColorset)
2231 	{
2232 		Scr.flags.do_need_window_update = 1;
2233 		Scr.flags.has_default_color_changed = 1;
2234 	}
2235 	UpdateMenuColorset(cset);
2236 	update_style_colorset(cset);
2237 	update_decors_colorset(cset);
2238 
2239 	return;
2240 }
2241 
2242 /* ---------------------------- builtin commands --------------------------- */
2243 
CMD_Status(F_CMD_ARGS)2244 void CMD_Status(F_CMD_ARGS)
2245 {
2246 	if ((strcasecmp(action, "on") == 0) && status_fp == NULL) {
2247 		status_init_pipe();
2248 	} else if (strcasecmp(action, "off") == 0) {
2249 		if (status_fp != NULL) {
2250 			fclose(status_fp);
2251 			status_fp = NULL;
2252 			fvwm_debug(__func__, "Closed pipe for status");
2253 		}
2254 		return;
2255 	} else {
2256 		fvwm_debug(__func__, "unknown option: %s", action);
2257 		return;
2258 	}
2259 
2260 	status_send();
2261 }
2262 
CMD_Beep(F_CMD_ARGS)2263 void CMD_Beep(F_CMD_ARGS)
2264 {
2265 	XBell(dpy, 0);
2266 
2267 	return;
2268 }
2269 
CMD_Nop(F_CMD_ARGS)2270 void CMD_Nop(F_CMD_ARGS)
2271 {
2272 	return;
2273 }
2274 
CMD_EscapeFunc(F_CMD_ARGS)2275 void CMD_EscapeFunc(F_CMD_ARGS)
2276 {
2277 	return;
2278 }
2279 
CMD_CursorMove(F_CMD_ARGS)2280 void CMD_CursorMove(F_CMD_ARGS)
2281 {
2282 	int x = 0, y = 0;
2283 	int val1, val2, val1_unit, val2_unit;
2284 	int x_unit, y_unit;
2285 	int virtual_x, virtual_y;
2286 	int x_pages, y_pages;
2287 	struct monitor	*m = NULL;
2288 
2289 	if (GetTwoArguments(action, &val1, &val2, &val1_unit, &val2_unit) != 2)
2290 	{
2291 		fvwm_debug(__func__, "CursorMove needs 2 arguments");
2292 		return;
2293 	}
2294 	if (FQueryPointer(dpy, Scr.Root, &JunkRoot, &JunkChild,
2295 			  &x, &y, &JunkX, &JunkY, &JunkMask) == False)
2296 	{
2297 		/* pointer is on a different screen */
2298 		return;
2299 	}
2300 
2301 	m = monitor_get_current();
2302 
2303 	x_unit = val1 * val1_unit / 100;
2304 	y_unit = val2 * val2_unit / 100;
2305 
2306 	x += x_unit;
2307 	y += y_unit;
2308 
2309 	virtual_x = m->virtual_scr.Vx;
2310 	virtual_y = m->virtual_scr.Vy;
2311 	if (x >= 0)
2312 	{
2313 		x_pages = x / monitor_get_all_widths();
2314 	}
2315 	else
2316 	{
2317 		x_pages = ((x + 1) / monitor_get_all_widths()) - 1;
2318 	}
2319 	virtual_x += x_pages * monitor_get_all_widths();
2320 	x -= x_pages * monitor_get_all_widths();
2321 	if (virtual_x < 0)
2322 	{
2323 		x += virtual_x;
2324 		virtual_x = 0;
2325 	}
2326 	else if (virtual_x > m->virtual_scr.VxMax)
2327 	{
2328 		x += virtual_x - m->virtual_scr.VxMax;
2329 		virtual_x = m->virtual_scr.VxMax;
2330 	}
2331 
2332 	if (y >= 0)
2333 	{
2334 		y_pages = y / monitor_get_all_heights();
2335 	}
2336 	else
2337 	{
2338 		y_pages = ((y + 1) / monitor_get_all_heights()) - 1;
2339 	}
2340 	virtual_y += y_pages > monitor_get_all_heights();
2341 	y -= y_pages * monitor_get_all_heights();
2342 
2343 	if (virtual_y < 0)
2344 	{
2345 		y += virtual_y;
2346 		virtual_y = 0;
2347 	}
2348 	else if (virtual_y > m->virtual_scr.VyMax)
2349 	{
2350 		y += virtual_y - m->virtual_scr.VyMax;
2351 		virtual_y = m->virtual_scr.VyMax;
2352 	}
2353 
2354 	/* TA:  (2010/12/19):  Only move to the new page if scrolling is
2355 	 * enabled and the viewport is able to change based on where the
2356 	 * pointer is.
2357 	 */
2358 	if ((virtual_x != m->virtual_scr.Vx && m->virtual_scr.EdgeScrollX != 0) ||
2359 	    (virtual_y != m->virtual_scr.Vy && m->virtual_scr.EdgeScrollY != 0))
2360 	{
2361 		MoveViewport(m, virtual_x, virtual_y, True);
2362 	}
2363 
2364 	/* TA:  (2010/12/19):  If the cursor is about to enter a pan-window, or
2365 	 * is one, or the cursor's next step is to go beyond the page
2366 	 * boundary, stop the cursor from moving in that direction, *if* we've
2367 	 * disallowed edge scrolling.
2368 	 *
2369 	 * Whilst this stops the cursor short of the edge of the screen in a
2370 	 * given direction, this is the desired behaviour.
2371 	 */
2372 	if (m->virtual_scr.EdgeScrollX == 0 && (x >= monitor_get_all_widths() ||
2373 						x + x_unit >= monitor_get_all_widths()))
2374 		return;
2375 
2376 	if (m->virtual_scr.EdgeScrollY == 0 && (y >= monitor_get_all_heights() ||
2377 						y + y_unit >= monitor_get_all_heights()))
2378 		return;
2379 
2380 	FWarpPointerUpdateEvpos(
2381 		exc->x.elast, dpy, None, Scr.Root, 0, 0,
2382 		monitor_get_all_widths(),
2383 		monitor_get_all_heights(), x, y);
2384 
2385 	return;
2386 }
2387 
CMD_Delete(F_CMD_ARGS)2388 void CMD_Delete(F_CMD_ARGS)
2389 {
2390 	FvwmWindow * const fw = exc->w.fw;
2391 
2392 	if (!is_function_allowed(F_DELETE, NULL, fw, RQORIG_PROGRAM_US, True))
2393 	{
2394 		XBell(dpy, 0);
2395 
2396 		return;
2397 	}
2398 	if (IS_TEAR_OFF_MENU(fw))
2399 	{
2400 		/* 'soft' delete tear off menus.  Note: we can't send the
2401 		 * message to the menu window directly because it was created
2402 		 * using a different display.  The client message would never
2403 		 * be read from there. */
2404 		send_clientmessage(
2405 			dpy, FW_W_PARENT(fw), _XA_WM_DELETE_WINDOW,
2406 			CurrentTime);
2407 
2408 		return;
2409 	}
2410 	if (WM_DELETES_WINDOW(fw))
2411 	{
2412 		send_clientmessage(
2413 			dpy, FW_W(fw), _XA_WM_DELETE_WINDOW, CurrentTime);
2414 
2415 		return;
2416 	}
2417 	else
2418 	{
2419 		XBell(dpy, 0);
2420 	}
2421 	XFlush(dpy);
2422 
2423 	return;
2424 }
2425 
CMD_Destroy(F_CMD_ARGS)2426 void CMD_Destroy(F_CMD_ARGS)
2427 {
2428 	FvwmWindow * const fw = exc->w.fw;
2429 
2430 	if (IS_TEAR_OFF_MENU(fw))
2431 	{
2432 		CMD_Delete(F_PASS_ARGS);
2433 		return;
2434 	}
2435 	if (!is_function_allowed(F_DESTROY, NULL, fw, True, True))
2436 	{
2437 		XBell(dpy, 0);
2438 		return;
2439 	}
2440 	if (
2441 		XGetGeometry(
2442 			dpy, FW_W(fw), &JunkRoot, &JunkX, &JunkY,
2443 			(unsigned int*)&JunkWidth, (unsigned int*)&JunkHeight,
2444 			(unsigned int*)&JunkBW, (unsigned int*)&JunkDepth)
2445 		!= 0)
2446 	{
2447 		XKillClient(dpy, FW_W(fw));
2448 	}
2449 	destroy_window(fw);
2450 	XFlush(dpy);
2451 
2452 	return;
2453 }
2454 
CMD_Close(F_CMD_ARGS)2455 void CMD_Close(F_CMD_ARGS)
2456 {
2457 	FvwmWindow * const fw = exc->w.fw;
2458 
2459 	if (IS_TEAR_OFF_MENU(fw))
2460 	{
2461 		CMD_Delete(F_PASS_ARGS);
2462 		return;
2463 	}
2464 	if (!is_function_allowed(F_CLOSE, NULL, fw, True, True))
2465 	{
2466 		XBell(dpy, 0);
2467 		return;
2468 	}
2469 	if (WM_DELETES_WINDOW(fw))
2470 	{
2471 		send_clientmessage(
2472 			dpy, FW_W(fw), _XA_WM_DELETE_WINDOW, CurrentTime);
2473 		return;
2474 	}
2475 	if (
2476 		XGetGeometry(
2477 			dpy, FW_W(fw), &JunkRoot, &JunkX, &JunkY,
2478 			(unsigned int*)&JunkWidth, (unsigned int*)&JunkHeight,
2479 			(unsigned int*)&JunkBW, (unsigned int*)&JunkDepth)
2480 		!= 0)
2481 	{
2482 		XKillClient(dpy, FW_W(fw));
2483 	}
2484 
2485 	destroy_window(fw);
2486 	XFlush(dpy);
2487 
2488 	return;
2489 }
2490 
CMD_Restart(F_CMD_ARGS)2491 void CMD_Restart(F_CMD_ARGS)
2492 {
2493 	Done(1, action);
2494 
2495 	return;
2496 }
2497 
CMD_ExecUseShell(F_CMD_ARGS)2498 void CMD_ExecUseShell(F_CMD_ARGS)
2499 {
2500 	char *arg=NULL;
2501 	static char shell_set = 0;
2502 
2503 	if (shell_set)
2504 	{
2505 		free(exec_shell_name);
2506 	}
2507 	shell_set = 1;
2508 	action = GetNextToken(action,&arg);
2509 	if (arg) /* specific shell was specified */
2510 	{
2511 		exec_shell_name = arg;
2512 	}
2513 	else /* no arg, so use $SHELL -- not working??? */
2514 	{
2515 		if (getenv("SHELL"))
2516 		{
2517 			exec_shell_name = fxstrdup(getenv("SHELL"));
2518 		}
2519 		else
2520 		{
2521 			/* if $SHELL not set, use default */
2522 			exec_shell_name = fxstrdup("/bin/sh");
2523 		}
2524 	}
2525 }
2526 
CMD_Exec(F_CMD_ARGS)2527 void CMD_Exec(F_CMD_ARGS)
2528 {
2529 	char *cmd=NULL;
2530 
2531 	/* if it doesn't already have an 'exec' as the first word, add that
2532 	 * to keep down number of procs started */
2533 	/* need to parse string better to do this right though, so not doing
2534 	 * this for now... */
2535 #if 0
2536 	if (strncasecmp(action,"exec",4)!=0)
2537 	{
2538 		cmd = fxmalloc(strlen(action)+6);
2539 		strcpy(cmd,"exec ");
2540 		strcat(cmd,action);
2541 	}
2542 	else
2543 #endif
2544 	{
2545 		cmd = fxstrdup(action);
2546 	}
2547 	if (!cmd)
2548 	{
2549 		return;
2550 	}
2551 	/* Use to grab the pointer here, but the fork guarantees that
2552 	 * we wont be held up waiting for the function to finish,
2553 	 * so the pointer-gram just caused needless delay and flashing
2554 	 * on the screen */
2555 	/* Thought I'd try vfork and _exit() instead of regular fork().
2556 	 * The man page says that its better. */
2557 	/* Not everyone has vfork! */
2558 	/* According to the man page, vfork should never be used at all.
2559 	 */
2560 
2561 	if (!(fork())) /* child process */
2562 	{
2563 		/* This is for fixing a problem with rox filer */
2564 		int fd;
2565 
2566 		fvmm_deinstall_signals();
2567 		fd = open("/dev/null", O_RDONLY, 0);
2568 		dup2(fd,STDIN_FILENO);
2569 
2570 		if (fd != STDIN_FILENO)
2571 			close(fd);
2572 
2573 		if (fvwm_setpgrp() == -1)
2574 		{
2575 			fvwm_debug(__func__, "setpgrp failed (%s)",
2576 				   strerror(errno));
2577 			exit(100);
2578 		}
2579 		if (execl(exec_shell_name, exec_shell_name, "-c", cmd, NULL) ==
2580 		    -1)
2581 		{
2582 			fvwm_debug(__func__, "execl failed (%s)",
2583 				   strerror(errno));
2584 			exit(100);
2585 		}
2586 	}
2587 	free(cmd);
2588 
2589 	return;
2590 }
2591 
CMD_Refresh(F_CMD_ARGS)2592 void CMD_Refresh(F_CMD_ARGS)
2593 {
2594 	refresh_window(Scr.Root, True);
2595 
2596 	return;
2597 }
2598 
CMD_RefreshWindow(F_CMD_ARGS)2599 void CMD_RefreshWindow(F_CMD_ARGS)
2600 {
2601 	FvwmWindow * const fw = exc->w.fw;
2602 
2603 	refresh_window(
2604 		(exc->w.wcontext == C_ICON) ?
2605 		FW_W_ICON_TITLE(fw) : FW_W_FRAME(fw), True);
2606 
2607 	return;
2608 }
2609 
CMD_Wait(F_CMD_ARGS)2610 void CMD_Wait(F_CMD_ARGS)
2611 {
2612 	Bool done = False;
2613 	Bool redefine_cursor = False;
2614 	Bool is_ungrabbed;
2615 	char *escape;
2616 	Window nonewin = None;
2617 	char *wait_string, *rest;
2618 	FvwmWindow *t;
2619 
2620 	/* try to get a single token */
2621 	rest = GetNextToken(action, &wait_string);
2622 	if (wait_string)
2623 	{
2624 		while (*rest && isspace((unsigned char)*rest))
2625 		{
2626 			rest++;
2627 		}
2628 		if (*rest)
2629 		{
2630 			int i;
2631 			char *temp;
2632 
2633 			/* nope, multiple tokens - try old syntax */
2634 
2635 			/* strip leading and trailing whitespace */
2636 			temp = action;
2637 			while (*temp && isspace((unsigned char)*temp))
2638 			{
2639 				temp++;
2640 			}
2641 			free(wait_string);
2642 			wait_string = fxstrdup(temp);
2643 			for (i = strlen(wait_string) - 1; i >= 0 &&
2644 				     isspace(wait_string[i]); i--)
2645 			{
2646 				wait_string[i] = 0;
2647 			}
2648 		}
2649 	}
2650 	else
2651 	{
2652 		wait_string = fxstrdup("");
2653 	}
2654 
2655 	is_ungrabbed = UngrabEm(GRAB_NORMAL);
2656 	while (!done && !isTerminated)
2657 	{
2658 		XEvent e;
2659 		if (BUSY_WAIT & Scr.BusyCursor)
2660 		{
2661 			XDefineCursor(dpy, Scr.Root, Scr.FvwmCursors[CRS_WAIT]);
2662 			redefine_cursor = True;
2663 		}
2664 		if (My_XNextEvent(dpy, &e))
2665 		{
2666 			dispatch_event(&e);
2667 			if (XFindContext(
2668 				    dpy, e.xmap.window, FvwmContext,
2669 				    (caddr_t *)&t) == XCNOENT)
2670 			{
2671 				t = NULL;
2672 			}
2673 
2674 			if (e.type == MapNotify && e.xmap.event == Scr.Root)
2675 			{
2676 				if (!*wait_string)
2677 				{
2678 					done = True;
2679 				}
2680 				if (t && matchWildcards(
2681 					    wait_string, t->name.name) == True)
2682 				{
2683 					done = True;
2684 				}
2685 				else if (t && t->class.res_class &&
2686 					 matchWildcards(
2687 						 wait_string,
2688 						 t->class.res_class) == True)
2689 				{
2690 					done = True;
2691 				}
2692 				else if (t && t->class.res_name &&
2693 					 matchWildcards(
2694 						 wait_string,
2695 						 t->class.res_name) == True)
2696 				{
2697 					done = True;
2698 				}
2699 			}
2700 			else if (e.type == KeyPress)
2701 			{
2702 				/* should I be using <t> or <exc->w.fw>?
2703 				 * DV: t
2704 				 */
2705 				int context;
2706 				XClassHint *class;
2707 				char *name;
2708 
2709 				context = GetContext(&t, t, &e, &nonewin);
2710 				if (t != NULL)
2711 				{
2712 					class = &(t->class);
2713 					name = t->name.name;
2714 				}
2715 				else
2716 				{
2717 					class = NULL;
2718 					name = NULL;
2719 				}
2720 				escape = CheckBinding(
2721 					Scr.AllBindings,
2722 					e.xkey.keycode, e.xkey.state,
2723 					GetUnusedModifiers(), context,
2724 					BIND_KEYPRESS, class, name);
2725 				if (escape != NULL)
2726 				{
2727 					if (!strcasecmp(escape,"escapefunc"))
2728 					{
2729 						done = True;
2730 					}
2731 				}
2732 			}
2733 		}
2734 	}
2735 	if (redefine_cursor)
2736 	{
2737 		XDefineCursor(dpy, Scr.Root, Scr.FvwmCursors[CRS_ROOT]);
2738 	}
2739 	if (is_ungrabbed)
2740 	{
2741 		GrabEm(CRS_NONE, GRAB_NORMAL);
2742 	}
2743 	free(wait_string);
2744 
2745 	return;
2746 }
2747 
CMD_Quit(F_CMD_ARGS)2748 void CMD_Quit(F_CMD_ARGS)
2749 {
2750 	if (master_pid != getpid())
2751 	{
2752 		kill(master_pid, SIGTERM);
2753 	}
2754 	Done(0,NULL);
2755 
2756 	return;
2757 }
2758 
CMD_QuitScreen(F_CMD_ARGS)2759 void CMD_QuitScreen(F_CMD_ARGS)
2760 {
2761 	Done(0,NULL);
2762 
2763 	return;
2764 }
2765 
CMD_Echo(F_CMD_ARGS)2766 void CMD_Echo(F_CMD_ARGS)
2767 {
2768 	int len;
2769 
2770 	if (!action)
2771 	{
2772 		action = "";
2773 	}
2774 	len = strlen(action);
2775 	if (len != 0)
2776 	{
2777 		if (action[len-1]=='\n')
2778 		{
2779 			action[len-1]='\0';
2780 		}
2781 	}
2782 	BroadcastName(MX_ECHO, -1, -1, -1, action);
2783 	fvwm_debug(__func__, "%s\n", action);
2784 
2785 	return;
2786 }
2787 
CMD_PrintInfo(F_CMD_ARGS)2788 void CMD_PrintInfo(F_CMD_ARGS)
2789 {
2790 	int verbose;
2791 	char *rest, *subject = NULL;
2792 
2793 	rest = GetNextToken(action, &subject);
2794 	if (!rest || GetIntegerArguments(rest, NULL, &verbose, 1) != 1)
2795 	{
2796 		verbose = 0;
2797 	}
2798 	if (StrEquals(subject, "Colors"))
2799 	{
2800 		PicturePrintColorInfo(verbose);
2801 	}
2802 	else if (StrEquals(subject, "Locale"))
2803 	{
2804 		FlocalePrintLocaleInfo(dpy, verbose);
2805 	}
2806 	else if (StrEquals(subject, "NLS"))
2807 	{
2808 		FGettextPrintLocalePath(verbose);
2809 	}
2810 	else if (StrEquals(subject, "style"))
2811 	{
2812 		print_styles(verbose);
2813 	}
2814 	else if (StrEquals(subject, "ImageCache"))
2815 	{
2816 		PicturePrintImageCache(verbose);
2817 	}
2818 	else if (StrEquals(subject, "Bindings"))
2819 	{
2820 		print_bindings();
2821 	}
2822 	else if (StrEquals(subject, "InfoStore"))
2823 	{
2824 		print_infostore();
2825 	}
2826 	else
2827 	{
2828 		fvwm_debug(__func__,
2829 			   "Unknown subject '%s'", action);
2830 	}
2831 	if (subject)
2832 	{
2833 		free(subject);
2834 	}
2835 	return;
2836 }
2837 
CMD_ColormapFocus(F_CMD_ARGS)2838 void CMD_ColormapFocus(F_CMD_ARGS)
2839 {
2840 	if (MatchToken(action,"FollowsFocus"))
2841 	{
2842 		Scr.ColormapFocus = COLORMAP_FOLLOWS_FOCUS;
2843 	}
2844 	else if (MatchToken(action,"FollowsMouse"))
2845 	{
2846 		Scr.ColormapFocus = COLORMAP_FOLLOWS_MOUSE;
2847 	}
2848 	else
2849 	{
2850 		fvwm_debug(__func__,
2851 			   "ColormapFocus requires 1 arg: FollowsFocus or"
2852 			   " FollowsMouse");
2853 		return;
2854 	}
2855 
2856 	return;
2857 }
2858 
CMD_ClickTime(F_CMD_ARGS)2859 void CMD_ClickTime(F_CMD_ARGS)
2860 {
2861 	int val;
2862 
2863 	if (GetIntegerArguments(action, NULL, &val, 1) != 1)
2864 	{
2865 		Scr.ClickTime = DEFAULT_CLICKTIME;
2866 	}
2867 	else
2868 	{
2869 		Scr.ClickTime = (val < 0)? 0 : val;
2870 	}
2871 
2872 	/* Use a negative value during startup and change sign afterwards. This
2873 	 * speeds things up quite a bit. */
2874 	if (fFvwmInStartup)
2875 	{
2876 		Scr.ClickTime = -Scr.ClickTime;
2877 	}
2878 
2879 	return;
2880 }
2881 
2882 
CMD_ImagePath(F_CMD_ARGS)2883 void CMD_ImagePath(F_CMD_ARGS)
2884 {
2885 	PictureSetImagePath( action );
2886 
2887 	return;
2888 }
2889 
CMD_IconPath(F_CMD_ARGS)2890 void CMD_IconPath(F_CMD_ARGS)
2891 {
2892 	fvwm_debug(__func__,
2893 		   "IconPath is deprecated since 2.3.0; use ImagePath instead.");
2894 	obsolete_imagepaths( action );
2895 
2896 	return;
2897 }
2898 
CMD_PixmapPath(F_CMD_ARGS)2899 void CMD_PixmapPath(F_CMD_ARGS)
2900 {
2901 	fvwm_debug(__func__,
2902 		   "PixmapPath is deprecated since 2.3.0; use ImagePath"
2903 		   " instead." );
2904 	obsolete_imagepaths( action );
2905 
2906 	return;
2907 }
2908 
CMD_LocalePath(F_CMD_ARGS)2909 void CMD_LocalePath(F_CMD_ARGS)
2910 {
2911 	FGettextSetLocalePath( action );
2912 
2913 	return;
2914 }
2915 
CMD_ModulePath(F_CMD_ARGS)2916 void CMD_ModulePath(F_CMD_ARGS)
2917 {
2918 	static int need_to_free = 0;
2919 
2920 	setPath( &ModulePath, action, need_to_free );
2921 	need_to_free = 1;
2922 
2923 	return;
2924 }
2925 
CMD_ModuleTimeout(F_CMD_ARGS)2926 void CMD_ModuleTimeout(F_CMD_ARGS)
2927 {
2928 	int timeout;
2929 
2930 	moduleTimeout = DEFAULT_MODULE_TIMEOUT;
2931 	if (GetIntegerArguments(action, NULL, &timeout, 1) == 1 && timeout > 0)
2932 	{
2933 		moduleTimeout = timeout;
2934 	}
2935 
2936 	return;
2937 }
2938 
CMD_HilightColor(F_CMD_ARGS)2939 void CMD_HilightColor(F_CMD_ARGS)
2940 {
2941 	char *fore;
2942 	char *back;
2943 
2944 	if (Scr.cur_decor && Scr.cur_decor != &Scr.DefaultDecor)
2945 	{
2946 		fvwm_debug(__func__,
2947 			   "Decors do not support the HilightColor command"
2948 			   " anymore. Please use"
2949 			   " 'Style <stylename> HilightFore <forecolor>' and"
2950 			   " 'Style <stylename> HilightBack <backcolor>' instead."
2951 			   " Sorry for the inconvenience.");
2952 		return;
2953 	}
2954 	action = GetNextToken(action, &fore);
2955 	GetNextToken(action, &back);
2956 	if (fore && back)
2957 	{
2958 		/* TA:  FIXME:  xasprintf() */
2959 		action = fxmalloc(strlen(fore) + strlen(back) + 29);
2960 		sprintf(action, "* HilightFore %s, HilightBack %s", fore, back);
2961 		CMD_Style(F_PASS_ARGS);
2962 	}
2963 	if (fore)
2964 	{
2965 		free(fore);
2966 	}
2967 	if (back)
2968 	{
2969 		free(back);
2970 	}
2971 
2972 	return;
2973 }
2974 
CMD_HilightColorset(F_CMD_ARGS)2975 void CMD_HilightColorset(F_CMD_ARGS)
2976 {
2977 	char *newaction;
2978 
2979 	if (Scr.cur_decor && Scr.cur_decor != &Scr.DefaultDecor)
2980 	{
2981 		fvwm_debug(__func__,
2982 			   "Decors do not support the HilightColorset command "
2983 			   "anymore. Please use "
2984 			   "'Style <stylename> HilightColorset <colorset>'"
2985 			   " instead. Sorry for the inconvenience.");
2986 		return;
2987 	}
2988 
2989 	if (action)
2990 	{
2991 		/* TA:  FIXME!  xasprintf() */
2992 		newaction = fxmalloc(strlen(action) + 32);
2993 		sprintf(newaction, "* HilightColorset %s", action);
2994 		action = newaction;
2995 		CMD_Style(F_PASS_ARGS);
2996 		free(newaction);
2997 	}
2998 
2999 	return;
3000 }
3001 
CMD_TitleStyle(F_CMD_ARGS)3002 void CMD_TitleStyle(F_CMD_ARGS)
3003 {
3004 	do_title_style(F_PASS_ARGS, False);
3005 
3006 	return;
3007 } /* SetTitleStyle */
3008 
3009 /*
3010  *
3011  * Appends a titlestyle (veliaa@rpi.edu)
3012  *
3013  */
CMD_AddTitleStyle(F_CMD_ARGS)3014 void CMD_AddTitleStyle(F_CMD_ARGS)
3015 {
3016 	do_title_style(F_PASS_ARGS, True);
3017 
3018 	return;
3019 }
3020 
CMD_PropertyChange(F_CMD_ARGS)3021 void CMD_PropertyChange(F_CMD_ARGS)
3022 {
3023 	char string[256];
3024 	char *token;
3025 	char *rest;
3026 	int ret;
3027 	unsigned long argument;
3028 	unsigned long data1;
3029 	unsigned long data2;
3030 
3031 	/* argument */
3032 	token = PeekToken(action, &rest);
3033 	if (token == NULL)
3034 	{
3035 		return;
3036 	}
3037 	ret = sscanf(token, "%lu", &argument);
3038 	if (ret < 1)
3039 	{
3040 		return;
3041 	}
3042 	/* data1 */
3043 	data1 = 0;
3044 	token = PeekToken(rest, &rest);
3045 	if (token != NULL)
3046 	{
3047 		ret = sscanf(token, "%lu", &data1);
3048 		if (ret < 1)
3049 		{
3050 			rest = NULL;
3051 		}
3052 	}
3053 	/* data2 */
3054 	data2 = 0;
3055 	token = PeekToken(rest, &rest);
3056 	if (token != NULL)
3057 	{
3058 		ret = sscanf(token, "%lu", &data2);
3059 		if (ret < 1)
3060 		{
3061 			rest = NULL;
3062 		}
3063 	}
3064 	/* string */
3065 	memset(string, 0, 256);
3066 	if (rest != NULL)
3067 	{
3068 		ret = sscanf(rest, "%255c", &(string[0]));
3069 	}
3070 	BroadcastPropertyChange(argument, data1, data2, string);
3071 
3072 	return;
3073 }
3074 
CMD_DefaultIcon(F_CMD_ARGS)3075 void CMD_DefaultIcon(F_CMD_ARGS)
3076 {
3077 	if (Scr.DefaultIcon)
3078 	{
3079 		free(Scr.DefaultIcon);
3080 	}
3081 	GetNextToken(action, &Scr.DefaultIcon);
3082 
3083 	return;
3084 }
3085 
CMD_DefaultColorset(F_CMD_ARGS)3086 void CMD_DefaultColorset(F_CMD_ARGS)
3087 {
3088 	int cset;
3089 
3090 	if (GetIntegerArguments(action, NULL, &cset, 1) != 1)
3091 	{
3092 		return;
3093 	}
3094 	Scr.DefaultColorset = cset;
3095 	if (Scr.DefaultColorset < 0)
3096 	{
3097 		Scr.DefaultColorset = -1;
3098 	}
3099 	alloc_colorset(Scr.DefaultColorset);
3100 	Scr.flags.do_need_window_update = 1;
3101 	Scr.flags.has_default_color_changed = 1;
3102 
3103 	return;
3104 }
3105 
CMD_DefaultColors(F_CMD_ARGS)3106 void CMD_DefaultColors(F_CMD_ARGS)
3107 {
3108 	char *fore = NULL;
3109 	char *back = NULL;
3110 
3111 	action = GetNextToken(action, &fore);
3112 	if (action)
3113 	{
3114 		action = GetNextToken(action, &back);
3115 	}
3116 	if (!back)
3117 	{
3118 		back = fxstrdup(DEFAULT_BACK_COLOR);
3119 	}
3120 	if (!fore)
3121 	{
3122 		fore = fxstrdup(DEFAULT_FORE_COLOR);
3123 	}
3124 	if (!StrEquals(fore, "-"))
3125 	{
3126 		PictureFreeColors(dpy, Pcmap, &Scr.StdFore, 1, 0, True);
3127 		Scr.StdFore = GetColor(fore);
3128 	}
3129 	if (!StrEquals(back, "-"))
3130 	{
3131 		PictureFreeColors(dpy, Pcmap, &Scr.StdBack, 3, 0, True);
3132 		Scr.StdBack = GetColor(back);
3133 		Scr.StdHilite = GetHilite(Scr.StdBack);
3134 		Scr.StdShadow = GetShadow(Scr.StdBack);
3135 	}
3136 	free(fore);
3137 	free(back);
3138 
3139 	Scr.DefaultColorset = -1;
3140 	Scr.flags.do_need_window_update = 1;
3141 	Scr.flags.has_default_color_changed = 1;
3142 
3143 	return;
3144 }
3145 
CMD_DefaultFont(F_CMD_ARGS)3146 void CMD_DefaultFont(F_CMD_ARGS)
3147 {
3148 	char *font;
3149 	FlocaleFont *new_font;
3150 	FvwmWindow *t;
3151 
3152 	font = PeekToken(action, &action);
3153 	if (!font)
3154 	{
3155 		/* Try 'fixed', pass NULL font name */
3156 	}
3157 	if (!(new_font = FlocaleLoadFont(dpy, font, "fvwm")))
3158 	{
3159 		if (Scr.DefaultFont == NULL)
3160 		{
3161 			exit(1);
3162 		}
3163 		else
3164 		{
3165 			return;
3166 		}
3167 	}
3168 	FlocaleUnloadFont(dpy, Scr.DefaultFont);
3169 	Scr.DefaultFont = new_font;
3170 	/* we should do that here because a redraw can happen before
3171 	   flush_window_updates is called ... */
3172 	for (t = Scr.FvwmRoot.next; t != NULL; t = t->next)
3173 	{
3174 		if (USING_DEFAULT_ICON_FONT(t))
3175 		{
3176 			t->icon_font = Scr.DefaultFont;
3177 		}
3178 		if (USING_DEFAULT_WINDOW_FONT(t))
3179 		{
3180 			t->title_font = Scr.DefaultFont;
3181 		}
3182 	}
3183 	/* set flags to indicate that the font has changed */
3184 	Scr.flags.do_need_window_update = 1;
3185 	Scr.flags.has_default_font_changed = 1;
3186 
3187 	return;
3188 }
3189 
CMD_IconFont(F_CMD_ARGS)3190 void CMD_IconFont(F_CMD_ARGS)
3191 {
3192 	char *newaction;
3193 
3194 	if (Scr.cur_decor && Scr.cur_decor != &Scr.DefaultDecor)
3195 	{
3196 		fvwm_debug(__func__,
3197 			   "Decors do not support the IconFont command anymore."
3198 			   " Please use 'Style <stylename> IconFont <fontname>'"
3199 			   " instead.  Sorry for the inconvenience.");
3200 		return;
3201 	}
3202 
3203 	if (action)
3204 	{
3205 		/* TA:  FIXME!  xasprintf() */
3206 		newaction = fxmalloc(strlen(action) + 16);
3207 		sprintf(newaction, "* IconFont %s", action);
3208 		action = newaction;
3209 		CMD_Style(F_PASS_ARGS);
3210 		free(newaction);
3211 	}
3212 
3213 	return;
3214 }
3215 
CMD_WindowFont(F_CMD_ARGS)3216 void CMD_WindowFont(F_CMD_ARGS)
3217 {
3218 	char *newaction;
3219 
3220 	if (Scr.cur_decor && Scr.cur_decor != &Scr.DefaultDecor)
3221 	{
3222 		fvwm_debug(__func__,
3223 			   "Decors do not support the WindowFont command anymore."
3224 			   " Please use 'Style <stylename> Font <fontname>'"
3225 			   " instead.  Sorry for the inconvenience.");
3226 		return;
3227 	}
3228 
3229 	if (action)
3230 	{
3231 		/* TA;  FIXME!  xasprintf() */
3232 		newaction = fxmalloc(strlen(action) + 16);
3233 		sprintf(newaction, "* Font %s", action);
3234 		action = newaction;
3235 		CMD_Style(F_PASS_ARGS);
3236 		free(newaction);
3237 	}
3238 
3239 	return;
3240 }
3241 
3242 /*
3243  *
3244  * Changes the window's FvwmDecor pointer (veliaa@rpi.edu)
3245  *
3246  */
CMD_ChangeDecor(F_CMD_ARGS)3247 void CMD_ChangeDecor(F_CMD_ARGS)
3248 {
3249 	char *item;
3250 	FvwmDecor *decor = &Scr.DefaultDecor;
3251 	FvwmDecor *found = NULL;
3252 	FvwmWindow * const fw = exc->w.fw;
3253 
3254 	item = PeekToken(action, &action);
3255 	if (!action || !item)
3256 	{
3257 		return;
3258 	}
3259 	/* search for tag */
3260 	for (; decor; decor = decor->next)
3261 	{
3262 		if (decor->tag && StrEquals(item, decor->tag))
3263 		{
3264 			found = decor;
3265 			break;
3266 		}
3267 	}
3268 	if (!found)
3269 	{
3270 		XBell(dpy, 0);
3271 		return;
3272 	}
3273 	SET_DECOR_CHANGED(fw, 1);
3274 	fw->decor = found;
3275 	apply_decor_change(fw);
3276 
3277 	return;
3278 }
3279 
3280 /*
3281  *
3282  * Destroys an FvwmDecor (veliaa@rpi.edu)
3283  *
3284  */
CMD_DestroyDecor(F_CMD_ARGS)3285 void CMD_DestroyDecor(F_CMD_ARGS)
3286 {
3287 	char *item;
3288 	FvwmDecor *decor = Scr.DefaultDecor.next;
3289 	FvwmDecor *prev = &Scr.DefaultDecor, *found = NULL;
3290 	Bool do_recreate = False;
3291 
3292 	item = PeekToken(action, &action);
3293 	if (!item)
3294 	{
3295 		return;
3296 	}
3297 	if (StrEquals(item, "recreate"))
3298 	{
3299 		do_recreate = True;
3300 		item = PeekToken(action, NULL);
3301 	}
3302 	if (!item)
3303 	{
3304 		return;
3305 	}
3306 
3307 	/* search for tag */
3308 	for (; decor; decor = decor->next)
3309 	{
3310 		if (decor->tag && StrEquals(item, decor->tag))
3311 		{
3312 			found = decor;
3313 			break;
3314 		}
3315 		prev = decor;
3316 	}
3317 
3318 	if (found && (found != &Scr.DefaultDecor || do_recreate))
3319 	{
3320 		if (!do_recreate)
3321 		{
3322 			__remove_window_decors(F_PASS_ARGS, found);
3323 		}
3324 		DestroyFvwmDecor(found);
3325 		if (do_recreate)
3326 		{
3327 			int i;
3328 
3329 			InitFvwmDecor(found);
3330 			found->tag = fxstrdup(item);
3331 			Scr.flags.do_need_window_update = 1;
3332 			found->flags.has_changed = 1;
3333 			found->flags.has_title_height_changed = 0;
3334 			found->titlebar.flags.has_changed = 1;
3335 			for (i = 0; i < NUMBER_OF_TITLE_BUTTONS; ++i)
3336 			{
3337 				TB_FLAGS(found->buttons[i]).has_changed = 1;
3338 			}
3339 		}
3340 		else
3341 		{
3342 			prev->next = found->next;
3343 			free(found);
3344 		}
3345 	}
3346 
3347 	return;
3348 }
3349 
3350 /*
3351  *
3352  * Initiates an AddToDecor (veliaa@rpi.edu)
3353  *
3354  */
CMD_AddToDecor(F_CMD_ARGS)3355 void CMD_AddToDecor(F_CMD_ARGS)
3356 {
3357 	FvwmDecor *decor;
3358 	FvwmDecor *found = NULL;
3359 	char *item = NULL;
3360 
3361 	action = GetNextToken(action, &item);
3362 	if (!item)
3363 	{
3364 		return;
3365 	}
3366 	if (!action)
3367 	{
3368 		free(item);
3369 		return;
3370 	}
3371 	/* search for tag */
3372 	for (decor = &Scr.DefaultDecor; decor; decor = decor->next)
3373 	{
3374 		if (decor->tag && StrEquals(item, decor->tag))
3375 		{
3376 			found = decor;
3377 			break;
3378 		}
3379 	}
3380 	if (!found)
3381 	{
3382 		/* then make a new one */
3383 		found = fxmalloc(sizeof *found);
3384 		InitFvwmDecor(found);
3385 		found->tag = item; /* tag it */
3386 		/* add it to list */
3387 		for (decor = &Scr.DefaultDecor; decor->next;
3388 		     decor = decor->next)
3389 		{
3390 			/* nop */
3391 		}
3392 		decor->next = found;
3393 	}
3394 	else
3395 	{
3396 		free(item);
3397 	}
3398 
3399 	if (found)
3400 	{
3401 		AddToDecor(F_PASS_ARGS, found);
3402 		/* Set + state to last decor */
3403 		set_last_added_item(ADDED_DECOR, found);
3404 	}
3405 
3406 	return;
3407 }
3408 
3409 
3410 /*
3411  *
3412  * Updates window decoration styles (veliaa@rpi.edu)
3413  *
3414  */
CMD_UpdateDecor(F_CMD_ARGS)3415 void CMD_UpdateDecor(F_CMD_ARGS)
3416 {
3417 	FvwmWindow *fw2;
3418 
3419 	FvwmDecor *decor, *found = NULL;
3420 	FvwmWindow *hilight = Scr.Hilite;
3421 	char *item = NULL;
3422 
3423 	action = GetNextToken(action, &item);
3424 	if (item)
3425 	{
3426 		/* search for tag */
3427 		for (decor = &Scr.DefaultDecor; decor; decor = decor->next)
3428 		{
3429 			if (decor->tag && StrEquals(item, decor->tag))
3430 			{
3431 				found = decor;
3432 				break;
3433 			}
3434 		}
3435 		free(item);
3436 	}
3437 
3438 	for (fw2 = Scr.FvwmRoot.next; fw2; fw2 = fw2->next)
3439 	{
3440 		/* update specific decor, or all */
3441 		if (found)
3442 		{
3443 			if (fw2->decor == found)
3444 			{
3445 				border_draw_decorations(
3446 					fw2, PART_ALL, True, True, CLEAR_ALL,
3447 					NULL, NULL);
3448 				border_draw_decorations(
3449 					fw2, PART_ALL, False, True, CLEAR_ALL,
3450 					NULL, NULL);
3451 			}
3452 		}
3453 		else
3454 		{
3455 			border_draw_decorations(
3456 				fw2, PART_ALL, True, True, CLEAR_ALL, NULL,
3457 				NULL);
3458 			border_draw_decorations(
3459 				fw2, PART_ALL, False, True, CLEAR_ALL, NULL,
3460 				NULL);
3461 		}
3462 	}
3463 	border_draw_decorations(
3464 		hilight, PART_ALL, True, True, CLEAR_ALL, NULL, NULL);
3465 }
3466 
CMD_ButtonStyle(F_CMD_ARGS)3467 void CMD_ButtonStyle(F_CMD_ARGS)
3468 {
3469 	do_button_style(F_PASS_ARGS, False);
3470 
3471 	return;
3472 }
3473 
3474 /*
3475  *
3476  * Appends a button decoration style (veliaa@rpi.edu)
3477  *
3478  */
CMD_AddButtonStyle(F_CMD_ARGS)3479 void CMD_AddButtonStyle(F_CMD_ARGS)
3480 {
3481 	do_button_style(F_PASS_ARGS, True);
3482 
3483 	return;
3484 }
3485 
CMD_SetEnv(F_CMD_ARGS)3486 void CMD_SetEnv(F_CMD_ARGS)
3487 {
3488 	char *szVar = NULL;
3489 	char *szValue = NULL;
3490 	char *szPutenv = NULL;
3491 
3492 	action = GetNextToken(action, &szVar);
3493 	if (!szVar)
3494 	{
3495 		return;
3496 	}
3497 	action = GetNextToken(action, &szValue);
3498 	if (!szValue)
3499 	{
3500 		szValue = fxstrdup("");
3501 	}
3502 	szPutenv = fxmalloc(strlen(szVar) + strlen(szValue) + 2);
3503 	sprintf(szPutenv,"%s=%s", szVar, szValue);
3504 	flib_putenv(szVar, szPutenv);
3505 	free(szVar);
3506 	free(szPutenv);
3507 	free(szValue);
3508 
3509 	return;
3510 }
3511 
CMD_UnsetEnv(F_CMD_ARGS)3512 void CMD_UnsetEnv(F_CMD_ARGS)
3513 {
3514 	char *szVar = NULL;
3515 
3516 	szVar = PeekToken(action, &action);
3517 	if (!szVar)
3518 	{
3519 		return;
3520 	}
3521 	flib_unsetenv(szVar);
3522 
3523 	return;
3524 }
3525 
CMD_GlobalOpts(F_CMD_ARGS)3526 void CMD_GlobalOpts(F_CMD_ARGS)
3527 {
3528 	char *opt;
3529 	char *replace;
3530 	char buf[64];
3531 	int i;
3532 	Bool is_bugopt;
3533 	char *optlist[] = {
3534 		"WindowShadeShrinks",
3535 		"WindowShadeScrolls",
3536 		"SmartPlacementIsReallySmart",
3537 		"SmartPlacementIsNormal",
3538 		"ClickToFocusDoesntPassClick",
3539 		"ClickToFocusPassesClick",
3540 		"ClickToFocusDoesntRaise",
3541 		"ClickToFocusRaises",
3542 		"MouseFocusClickDoesntRaise",
3543 		"MouseFocusClickRaises",
3544 		"NoStipledTitles",
3545 		"StipledTitles",
3546 		"CaptureHonorsStartsOnPage",
3547 		"CaptureIgnoresStartsOnPage",
3548 		"RecaptureHonorsStartsOnPage",
3549 		"RecaptureIgnoresStartsOnPage",
3550 		"ActivePlacementHonorsStartsOnPage",
3551 		"ActivePlacementIgnoresStartsOnPage",
3552 		"RaiseOverNativeWindows",
3553 		"IgnoreNativeWindows",
3554 		NULL
3555 	};
3556 	char *replacelist[] = {
3557 		/* These options are mapped to the Style * command */
3558 		NULL, /* NULL means to use "Style * <optionname>" */
3559 		NULL,
3560 		"* MinOverlapPlacement",
3561 		"* TileCascadePlacement",
3562 		"* ClickToFocusPassesClickOff",
3563 		"* ClickToFocusPassesClick",
3564 		"* ClickToFocusRaisesOff",
3565 		"* ClickToFocusRaises",
3566 		"* MouseFocusClickRaisesOff",
3567 		"* MouseFocusClickRaises",
3568 		"* StippledTitleOff",
3569 		"* StippledTitle",
3570 		NULL,
3571 		NULL,
3572 		NULL,
3573 		NULL,
3574 		"* ManualPlacementHonorsStartsOnPage",
3575 		"* ManualPlacementIgnoresStartsOnPage",
3576 		/* These options are mapped to the BugOpts command */
3577 		"RaiseOverNativeWindows on",
3578 		"RaiseOverNativeWindows off"
3579 	};
3580 
3581 	fvwm_debug(__func__,
3582 		   "The GlobalOpts command is obsolete.");
3583 	for (action = GetNextSimpleOption(action, &opt); opt;
3584 	     action = GetNextSimpleOption(action, &opt))
3585 	{
3586 		replace = NULL;
3587 		is_bugopt = False;
3588 
3589 		i = GetTokenIndex(opt, optlist, 0, NULL);
3590 		if (i > -1)
3591 		{
3592 			char *cmd;
3593 			char *tmp;
3594 
3595 			replace = replacelist[i];
3596 			if (replace == NULL)
3597 			{
3598 				replace = &(buf[0]);
3599 				sprintf(buf, "* %s", opt);
3600 			}
3601 			else if (*replace != '*')
3602 			{
3603 				is_bugopt = True;
3604 			}
3605 			tmp = action;
3606 			action = replace;
3607 			if (!is_bugopt)
3608 			{
3609 				CMD_Style(F_PASS_ARGS);
3610 				cmd = "Style";
3611 			}
3612 			else
3613 			{
3614 				CMD_BugOpts(F_PASS_ARGS);
3615 				cmd = "BugOpts";
3616 			}
3617 			action = tmp;
3618 			fvwm_debug(__func__,
3619 				   "Please replace 'GlobalOpts %s' with '%s %s'.",
3620 				   opt, cmd, replace);
3621 		}
3622 		else
3623 		{
3624 			fvwm_debug(__func__,
3625 				   "Unknown Global Option '%s'", opt);
3626 		}
3627 		/* should never be null, but checking anyways... */
3628 		if (opt)
3629 		{
3630 			free(opt);
3631 		}
3632 	}
3633 	if (opt)
3634 	{
3635 		free(opt);
3636 	}
3637 
3638 	return;
3639 }
3640 
CMD_BugOpts(F_CMD_ARGS)3641 void CMD_BugOpts(F_CMD_ARGS)
3642 {
3643 	char *opt;
3644 	int toggle;
3645 	char *optstring;
3646 
3647 	/* fvwm_msg(DBG,"SetGlobalOptions","init action == '%s'\n",action); */
3648 	while (action && *action && *action != '\n')
3649 	{
3650 		action = GetNextFullOption(action, &optstring);
3651 		if (!optstring)
3652 		{
3653 			/* no more options */
3654 			return;
3655 		}
3656 		toggle = ParseToggleArgument(
3657 			SkipNTokens(optstring,1), NULL, 2, False);
3658 		opt = PeekToken(optstring, NULL);
3659 		free(optstring);
3660 
3661 		if (!opt)
3662 		{
3663 			return;
3664 		}
3665 		/* toggle = ParseToggleArgument(rest, &rest, 2, False);*/
3666 
3667 		if (StrEquals(opt, "FlickeringMoveWorkaround"))
3668 		{
3669 			switch (toggle)
3670 			{
3671 			case -1:
3672 				Scr.bo.do_disable_configure_notify ^= 1;
3673 				break;
3674 			case 0:
3675 			case 1:
3676 				Scr.bo.do_disable_configure_notify = toggle;
3677 				break;
3678 			default:
3679 				Scr.bo.do_disable_configure_notify = 0;
3680 				break;
3681 			}
3682 		}
3683 		else if (StrEquals(opt, "MixedVisualWorkaround"))
3684 		{
3685 			switch (toggle)
3686 			{
3687 			case -1:
3688 				Scr.bo.do_install_root_cmap ^= 1;
3689 				break;
3690 			case 0:
3691 			case 1:
3692 				Scr.bo.do_install_root_cmap = toggle;
3693 				break;
3694 			default:
3695 				Scr.bo.do_install_root_cmap = 0;
3696 				break;
3697 			}
3698 		}
3699 		else if (StrEquals(opt, "ModalityIsEvil"))
3700 		{
3701 			switch (toggle)
3702 			{
3703 			case -1:
3704 				Scr.bo.is_modality_evil ^= 1;
3705 				break;
3706 			case 0:
3707 			case 1:
3708 				Scr.bo.is_modality_evil = toggle;
3709 				break;
3710 			default:
3711 				Scr.bo.is_modality_evil = 0;
3712 				break;
3713 			}
3714 			if (Scr.bo.is_modality_evil)
3715 			{
3716 				SetMWM_INFO(Scr.NoFocusWin);
3717 			}
3718 		}
3719 		else if (StrEquals(opt, "RaiseOverNativeWindows"))
3720 		{
3721 			switch (toggle)
3722 			{
3723 			case -1:
3724 				Scr.bo.is_raise_hack_needed ^= 1;
3725 				break;
3726 			case 0:
3727 			case 1:
3728 				Scr.bo.is_raise_hack_needed = toggle;
3729 				break;
3730 			default:
3731 				Scr.bo.is_raise_hack_needed = 0;
3732 				break;
3733 			}
3734 		}
3735 		else if (StrEquals(opt, "RaiseOverUnmanaged"))
3736 		{
3737 			switch (toggle)
3738 			{
3739 			case -1:
3740 				Scr.bo.do_raise_over_unmanaged ^= 1;
3741 				break;
3742 			case 0:
3743 			case 1:
3744 				Scr.bo.do_raise_over_unmanaged = toggle;
3745 				break;
3746 			default:
3747 				Scr.bo.do_raise_over_unmanaged = 0;
3748 				break;
3749 			}
3750 		}
3751 		else if (StrEquals(opt, "FlickeringQtDialogsWorkaround"))
3752 		{
3753 			switch (toggle)
3754 			{
3755 			case -1:
3756 				Scr.bo.do_enable_flickering_qt_dialogs_workaround ^= 1;
3757 				break;
3758 			case 0:
3759 			case 1:
3760 				Scr.bo.do_enable_flickering_qt_dialogs_workaround = toggle;
3761 				break;
3762 			default:
3763 				Scr.bo.do_enable_flickering_qt_dialogs_workaround = 0;
3764 				break;
3765 			}
3766 		}
3767 		else if (StrEquals(opt, "QtDragnDropWorkaround") )
3768 		{
3769 			switch (toggle)
3770 			{
3771 			case -1:
3772 				Scr.bo.do_enable_qt_drag_n_drop_workaround ^= 1;
3773 				break;
3774 			case 0:
3775 			case 1:
3776 				Scr.bo.do_enable_qt_drag_n_drop_workaround = toggle;
3777 				break;
3778 			default:
3779 				Scr.bo.do_enable_qt_drag_n_drop_workaround = 0;
3780 				break;
3781 			}
3782 		}
3783 		else if (EWMH_BugOpts(opt, toggle))
3784 		{
3785 			/* work is done in EWMH_BugOpts */
3786 		}
3787 		else if (StrEquals(opt, "DisplayNewWindowNames"))
3788 		{
3789 			switch (toggle)
3790 			{
3791 			case -1:
3792 				Scr.bo.do_display_new_window_names ^= 1;
3793 				break;
3794 			case 0:
3795 			case 1:
3796 				Scr.bo.do_display_new_window_names = toggle;
3797 				break;
3798 			default:
3799 				Scr.bo.do_display_new_window_names = 0;
3800 				break;
3801 			}
3802 		}
3803 		else if (StrEquals(opt, "ExplainWindowPlacement"))
3804 		{
3805 			switch (toggle)
3806 			{
3807 			case -1:
3808 				Scr.bo.do_explain_window_placement ^= 1;
3809 				break;
3810 			case 0:
3811 			case 1:
3812 				Scr.bo.do_explain_window_placement = toggle;
3813 				break;
3814 			default:
3815 				Scr.bo.do_explain_window_placement = 0;
3816 				break;
3817 			}
3818 		}
3819 		else if (StrEquals(opt, "DebugCRMotionMethod"))
3820 		{
3821 			switch (toggle)
3822 			{
3823 			case -1:
3824 				Scr.bo.do_debug_cr_motion_method ^= 1;
3825 				break;
3826 			case 0:
3827 			case 1:
3828 				Scr.bo.do_debug_cr_motion_method = toggle;
3829 				break;
3830 			default:
3831 				Scr.bo.do_debug_cr_motion_method = 0;
3832 				break;
3833 			}
3834 		}
3835 		else if (StrEquals(opt, "DebugRandR"))
3836 		{
3837 			switch (toggle)
3838 			{
3839 			case -1:
3840 				Scr.bo.do_debug_randr ^= 1;
3841 				break;
3842 			case 0:
3843 			case 1:
3844 				Scr.bo.do_debug_randr = toggle;
3845 				break;
3846 			default:
3847 				Scr.bo.do_debug_randr = 0;
3848 				break;
3849 			}
3850 			monitor_dump_state(NULL);
3851 		}
3852 		else if (StrEquals(opt, "TransliterateUtf8"))
3853 		{
3854 			FiconvSetTransliterateUtf8(toggle);
3855 		}
3856 		else
3857 		{
3858 			fvwm_debug(__func__,
3859 				   "Unknown Bug Option '%s'", opt);
3860 		}
3861 	}
3862 
3863 	return;
3864 }
3865 
CMD_Emulate(F_CMD_ARGS)3866 void CMD_Emulate(F_CMD_ARGS)
3867 {
3868 	char *style;
3869 
3870 	style = PeekToken(action, NULL);
3871 	if (!style || StrEquals(style, "fvwm"))
3872 	{
3873 		Scr.gs.do_emulate_mwm = False;
3874 		Scr.gs.do_emulate_win = False;
3875 	}
3876 	else if (StrEquals(style, "mwm"))
3877 	{
3878 		Scr.gs.do_emulate_mwm = True;
3879 		Scr.gs.do_emulate_win = False;
3880 	}
3881 	else if (StrEquals(style, "win"))
3882 	{
3883 		Scr.gs.do_emulate_mwm = False;
3884 		Scr.gs.do_emulate_win = True;
3885 	}
3886 	else
3887 	{
3888 		fvwm_debug(__func__, "Unknown style '%s'", style);
3889 		return;
3890 	}
3891 	/* This command might have been issued after any GeometryWindow
3892 	 * commands, in which case set those values to their defaults.
3893 	 */
3894 	Scr.SizeWindow.is_configured = false;
3895 	Scr.SizeWindow.m = NULL;
3896 
3897 	Scr.flags.do_need_window_update = 1;
3898 	Scr.flags.has_default_font_changed = 1;
3899 	Scr.flags.has_default_color_changed = 1;
3900 
3901 	return;
3902 }
3903 
CMD_ColorLimit(F_CMD_ARGS)3904 void CMD_ColorLimit(F_CMD_ARGS)
3905 {
3906 	fvwm_debug(__func__, "ColorLimit is obsolete,\n\tuse the "
3907 		   "fvwm -color-limit option");
3908 
3909 	return;
3910 }
3911 
3912 
3913 /* set animation parameters */
CMD_SetAnimation(F_CMD_ARGS)3914 void CMD_SetAnimation(F_CMD_ARGS)
3915 {
3916 	char *opt;
3917 	int delay;
3918 	float pct;
3919 	int i = 0;
3920 
3921 	opt = PeekToken(action, &action);
3922 	if (!opt || sscanf(opt,"%d",&delay) != 1)
3923 	{
3924 		fvwm_debug(__func__,
3925 			   "Improper milli-second delay as first argument");
3926 		return;
3927 	}
3928 	if (delay > 500)
3929 	{
3930 		fvwm_debug(__func__,
3931 			   "Using longer than .5 seconds as between frame"
3932 			   " animation delay");
3933 	}
3934 	cmsDelayDefault = delay;
3935 	for (opt = PeekToken(action, &action); opt;
3936 	     opt = PeekToken(action, &action))
3937 	{
3938 		if (sscanf(opt,"%f",&pct) != 1)
3939 		{
3940 			fvwm_debug(__func__,
3941 				   "Use fractional values ending in 1.0 as args"
3942 				   " 2 and on");
3943 			return;
3944 		}
3945 		rgpctMovementDefault[i++] = pct;
3946 	}
3947 	/* No pct entries means don't change them at all */
3948 	if (i > 0 && rgpctMovementDefault[i-1] != 1.0)
3949 	{
3950 		rgpctMovementDefault[i++] = 1.0;
3951 	}
3952 
3953 	return;
3954 }
3955 
3956 /* Determine which modifiers are required with a keycode to make <keysym>. */
FKeysymToKeycode(Display * dpy,KeySym keysym,unsigned int * keycode,unsigned int * modifiers)3957 static Bool FKeysymToKeycode (Display *dpy, KeySym keysym,
3958 	unsigned int *keycode, unsigned int *modifiers)
3959 {
3960 	int m;
3961 
3962 	*keycode = XKeysymToKeycode(dpy, keysym);
3963 	*modifiers = 0;
3964 
3965 	for (m = 0; m <= 8; ++m)
3966 	{
3967 		KeySym ks = fvwm_KeycodeToKeysym(dpy, *keycode, m, 0);
3968 		if (ks == keysym)
3969 		{
3970 			switch (m)
3971 			{
3972 				case 0: /* No modifiers */
3973 					break;
3974 				case 1: /* Shift modifier */
3975 					*modifiers |= ShiftMask;
3976 					break;
3977 				default:
3978 					fvwm_debug(__func__,
3979 						   "Unhandled modifier %d", m);
3980 					break;
3981 			}
3982 			return True;
3983 		}
3984 	}
3985 	return False;
3986 }
3987 
__fake_event(F_CMD_ARGS,FakeEventType type)3988 static void __fake_event(F_CMD_ARGS, FakeEventType type)
3989 {
3990 	char *token;
3991 	char *optlist[] = {
3992 		"press", "p",
3993 		"release", "r",
3994 		"wait", "w",
3995 		"modifiers", "m",
3996 		"depth", "d",
3997 		NULL
3998 	};
3999 	unsigned int mask = 0;
4000 	Window root = Scr.Root;
4001 	int maxdepth = 0;
4002 	static char args[128];
4003 	strncpy(args, action, sizeof(args) - 1);
4004 
4005 	/* get the mask of pressed/released buttons/keys */
4006 	FQueryPointer(
4007 		dpy, Scr.Root, &root, &JunkRoot, &JunkX, &JunkY, &JunkX,
4008 		&JunkY, &mask);
4009 
4010 	token = PeekToken(action, &action);
4011 	while (token && action)
4012 	{
4013 		int index = GetTokenIndex(token, optlist, 0, NULL);
4014 		int val, depth;
4015 		XEvent e;
4016 		Window w;
4017 		Window child_w;
4018 		int x = 0;
4019 		int y = 0;
4020 		int rx = 0;
4021 		int ry = 0;
4022 		Bool do_unset;
4023 		long add_mask = 0;
4024 		KeySym keysym = NoSymbol;
4025 
4026 		XFlush(dpy);
4027 		do_unset = True;
4028 		switch (index)
4029 		{
4030 		case 0:
4031 		case 1:
4032 			do_unset = False;
4033 			/* fall through */
4034 		case 2:
4035 		case 3:
4036 			/* key/button press or release */
4037 			if (type == FakeMouseEvent)
4038 			{
4039 				if ((GetIntegerArguments(
4040 					     action, &action, &val, 1) != 1) ||
4041 				    val < 1 ||
4042 				    val > NUMBER_OF_EXTENDED_MOUSE_BUTTONS)
4043 				{
4044 					fvwm_debug(__func__,
4045 						   "Invalid button specifier in"
4046 						   " \"%s\" for FakeClick.",
4047 						   args);
4048 					return; /* error */
4049 				}
4050 			}
4051 			else /* type == FakeKeyEvent */
4052 			{
4053 				char *key = PeekToken(action, &action);
4054 				if (key == NULL)
4055 				{
4056 					fvwm_debug(__func__,
4057 						   "No keysym specifier in \"%s\""
4058 						   " for FakeKeypress.", args);
4059 					return;
4060 				}
4061 
4062 				/* Do *NOT* use FvwmStringToKeysym() as it is
4063 				 * case insensitive. */
4064 				keysym = XStringToKeysym(key);
4065 				if (keysym == NoSymbol)
4066 				{
4067 					fvwm_debug(__func__,
4068 						   "Invalid keysym specifier (%s)"
4069 						   " in \"%s\" for FakeKeypress.",
4070 						   key, args);
4071 					return;
4072 				}
4073 			}
4074 
4075 			w = None;
4076 			child_w = root;
4077 			for (depth = 1;
4078 				 depth != maxdepth &&
4079 				     w != child_w && child_w != None;
4080 				 depth++)
4081 			{
4082 				w = child_w;
4083 				if (FQueryPointer(
4084 						dpy, w, &root, &child_w,
4085 						&rx, &ry, &x, &y,
4086 						&JunkMask) == False)
4087 				{
4088 					/* pointer is on a different
4089 					 * screen - that's okay here */
4090 				}
4091 			}
4092 
4093 			if (type == FakeMouseEvent)
4094 			{
4095 				e.type = (do_unset) ?
4096 					ButtonRelease : ButtonPress;
4097 				e.xbutton.display = dpy;
4098 				e.xbutton.window = w;
4099 				e.xbutton.subwindow = None;
4100 				e.xbutton.root = root;
4101 				e.xbutton.time = fev_get_evtime();
4102 				e.xbutton.x = x;
4103 				e.xbutton.y = y;
4104 				e.xbutton.x_root = rx;
4105 				e.xbutton.y_root = ry;
4106 				e.xbutton.button = val;
4107 				e.xbutton.state = mask;
4108 				e.xbutton.same_screen = (Scr.Root == root);
4109 				/* SS: I think this mask handling code is
4110 				 * buggy.
4111 				 * The value of <mask> is overridden during a
4112 				 * "wait" operation. Also why are we only using
4113 				 * Button1Mask? What if the user has requested
4114 				 * a FakeClick using some other button? */
4115 				/* DV: Button1Mask is actually a bit.  Shifting
4116 				 * it by (val -1) bits to the left gives
4117 				 * Button2Mask, Button3Mask etc. */
4118 				if (do_unset)
4119 				{
4120 					mask &= ~(Button1Mask << (val - 1));
4121 				}
4122 				else
4123 				{
4124 					mask |= (Button1Mask << (val - 1));
4125 				}
4126 				add_mask = (do_unset) ?
4127 					ButtonPressMask : ButtonReleaseMask;
4128 			}
4129 			else
4130 			{
4131 				/* type == FakeKeyEvent */
4132 				e.type = (do_unset ? KeyRelease : KeyPress);
4133 				e.xkey.display = dpy;
4134 				e.xkey.subwindow = None;
4135 				e.xkey.root = root;
4136 				e.xkey.time = fev_get_evtime();
4137 				e.xkey.x = x;
4138 				e.xkey.y = y;
4139 				e.xkey.x_root = rx;
4140 				e.xkey.y_root = ry;
4141 				e.xkey.same_screen = (Scr.Root == root);
4142 
4143 				w = e.xkey.window = exc->w.w;
4144 
4145 				if (FKeysymToKeycode(
4146 					    dpy, keysym, &(e.xkey.keycode),
4147 					    &(e.xkey.state)) != True)
4148 				{
4149 					fvwm_debug(__func__,
4150 						   "FKeysymToKeycode failed");
4151 					return;
4152 				}
4153 				e.xkey.state |= mask;
4154 				add_mask = (do_unset) ?
4155 					KeyReleaseMask : KeyPressMask;
4156 			}
4157 			FSendEvent(dpy, w, True,
4158 				SubstructureNotifyMask | add_mask, &e);
4159 			XFlush(dpy);
4160 			break;
4161 		case 4:
4162 		case 5:
4163 			/* wait */
4164 			if ((GetIntegerArguments(
4165 				     action, &action, &val, 1) != 1) ||
4166 			    val <= 0 || val > 1000000)
4167 			{
4168 				fvwm_debug(__func__,
4169 					   "Invalid wait value in \"%s\"",
4170 					   args);
4171 				return;
4172 			}
4173 
4174 			usleep(1000 * val);
4175 			if (FQueryPointer(
4176 					dpy, Scr.Root, &root, &JunkRoot,
4177 					&JunkX, &JunkY, &JunkX, &JunkY,
4178 					&mask) == False)
4179 			{
4180 				/* pointer is on a different screen -
4181 				 * that's okay here */
4182 			}
4183 			break;
4184 		case 6:
4185 		case 7:
4186 			/* set modifier */
4187 			if (GetIntegerArguments(action, &action, &val, 1) != 1)
4188 			{
4189 				fvwm_debug(__func__,
4190 					   "Invalid modifier value in \"%s\"",
4191 					   args);
4192 				return;
4193 			}
4194 			do_unset = False;
4195 			if (val < 0)
4196 			{
4197 				do_unset = True;
4198 				val = -val;
4199 			}
4200 			if (val == 6)
4201 			{
4202 				val = ShiftMask;
4203 			}
4204 			else if (val == 7)
4205 			{
4206 				val = LockMask;
4207 			}
4208 			else if (val == 8)
4209 			{
4210 				val = ControlMask;
4211 			}
4212 			else if (val >=1 && val <= 5)
4213 			{
4214 				val = (Mod1Mask << (val - 1));
4215 			}
4216 			else
4217 			{
4218 				/* error */
4219 				return;
4220 			}
4221 			/* SS: Could be buggy if a "modifier" operation
4222 			 * preceeds a "wait" operation. */
4223 			if (do_unset)
4224 			{
4225 				mask &= ~val;
4226 			}
4227 			else
4228 			{
4229 				mask |= val;
4230 			}
4231 			break;
4232 		case 8:
4233 		case 9:
4234 			/* new max depth */
4235 			if (GetIntegerArguments(action, &action, &val, 1) != 1)
4236 			{
4237 				fvwm_debug(__func__,
4238 					   "Invalid depth value in \"%s\"",
4239 					   args);
4240 				return;
4241 			}
4242 			maxdepth = val;
4243 			break;
4244 		default:
4245 			fvwm_debug(__func__,
4246 				   "Invalid command (%s) in \"%s\"", token,
4247 				   args);
4248 			return;
4249 		}
4250 		if (action)
4251 		{
4252 			token = PeekToken(action, &action);
4253 		}
4254 	}
4255 
4256 	return;
4257 }
4258 
CMD_FakeClick(F_CMD_ARGS)4259 void CMD_FakeClick(F_CMD_ARGS)
4260 {
4261 	__fake_event(F_PASS_ARGS, FakeMouseEvent);
4262 
4263 	return;
4264 }
4265 
CMD_FakeKeypress(F_CMD_ARGS)4266 void CMD_FakeKeypress(F_CMD_ARGS)
4267 {
4268 	__fake_event(F_PASS_ARGS, FakeKeyEvent);
4269 
4270 	return;
4271 }
4272 
CMD_State(F_CMD_ARGS)4273 void CMD_State(F_CMD_ARGS)
4274 {
4275 	unsigned int state;
4276 	int toggle;
4277 	int n;
4278 	FvwmWindow * const fw = exc->w.fw;
4279 
4280 	n = GetIntegerArguments(action, &action, (int *)&state, 1);
4281 	if (n <= 0)
4282 	{
4283 		return;
4284 	}
4285 	if (state > 31)
4286 	{
4287 		fvwm_debug(__func__, "Illegal state %d\n", state);
4288 		return;
4289 	}
4290 	toggle = ParseToggleArgument(action, NULL, -1, 0);
4291 	state = (1 << state);
4292 	switch (toggle)
4293 	{
4294 	case -1:
4295 		TOGGLE_USER_STATES(fw, state);
4296 		break;
4297 	case 0:
4298 		CLEAR_USER_STATES(fw, state);
4299 		break;
4300 	case 1:
4301 	default:
4302 		SET_USER_STATES(fw, state);
4303 		break;
4304 	}
4305 
4306 	return;
4307 }
4308