1 /* -*-c-*- */
2 /*
3  * FvwmButtons, copyright 1996, Jarl Totland
4  *
5  * This module, and the entire GoodStuff program, and the concept for
6  * interfacing this module to the Window Manager, are all original work
7  * by Robert Nation
8  */
9 
10 /* This program is free software; you can redistribute it and/or modify
11  * it under the terms of the GNU General Public License as published by
12  * the Free Software Foundation; either version 2 of the License, or
13  * (at your option) any later version.
14  *
15  * This program is distributed in the hope that it will be useful,
16  * but WITHOUT ANY WARRANTY; without even the implied warranty of
17  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
18  * GNU General Public License for more details.
19  *
20  * You should have received a copy of the GNU General Public License
21  * along with this program; if not, see: <http://www.gnu.org/licenses/>
22  */
23 
24 #include "config.h"
25 
26 #include <ctype.h>
27 #include <stdio.h>
28 
29 #include <X11/Xlib.h>
30 #include <X11/Intrinsic.h>
31 
32 #include "libs/fvwmlib.h"
33 #include "libs/FScreen.h"
34 #include "libs/Module.h"
35 #include "libs/Colorset.h"
36 #include "libs/Parse.h"
37 #include "libs/Strings.h"
38 #include "FvwmButtons.h"
39 #include "button.h"
40 #include "parse.h"
41 
42 extern int w, h, x, y, xneg, yneg; /* used in ParseConfigLine */
43 extern char *config_file;
44 extern int button_width;
45 extern int button_height;
46 extern int has_button_geometry;
47 extern int screen;
48 
49 /* contains the character that terminated the last string from seekright */
50 static char terminator = '\0';
51 
52 /* ----------------------------------- macros ------------------------------ */
53 
trimleft(char * s)54 static char *trimleft(char *s)
55 {
56 	while (s && isspace((unsigned char)*s))
57 	{
58 		s++;
59 	}
60 	return s;
61 }
62 
63 /**
64 *** seekright()
65 ***
66 *** split off the first continous section of the string into a new allocated
67 *** string and move the old pointer forward. Accepts and strips quoting with
68 *** ['"`], and the current quote q can be escaped inside the string with \q.
69 **/
seekright(char ** s)70 static char *seekright(char **s)
71 {
72 	char *token = NULL;
73 	char *line = *s;
74 
75 	line = DoGetNextToken(line, &token, NULL, "),", &terminator);
76 	if (*s != NULL && line == NULL)
77 	{
78 		line = strchr(*s, '\0');
79 	}
80 	*s = line;
81 
82 	return token;
83 }
84 
my_get_font(char ** s)85 static char *my_get_font(char **s)
86 {
87 	char *option;
88 	int len;
89 
90 	*s = GetNextFullOption(*s, &option);
91 	if (option)
92 	{
93 		for (len = strlen(option) - 1; len >= 0 && isspace(option[len]); len--)
94 		{
95 			/* remove trailing whitespace */
96 			option[len] = 0;
97 		}
98 		for ( ; *option && isspace(*option); option++)
99 		{
100 			/* remove leading whitespace */
101 		}
102 	}
103 
104 	len = strlen(option) -1;
105 	if (option[len] == ')' )
106 	{
107 		option[len] = 0;
108 	}
109 
110 	return option;
111 }
112 
113 /**
114 *** ParseBack()
115 *** Parses the options possible to Back
116 *** This function appears to be obsolete & should be removed -- SS.
117 **/
ParseBack(char ** ss)118 static int ParseBack(char **ss)
119 {
120 	char *opts[] =
121 	{
122 		"icon",
123 		NULL
124 	};
125 	char *t, *s = *ss;
126 	int r = 0;
127 
128 	while (*s && *s != ')')
129 	{
130 		s = trimleft(s);
131 		if (*s == ',')
132 		{
133 			s++;
134 			continue;
135 		}
136 
137 		switch (GetTokenIndex(s, opts, -1, &s))
138 		{
139 		case 0: /* Icon */
140 			r = 1;
141 			fprintf(stderr,
142 				"%s: Back(Icon) not supported yet\n",
143 				MyName);
144 			break;
145 		default:
146 			t = seekright(&s);
147 			fprintf(stderr,
148 				"%s: Illegal back option \"%s\"\n",
149 				MyName, (t) ? t : "");
150 			if (t)
151 			{
152 				free(t);
153 			}
154 		}
155 	}
156 	if (*s)
157 	{
158 		s++;
159 	}
160 	*ss = s;
161 
162 	return r;
163 }
164 
165 /**
166 *** ParseBoxSize()
167 *** Parses the options possible to BoxSize
168 **/
ParseBoxSize(char ** ss,flags_type * flags)169 static void ParseBoxSize(char **ss, flags_type *flags)
170 {
171 	char *opts[] =
172 	{
173 		"dumb",
174 		"fixed",
175 		"smart",
176 		NULL
177 	};
178 	char *s = *ss;
179 	int m;
180 
181 	if (!s)
182 	{
183 		return;
184 	}
185 	*ss = GetNextTokenIndex(*ss, opts, 0, &m);
186 	switch (m)
187 	{
188 	case 0:
189 		flags->b_SizeFixed = 0;
190 		flags->b_SizeSmart = 0;
191 		break;
192 	case 1:
193 		flags->b_SizeFixed = 1;
194 		flags->b_SizeSmart = 0;
195 		break;
196 	case 2:
197 		flags->b_SizeSmart = 1;
198 		flags->b_SizeFixed = 0;
199 		break;
200 	default:
201 		flags->b_SizeFixed = 0;
202 		flags->b_SizeSmart = 0;
203 		fprintf(stderr,
204 			"%s: Illegal boxsize option \"%s\"\n",
205 			MyName, s);
206 		break;
207 	}
208 	return;
209 }
210 
211 /**
212 *** ParseTitle()
213 *** Parses the options possible to Title
214 **/
ParseTitle(char ** ss,byte * flags,byte * mask)215 static void ParseTitle(char **ss, byte *flags, byte *mask)
216 {
217 	char *titleopts[] =
218 	{
219 		"left",
220 		"right",
221 		"center",
222 		"side",
223 		NULL
224 	};
225 	char *t, *s = *ss;
226 
227 	while (*s && *s != ')')
228 	{
229 		s = trimleft(s);
230 		if (*s == ',')
231 		{
232 			s++;
233 			continue;
234 		}
235 
236 		switch (GetTokenIndex(s, titleopts, -1, &s))
237 		{
238 		case 0: /* Left */
239 			*flags &= ~b_TitleHoriz;
240 			*flags &= ~3;
241 			*mask |= b_TitleHoriz;
242 			break;
243 		case 1: /* Right */
244 			*flags &= ~b_TitleHoriz;
245 			*flags &= ~3;
246 			*flags |= 2;
247 			*mask |= b_TitleHoriz;
248 			break;
249 		case 2: /* Center */
250 			*flags &= ~b_TitleHoriz;
251 			*flags &= ~3;
252 			*flags |= 1;
253 			*mask |= b_TitleHoriz;
254 			break;
255 		case 3: /* Side */
256 			*flags |= b_Horizontal;
257 			*flags &= ~3;
258 			*mask |= b_Horizontal;
259 			break;
260 		default:
261 			t = seekright(&s);
262 			fprintf(stderr,
263 				"%s: Illegal title option \"%s\"\n",
264 				MyName, (t) ? t : "");
265 			if (t)
266 			{
267 				free(t);
268 			}
269 		}
270 	}
271 	if (*s)
272 	{
273 		s++;
274 	}
275 	*ss = s;
276 }
277 
278 /**
279 *** ParseSwallow()
280 *** Parses the options possible to Swallow
281 **/
ParseSwallow(char ** ss,unsigned int * flags,unsigned int * mask,button_info * b)282 static void ParseSwallow(
283 	char **ss, unsigned int *flags, unsigned int *mask, button_info *b)
284 {
285 	char *swallowopts[] =
286 	{
287 		"nohints", "hints",
288 		"nokill", "kill",
289 		"noclose", "close",
290 		"respawn", "norespawn",
291 		"useold", "noold",
292 		"usetitle", "notitle",
293 		"fvwmmodule", "nofvwmmodule",
294 		"swallownew",
295 		NULL
296 	};
297 	char *t, *s = *ss;
298 
299 	while (*s && *s != ')')
300 	{
301 		s = trimleft(s);
302 		if (*s == ',')
303 		{
304 			s++;
305 			continue;
306 		}
307 
308 		switch (GetTokenIndex(s, swallowopts, -1, &s))
309 		{
310 		case 0: /* NoHints */
311 			*flags |= b_NoHints;
312 			*mask |= b_NoHints;
313 			break;
314 		case 1: /* Hints */
315 			*flags &= ~b_NoHints;
316 			*mask |= b_NoHints;
317 			break;
318 		case 2: /* NoKill */
319 			*flags &= ~b_Kill;
320 			*mask |= b_Kill;
321 			break;
322 		case 3: /* Kill */
323 			*flags |= b_Kill;
324 			*mask |= b_Kill;
325 			break;
326 		case 4: /* NoClose */
327 			*flags |= b_NoClose;
328 			*mask |= b_NoClose;
329 			break;
330 		case 5: /* Close */
331 			*flags &= ~b_NoClose;
332 			*mask |= b_NoClose;
333 			break;
334 		case 6: /* Respawn */
335 			*flags |= b_Respawn;
336 			*mask |= b_Respawn;
337 			b->newflags.do_swallow_new = 0;
338 			break;
339 		case 7: /* NoRespawn */
340 			*flags &= ~b_Respawn;
341 			*mask |= b_Respawn;
342 			b->newflags.do_swallow_new = 0;
343 			break;
344 		case 8: /* UseOld */
345 			*flags |= b_UseOld;
346 			*mask |= b_UseOld;
347 			break;
348 		case 9: /* NoOld */
349 			*flags &= ~b_UseOld;
350 			*mask |= b_UseOld;
351 			break;
352 		case 10: /* UseTitle */
353 			*flags |= b_UseTitle;
354 			*mask |= b_UseTitle;
355 			break;
356 		case 11: /* NoTitle */
357 			*flags &= ~b_UseTitle;
358 			*mask |= b_UseTitle;
359 			break;
360 		case 12: /* FvwmModule */
361 			*flags |= b_FvwmModule;
362 			*mask |= b_FvwmModule;
363 			break;
364 		case 13: /* NoFvwmModule */
365 			*flags &= ~b_FvwmModule;
366 			*mask |= b_FvwmModule;
367 			break;
368 		case 14: /* SwallowNew */
369 			*flags &= ~b_Respawn;
370 			*mask |= b_Respawn;
371 			b->newflags.do_swallow_new = 1;
372 			break;
373 		default:
374 			t = seekright(&s);
375 			fprintf(stderr,
376 				"%s: Illegal Swallow option \"%s\"\n", MyName,
377 				(t) ? t : "");
378 			if (t)
379 			{
380 				free(t);
381 			}
382 		}
383 	}
384 	if (*s)
385 	{
386 		s++;
387 	}
388 	*ss = s;
389 }
390 
391 /**
392 *** ParsePanel()
393 *** Parses the options possible to Panel
394 **/
ParsePanel(char ** ss,unsigned int * flags,unsigned int * mask,char * direction,int * steps,int * delay,panel_flags_type * panel_flags,int * indicator_size,int * rela_x,int * rela_y,char * position,char * context)395 static void ParsePanel(
396 	char **ss, unsigned int *flags, unsigned int *mask, char *direction,
397 	int *steps, int *delay, panel_flags_type *panel_flags,
398 	int *indicator_size, int *rela_x, int *rela_y, char *position,
399 	char *context)
400 {
401 	char *swallowopts[] =
402 	{
403 		"nohints", "hints",
404 		"nokill", "kill",
405 		"noclose", "close",
406 		"respawn", "norespawn",
407 		"useold", "noold",
408 		"usetitle", "notitle",
409 		"up", "down", "left", "right",
410 		"steps",
411 		"delay",
412 		"smooth",
413 		"noborder",
414 		"indicator",
415 		"position",
416 		NULL
417 	};
418 
419 	char *positionopts[] =
420 	{
421 		"button", "module", "root", "center", "left", "top", "right",
422 		"bottom", "noplr", "noptb", "mlr", "mtb", NULL
423 	};
424 
425 	char *t, *s = *ss;
426 	int n;
427 
428 	while (*s && *s != ')')
429 	{
430 		s = trimleft(s);
431 		if (*s == ',')
432 		{
433 			s++;
434 			continue;
435 		}
436 
437 		switch (GetTokenIndex(s, swallowopts, -1, &s))
438 		{
439 		case 0: /* NoHints */
440 			*flags |= b_NoHints;
441 			*mask |= b_NoHints;
442 			break;
443 		case 1: /* Hints */
444 			*flags &= ~b_NoHints;
445 			*mask |= b_NoHints;
446 			break;
447 		case 2: /* NoKill */
448 			*flags &= ~b_Kill;
449 			*mask |= b_Kill;
450 			break;
451 		case 3: /* Kill */
452 			*flags |= b_Kill;
453 			*mask |= b_Kill;
454 			break;
455 		case 4: /* NoClose */
456 			*flags |= b_NoClose;
457 			*mask |= b_NoClose;
458 			break;
459 		case 5: /* Close */
460 			*flags &= ~b_NoClose;
461 			*mask |= b_NoClose;
462 			break;
463 		case 6: /* Respawn */
464 			*flags |= b_Respawn;
465 			*mask |= b_Respawn;
466 			break;
467 		case 7: /* NoRespawn */
468 			*flags &= ~b_Respawn;
469 			*mask |= b_Respawn;
470 			break;
471 		case 8: /* UseOld */
472 			*flags |= b_UseOld;
473 			*mask |= b_UseOld;
474 			break;
475 		case 9: /* NoOld */
476 			*flags &= ~b_UseOld;
477 			*mask |= b_UseOld;
478 			break;
479 		case 10: /* UseTitle */
480 			*flags |= b_UseTitle;
481 			*mask |= b_UseTitle;
482 			break;
483 		case 11: /* NoTitle */
484 			*flags &= ~b_UseTitle;
485 			*mask |= b_UseTitle;
486 			break;
487 		case 12: /* up */
488 			*direction = SLIDE_UP;
489 			break;
490 		case 13: /* down */
491 			*direction = SLIDE_DOWN;
492 			break;
493 		case 14: /* left */
494 			*direction = SLIDE_LEFT;
495 			break;
496 		case 15: /* right */
497 			*direction = SLIDE_RIGHT;
498 			break;
499 		case 16: /* steps */
500 			sscanf(s, "%d%n", steps, &n);
501 			s += n;
502 			break;
503 		case 17: /* delay */
504 			sscanf(s, "%d%n", delay, &n);
505 			s += n;
506 			break;
507 		case 18: /* smooth */
508 			(*panel_flags).smooth = 1;
509 			break;
510 		case 19: /* noborder */
511 			(*panel_flags).ignore_lrborder = 1;
512 			(*panel_flags).ignore_tbborder = 1;
513 			break;
514 		case 20: /* indicator */
515 			n = 0;
516 			(*panel_flags).panel_indicator = 1;
517 			*indicator_size = 0;
518 			sscanf(s, "%d%n", indicator_size, &n);
519 			if (*indicator_size < 0 || *indicator_size > 100)
520 			{
521 				*indicator_size = 0;
522 			}
523 			s += n;
524 			break;
525 		case 21: /* position */
526 			n = 0;
527 			*rela_x = *rela_y = 0;
528 			while (*s != ',' && *s != ')' && *s)
529 			{
530 				s = trimleft(s);
531 				/* get x and y offset */
532 				if (isdigit(*s) || *s == '+' || *s == '-')
533 				{
534 					sscanf(s, "%i%n", rela_x, &n);
535 					s += n;
536 					if (*s == 'p' || *s == 'P')
537 					{
538 						(*panel_flags).relative_x_pixel = 1;
539 						s++;
540 					}
541 					n = 0;
542 					s = trimleft(s);
543 					sscanf(s, "%i%n", rela_y, &n);
544 					s += n;
545 					if (*s == 'p' || *s == 'P')
546 					{
547 						(*panel_flags).relative_y_pixel = 1;
548 						s++;
549 					}
550 					s = trimleft(s);
551 				}
552 				switch (GetTokenIndex(s, positionopts, -1, &s))
553 				{
554 				case 0: /* button */
555 					*context = SLIDE_CONTEXT_PB;
556 					break;
557 				case 1: /* module */
558 					*context = SLIDE_CONTEXT_MODULE;
559 					break;
560 				case 2: /* root */
561 					*context = SLIDE_CONTEXT_ROOT;
562 					break;
563 				case 3: /* center */
564 					*position = SLIDE_POSITION_CENTER;
565 					break;
566 				case 4: /* left */
567 					*position = SLIDE_POSITION_LEFT_TOP;
568 					break;
569 				case 5: /* top  */
570 					*position = SLIDE_POSITION_LEFT_TOP;
571 					break;
572 				case 6: /* right */
573 					*position = SLIDE_POSITION_RIGHT_BOTTOM;
574 					break;
575 				case 7: /* bottom */
576 					*position = SLIDE_POSITION_RIGHT_BOTTOM;
577 					break;
578 				case 8: /* noplr */
579 					(*panel_flags).ignore_lrborder = 1;
580 					break;
581 				case 9: /* noptb */
582 					(*panel_flags).ignore_tbborder = 1;
583 					break;
584 				case 10: /* mlr */
585 					(*panel_flags).buttons_lrborder = 1;
586 					break;
587 				case 11: /* mtb */
588 					(*panel_flags).buttons_tbborder = 1;
589 					break;
590 				default:
591 					t = seekright(&s);
592 					s--;
593 					if (t)
594 					{
595 						fprintf(stderr,
596 							"%s: Illegal Panel "
597 							"position option %s\n",
598 							MyName,	(t) ? t : "");
599 						free(t);
600 					}
601 				}
602 			}
603 			break;
604 		default:
605 			t = seekright(&s);
606 			fprintf(stderr,
607 				"%s: Illegal Panel option \"%s\"\n", MyName,
608 				(t) ? t : "");
609 			if (t)
610 			{
611 				free(t);
612 			}
613 		}
614 	}
615 	if (*s)
616 	{
617 		s++;
618 	}
619 	*ss = s;
620 }
621 
622 /**
623 *** ParseContainer()
624 *** Parses the options possible to Container
625 **/
ParseContainer(char ** ss,button_info * b)626 static void ParseContainer(char **ss,button_info *b)
627 {
628 	char *conts[] =
629 	{
630 		"columns",
631 		"rows",
632 		"font",
633 		"frame",
634 		"back",
635 		"fore",
636 		"padding",
637 		"title",
638 		"swallow",
639 		"nosize",
640 		"size",
641 		"boxsize",
642 		"colorset",
643 		NULL
644 	};
645 	char *t, *o, *s = *ss;
646 	int i, j;
647 
648 	while (*s && *s != ')')
649 	{
650 		s = trimleft(s);
651 		if (*s == ',')
652 		{
653 			s++;
654 			continue;
655 		}
656 
657 		switch (GetTokenIndex(s, conts, -1, &s))
658 		{
659 		case 0: /* Columns */
660 			b->c->num_columns = max(1, strtol(s, &t, 10));
661 			s = t;
662 			break;
663 		case 1: /* Rows */
664 			b->c->num_rows = max(1, strtol(s, &t, 10));
665 			s = t;
666 			break;
667 		case 2: /* Font */
668 			if (b->c->font_string)
669 			{
670 				free(b->c->font_string);
671 			}
672 			b->c->font_string = my_get_font(&s);
673 			b->c->flags.b_Font = (b->c->font_string ? 1 : 0);
674 			break;
675 		case 3: /* Frame */
676 			b->c->framew = strtol(s, &t, 10);
677 			b->c->flags.b_Frame = 1;
678 			s = t;
679 			break;
680 		case 4: /* Back */
681 			s = trimleft(s);
682 			if (*s == '(' && s++ && ParseBack(&s))
683 			{
684 				b->c->flags.b_IconBack = 1;
685 			}
686 			if (b->c->back)
687 			{
688 				free(b->c->back);
689 			}
690 			b->c->back = seekright(&s);
691 			if (b->c->back)
692 			{
693 				b->c->flags.b_Back = 1;
694 			}
695 			else
696 			{
697 				b->c->flags.b_IconBack = 0;
698 				b->c->flags.b_Back = 0;
699 			}
700 			break;
701     case 5: /* Fore */
702       if (b->c->fore) free(b->c->fore);
703       b->c->fore = seekright(&s);
704       b->c->flags.b_Fore = (b->c->fore ? 1 : 0);
705       break;
706     case 6: /* Padding */
707       i = strtol(s, &t, 10);
708       if (t > s)
709       {
710 	b->c->xpad = b->c->ypad = i;
711 	s = t;
712 	i = strtol(s, &t, 10);
713 	if (t > s)
714 	{
715 	  b->c->ypad = i;
716 	  s = t;
717 	}
718 	b->c->flags.b_Padding = 1;
719       }
720       else
721 	fprintf(stderr,"%s: Illegal padding argument\n",MyName);
722       break;
723     case 7: /* Title - flags */
724       s = trimleft(s);
725       if (*s == '(' && s++)
726       {
727 	b->c->justify = 0;
728 	b->c->justify_mask = 0;
729 	ParseTitle(&s, &b->c->justify, &b->c->justify_mask);
730 	if (b->c->justify_mask)
731 	{
732 	  b->c->flags.b_Justify = 1;
733 	}
734       }
735       else
736       {
737 	char *temp;
738 	fprintf(stderr,
739 		"%s: Illegal title in container options\n",
740 		MyName);
741 	temp = seekright(&s);
742 	if (temp)
743 	{
744 	  free(temp);
745 	}
746       }
747       break;
748     case 8: /* Swallow - flags */
749       {
750 	Bool failed = False;
751 
752 	s = trimleft(s);
753 	if (b->c->flags.b_Swallow || b->c->flags.b_Panel)
754 	{
755 	  fprintf(stderr, "%s: Multiple Swallow or Panel options are not"
756 		" allowed in a single button", MyName);
757 	  failed = True;
758 	}
759 	else if (*s == '(' && s++)
760 	{
761 	  b->c->swallow = 0;
762 	  b->c->swallow_mask = 0;
763 	  ParseSwallow(&s, &b->c->swallow, &b->c->swallow_mask, b);
764 	  if (b->c->swallow_mask)
765 	  {
766 	    b->c->flags.b_Swallow = 1;
767 	  }
768 	}
769 	else
770 	{
771 	  fprintf(stderr,
772 		  "%s: Illegal swallow or panel in container options\n",
773 		  MyName);
774 	  failed = True;
775 	}
776 	if (failed)
777 	{
778 	  char *temp;
779 
780 	  temp = seekright(&s);
781 	  if (temp)
782 	    free(temp);
783 	}
784       }
785       break;
786     case 9: /* NoSize */
787       b->c->flags.b_Size = 1;
788       b->c->minx = b->c->miny = 0;
789       break;
790 
791     case 10: /* Size */
792       i = strtol(s, &t, 10);
793       j = strtol(t, &o, 10);
794       if (t > s && o > t)
795       {
796 	b->c->minx = i;
797 	b->c->miny = j;
798 	b->c->flags.b_Size = 1;
799 	s = o;
800       }
801       else
802 	fprintf(stderr,"%s: Illegal size arguments\n",MyName);
803       break;
804 
805     case 11: /* BoxSize */
806       ParseBoxSize(&s, &b->c->flags);
807       break;
808 
809     case 12: /* Colorset */
810       i = strtol(s, &t, 10);
811       if (t > s)
812       {
813 	b->c->colorset = i;
814 	b->c->flags.b_Colorset = 1;
815 	AllocColorset(i);
816 	s = t;
817       }
818       else
819       {
820 	b->c->flags.b_Colorset = 0;
821       }
822       break;
823 
824     default:
825       t = seekright(&s);
826       fprintf(stderr,"%s: Illegal container option \"%s\"\n",MyName, (t)?t:"");
827       if (t)
828 	free(t);
829     }
830   }
831   if (*s)
832   {
833     s++;
834   }
835   *ss = s;
836 }
837 
838 /**
839 *** ParseButton()
840 ***
841 *** parse a buttonconfig string.
842 *** *FvwmButtons: (option[ options]) title iconname command
843 **/
844 /*#define DEBUG_PARSER*/
ParseButton(button_info ** uberb,char * s)845 static void ParseButton(button_info **uberb, char *s)
846 {
847 	button_info *b, *ub = *uberb;
848 	int i, j;
849 	char *t, *o;
850 
851 	b = alloc_button(ub, (ub->c->num_buttons)++);
852 	s = trimleft(s);
853 
854 	if (*s == '(' && s++)
855 	{
856 		char *opts[] =
857 		{
858 			"back",
859 			"fore",
860 			"font",
861 			"title",
862 			"icon",
863 			"frame",
864 			"padding",
865 			"swallow",
866 			"panel",
867 			"actionignoresclientwindow",
868 			"actiononpress",
869 			"container",
870 			"end",
871 			"nosize",
872 			"size",
873 			"left",
874 			"right",
875 			"center",
876 			"colorset",
877 			"action",
878 			"id",
879 			"activeicon",
880 			"activetitle",
881 			"pressicon",
882 			"presstitle",
883 			"activecolorset",
884 			"presscolorset",
885 			"top",
886 			NULL
887 		};
888 		s = trimleft(s);
889 		while (*s && *s != ')')
890 		{
891 			Bool is_swallow = False;
892 
893 			if (*s == ',')
894 			{
895 				s++;
896 				s = trimleft(s);
897 				continue;
898 			}
899 			if (isdigit(*s) || *s == '+' || *s == '-')
900 			{
901 				char *geom;
902 				int x, y, flags;
903 				unsigned int w, h;
904 				geom = seekright(&s);
905 				if (geom)
906 				{
907 					flags = XParseGeometry(geom, &x, &y, &w, &h);
908 					if (flags&WidthValue)
909 					{
910 						b->BWidth = w;
911 					}
912 					if (flags&HeightValue)
913 					{
914 						b->BHeight = h;
915 					}
916 					if (flags & XValue)
917 					{
918 						b->BPosX = x;
919 						b->flags.b_PosFixed = 1;
920 					}
921 					if (flags & YValue)
922 					{
923 						b->BPosY = y;
924 						b->flags.b_PosFixed = 1;
925 					}
926 					if (flags & XNegative)
927 					{
928 						b->BPosX = -1 - x;
929 					}
930 					if (flags & YNegative)
931 					{
932 						b->BPosY = -1 - y;
933 					}
934 					free(geom);
935 				}
936 				s = trimleft(s);
937 				continue;
938 			}
939 			switch (GetTokenIndex(s, opts, -1, &s))
940 			{
941 			case 0: /* Back */
942 				s = trimleft(s);
943 				if (*s == '(' && s++ && ParseBack(&s))
944 				{
945 					b->flags.b_IconBack = 1;
946 				}
947 				if (b->flags.b_Back && b->back)
948 				{
949 					free(b->back);
950 				}
951 				b->back = seekright(&s);
952 				if (b->back)
953 				{
954 					b->flags.b_Back = 1;
955 				}
956 				else
957 				{
958 					b->flags.b_IconBack = 0;
959 					b->flags.b_Back = 0;
960 				}
961 				break;
962 
963 			case 1: /* Fore */
964 				if (b->flags.b_Fore && b->fore)
965 				{
966 					free(b->fore);
967 				}
968 				b->fore = seekright(&s);
969 				b->flags.b_Fore = (b->fore ? 1 : 0);
970 				break;
971 
972 			case 2: /* Font */
973 				if (b->flags.b_Font && b->font_string)
974 				{
975 					free(b->font_string);
976 				}
977 				b->font_string = my_get_font(&s);
978 				b->flags.b_Font = (b->font_string ? 1 : 0);
979 				break;
980 
981 			/* ----------------- title --------------- */
982 
983 			case 3: /* Title */
984 				s = trimleft(s);
985 				if (*s == '(' && s++)
986 				{
987 					b->justify = 0;
988 					b->justify_mask = 0;
989 					ParseTitle(
990 						&s, &b->justify,
991 						&b->justify_mask);
992 					if (b->justify_mask)
993 					{
994 						b->flags.b_Justify = 1;
995 					}
996 				}
997 				t = seekright(&s);
998 				if (t && *t && (t[0] != '-' || t[1] != 0))
999 				{
1000 					if (b->title)
1001 					{
1002 						free(b->title);
1003 					}
1004 					b->title = t;
1005 #ifdef DEBUG_PARSER
1006 					fprintf(stderr,
1007 						"PARSE: Title \"%s\"\n",
1008 						b->title);
1009 #endif
1010 					b->flags.b_Title = 1;
1011 				}
1012 				else
1013 				{
1014 					fprintf(stderr,
1015 						"%s: Missing title argument\n",
1016 						MyName);
1017 					if (t)
1018 					{
1019 						free(t);
1020 					}
1021 				}
1022 				break;
1023 
1024 			/* ------------------ icon --------------- */
1025 
1026 			case 4: /* Icon */
1027 				t = seekright(&s);
1028 				if (t && *t && (t[0] != '-' || t[1] != 0))
1029 				{
1030 					if (b->flags.b_Swallow)
1031 					{
1032 						fprintf(stderr,
1033 							"%s: a button can not "
1034 							"have an icon and a "
1035 							"swallowed window at "
1036 							"the same time. "
1037 							"Ignoring icon\n",
1038 							MyName);
1039 					}
1040 					else
1041 					{
1042 						if (b->icon_file)
1043 						{
1044 							free(b->icon_file);
1045 						}
1046 						b->icon_file = t;
1047 						b->flags.b_Icon = 1;
1048 					}
1049 				}
1050 				else
1051 				{
1052 					fprintf(stderr,
1053 						"%s: Missing Icon argument\n",
1054 						MyName);
1055 					if (t)
1056 					{
1057 						free(t);
1058 					}
1059 				}
1060 				break;
1061 
1062 			/* ----------------- frame --------------- */
1063 
1064 			case 5: /* Frame */
1065 				i = strtol(s, &t, 10);
1066 				if (t > s)
1067 				{
1068 					b->flags.b_Frame = 1;
1069 					b->framew = i;
1070 					s = t;
1071 				}
1072 				else
1073 				{
1074 					fprintf(stderr,
1075 						"%s: Illegal frame argument\n",
1076 						MyName);
1077 				}
1078 				break;
1079 
1080 			/* ---------------- padding -------------- */
1081 
1082 			case 6: /* Padding */
1083 				i = strtol(s,&t,10);
1084 				if (t>s)
1085 				{
1086 					b->xpad = b->ypad = i;
1087 					b->flags.b_Padding = 1;
1088 					s = t;
1089 					i = strtol(s, &t, 10);
1090 					if (t > s)
1091 					{
1092 						b->ypad = i;
1093 						s = t;
1094 					}
1095 				}
1096 				else
1097 				{
1098 					fprintf(stderr,
1099 						"%s: Illegal padding "
1100 						"argument\n", MyName);
1101 				}
1102 				break;
1103 
1104 			/* ---------------- swallow -------------- */
1105 
1106 			case 7: /* Swallow */
1107 				is_swallow = True;
1108 				/* fall through */
1109 
1110 			case 8: /* Panel */
1111 				s = trimleft(s);
1112 				if (is_swallow)
1113 				{
1114 					b->swallow = 0;
1115 					b->swallow_mask = 0;
1116 				}
1117 				else
1118 				{
1119 					/* set defaults */
1120 					b->swallow = b_Respawn;
1121 					b->swallow_mask = b_Respawn;
1122 					b->slide_direction = SLIDE_UP;
1123 					b->slide_position = SLIDE_POSITION_CENTER;
1124 					b->slide_context = SLIDE_CONTEXT_PB;
1125 					b->relative_x = 0;
1126 					b->relative_y = 0;
1127 					b->slide_steps = 12;
1128 					b->slide_delay_ms = 5;
1129 				}
1130 				if (*s == '(' && s++)
1131 				{
1132 					if (is_swallow)
1133 					{
1134 						ParseSwallow(
1135 							&s, &b->swallow,
1136 							&b->swallow_mask, b);
1137 					}
1138 					else
1139 					{
1140 						ParsePanel(
1141 							&s, &b->swallow,
1142 							&b->swallow_mask,
1143 							&b->slide_direction,
1144 							&b->slide_steps,
1145 							&b->slide_delay_ms,
1146 							&b->panel_flags,
1147 							&b->indicator_size,
1148 							&b->relative_x,
1149 							&b->relative_y,
1150 							&b->slide_position,
1151 							&b->slide_context);
1152 					}
1153 				}
1154 				t = seekright(&s);
1155 				o = seekright(&s);
1156 				if (t)
1157 				{
1158 					if (b->hangon)
1159 					{
1160 						free(b->hangon);
1161 					}
1162 					b->hangon = t;
1163 					if (is_swallow)
1164 					{
1165 						if (b->flags.b_Icon)
1166 						{
1167 							fprintf(stderr,
1168 							"%s: a button can not "
1169 							"have an icon and a "
1170 							"swallowed window at "
1171 							"the same time. "
1172 							"Ignoring icon\n",
1173 							MyName);
1174 							b->flags.b_Icon = 0;
1175 						}
1176 
1177 						b->flags.b_Swallow = 1;
1178 						b->flags.b_Hangon = 1;
1179 					}
1180 					else
1181 					{
1182 						b->flags.b_Panel = 1;
1183 						b->flags.b_Hangon = 1;
1184 						b->newflags.is_panel = 1;
1185 						b->newflags.panel_mapped = 0;
1186 					}
1187 					b->swallow |= 1;
1188 					if (!(b->swallow & b_NoHints))
1189 					{
1190 						b->hints = (XSizeHints*)
1191 						mymalloc(sizeof(XSizeHints));
1192 					}
1193 					if (o)
1194 					{
1195 						char *p;
1196 
1197 						p = module_expand_action(
1198 							Dpy, screen, o, NULL,
1199 							UberButton->c->fore,
1200 							UberButton->c->back);
1201 						if (p)
1202 						{
1203 							if (!(buttonSwallow(b)&b_UseOld))
1204 							{
1205 								exec_swallow(p,b);
1206 							}
1207 							if (b->spawn)
1208 							{
1209 								free(b->spawn);
1210 							}
1211 
1212 							/* Might be needed if
1213 							 * respawning sometime
1214 							 */
1215 							b->spawn = o;
1216 							free(p);
1217 						}
1218 					}
1219 				}
1220 				else
1221 				{
1222 					fprintf(stderr,
1223 						"%s: Missing swallow "
1224 						"argument\n", MyName);
1225 					if (t)
1226 					{
1227 						free(t);
1228 					}
1229 					if (o)
1230 					{
1231 						free(o);
1232 					}
1233 				}
1234 				/* check if it is a module by command line inspection if
1235 				 * this hints has not been given in the swallow option */
1236 				if (is_swallow && !(b->swallow_mask & b_FvwmModule))
1237 				{
1238 					if (b->spawn != NULL &&
1239 					    (strncasecmp(b->spawn, "module", 6) == 0 ||
1240 					     strncasecmp(b->spawn, "fvwm", 4) == 0))
1241 					{
1242 						b->swallow |= b_FvwmModule;
1243 					}
1244 				}
1245 				break;
1246 
1247 			case 9: /* ActionIgnoresClientWindow */
1248 				b->flags.b_ActionIgnoresClientWindow = 1;
1249 				break;
1250 
1251 			case 10: /* ActionOnPress */
1252 				b->flags.b_ActionOnPress = 1;
1253 				break;
1254 
1255 			/* ---------------- container ------------ */
1256 
1257 			case 11: /* Container */
1258 				/*
1259 				 * SS: This looks very buggy! The FvwmButtons
1260 				 * man page suggests it's here to restrict the
1261 				 * options used with "Container", but it only
1262 				 * restricts those options appearing _before_
1263 				 * the "Container" keyword for a button.
1264 				 * b->flags&=b_Frame|b_Back|b_Fore|b_Padding|b_Action;
1265 				 */
1266 
1267 				MakeContainer(b);
1268 				*uberb = b;
1269 				s = trimleft(s);
1270 				if (*s == '(' && s++)
1271 				{
1272 					ParseContainer(&s,b);
1273 				}
1274 				break;
1275 
1276 			case 12: /* End */
1277 				*uberb = ub->parent;
1278 				ub->c->buttons[--(ub->c->num_buttons)] = NULL;
1279 				free(b);
1280 				if (!ub->parent)
1281 				{
1282 					fprintf(stderr,"%s: Unmatched END in config file\n",MyName);
1283 					exit(1);
1284 				}
1285 				if (ub->parent->c->flags.b_Colorset ||
1286 				    ub->parent->c->flags.b_ColorsetParent)
1287 				{
1288 					ub->c->flags.b_ColorsetParent = 1;
1289 				}
1290 				if (ub->parent->c->flags.b_IconBack || ub->parent->c->flags.b_IconParent)
1291 				{
1292 					ub->c->flags.b_IconParent = 1;
1293 				}
1294 				return;
1295 
1296 			case 13: /* NoSize */
1297 				b->flags.b_Size = 1;
1298 				b->minx = b->miny = 0;
1299 				break;
1300 
1301 			case 14: /* Size */
1302 				i = strtol(s, &t, 10);
1303 				j = strtol(t, &o, 10);
1304 				if (t > s && o > t)
1305 				{
1306 					b->minx = i;
1307 					b->miny = j;
1308 					b->flags.b_Size = 1;
1309 					s = o;
1310 				}
1311 				else
1312 				{
1313 					fprintf(stderr,
1314 						"%s: Illegal size arguments\n",
1315 						MyName);
1316 				}
1317 				break;
1318 
1319 			case 15: /* Left */
1320 				b->flags.b_Left = 1;
1321 				b->flags.b_Right = 0;
1322 				break;
1323 
1324 			case 16: /* Right */
1325 				b->flags.b_Right = 1;
1326 				b->flags.b_Left = 0;
1327 				break;
1328 
1329 			case 17: /* Center */
1330 				b->flags.b_Right = 0;
1331 				b->flags.b_Left = 0;
1332 				break;
1333 
1334 			case 18: /* Colorset */
1335 				i = strtol(s, &t, 10);
1336 				if (t > s)
1337 				{
1338 					b->colorset = i;
1339 					b->flags.b_Colorset = 1;
1340 					s = t;
1341 					AllocColorset(i);
1342 				}
1343 				else
1344 				{
1345 					b->flags.b_Colorset = 0;
1346 				}
1347 				break;
1348 
1349 			/* ----------------- action -------------- */
1350 
1351 			case 19: /* Action */
1352 				s = trimleft(s);
1353 				i = 0;
1354 				if (*s == '(')
1355 				{
1356 					s++;
1357 					if (strncasecmp(s, "mouse", 5) != 0)
1358 					{
1359 						fprintf(stderr,
1360 							"%s: Couldn't parse "
1361 							"action\n", MyName);
1362 					}
1363 					s += 5;
1364 					i = strtol(s, &t, 10);
1365 					s = t;
1366 					while (*s && *s != ')')
1367 					{
1368 						s++;
1369 					}
1370 					if (*s == ')')
1371 					{
1372 						s++;
1373 					}
1374 				}
1375 				{
1376 					char *r;
1377 					char *u = s;
1378 
1379 					s = GetQuotedString(s, &t, ",)", NULL, "(", ")");
1380 					r = s;
1381 					if (t && r > u + 1)
1382 					{
1383 						/* remove unquoted trailing spaces */
1384 						r -= 2;
1385 						while (r >= u && isspace(*r))
1386 						{
1387 							r--;
1388 						}
1389 						r++;
1390 						if (isspace(*r))
1391 						{
1392 							t[strlen(t) - (s - r - 1)] = 0;
1393 						}
1394 					}
1395 				}
1396 				if (t)
1397 				{
1398 					AddButtonAction(b,i,t);
1399 					free(t);
1400 				}
1401 				else
1402 				{
1403 					fprintf(stderr,
1404 						"%s: Missing action argument\n",
1405 						MyName);
1406 				}
1407 				break;
1408 
1409 			case 20: /* Id */
1410 				s = trimleft(s);
1411 				s = DoGetNextToken(s, &t, NULL, ",)", &terminator);
1412 
1413 				/* it should include the delimiter */
1414 				if (s && terminator == ')')
1415 				{
1416 					s--;
1417 				}
1418 
1419 				if (t)
1420 				{
1421 					if (isalpha(t[0]))
1422 					{
1423 						/* should check for duplicate ids first... */
1424 						b->flags.b_Id = 1;
1425 						if (b->id)
1426 						{
1427 							free(b->id);
1428 						}
1429 						CopyString(&b->id, t);
1430 					}
1431 			        	else
1432 					{
1433 						fprintf(stderr,
1434 							"%s: Incorrect id '%s' "
1435 							"ignored\n", MyName, t);
1436 					}
1437 					free(t);
1438 				}
1439 				else
1440 				{
1441 					fprintf(stderr,
1442 						"%s: Missing id argument\n",
1443 						MyName);
1444 				}
1445 				break;
1446 
1447 			/* ------------------ ActiveIcon --------------- */
1448 			case 21: /* ActiveIcon */
1449 				t = seekright(&s);
1450 				if (t && *t && (t[0] != '-' || t[1] != 0))
1451 				{
1452 					if (b->flags.b_Swallow)
1453 					{
1454 						fprintf(stderr,
1455 							"%s: a button can not "
1456 							"have a ActiveIcon and "
1457 							"a swallowed window at "
1458 							"the same time. "
1459 							"Ignoring ActiveIcon.\n",
1460 							MyName);
1461 					}
1462 					else
1463 					{
1464 						if (b->active_icon_file)
1465 						{
1466 							free(b->active_icon_file);
1467 						}
1468 						b->active_icon_file = t;
1469 						b->flags.b_ActiveIcon = 1;
1470 					}
1471 				}
1472 				else
1473 				{
1474 					fprintf(stderr,
1475 						"%s: Missing ActiveIcon "
1476 						"argument\n", MyName);
1477 					if (t)
1478 					{
1479 						free(t);
1480 					}
1481 				}
1482 				break;
1483 
1484 			/* --------------- ActiveTitle --------------- */
1485 			case 22: /* ActiveTitle */
1486 				s = trimleft(s);
1487 				if (*s == '(')
1488 				{
1489 					fprintf(stderr,
1490 						"%s: justification not allowed "
1491 						"for ActiveTitle.\n", MyName);
1492 				}
1493 				t = seekright(&s);
1494 				if (t && *t && (t[0] != '-' || t[1] != 0))
1495 				{
1496 					if (b->activeTitle)
1497 					{
1498 						free(b->activeTitle);
1499 					}
1500 					b->activeTitle = t;
1501 #ifdef DEBUG_PARSER
1502 					fprintf(stderr,
1503 						"PARSE: ActiveTitle \"%s\"\n",
1504 						b->activeTitle);
1505 #endif
1506 					b->flags.b_ActiveTitle = 1;
1507 				}
1508 				else
1509 				{
1510 					fprintf(stderr,
1511 						"%s: Missing ActiveTitle "
1512 						"argument\n", MyName);
1513 					if (t)
1514 					{
1515 						free(t);
1516 					}
1517 				}
1518 				break;
1519 
1520 			/* --------------- PressIcon --------------- */
1521 			case 23: /* PressIcon */
1522 				t = seekright(&s);
1523 				if (t && *t && (t[0] != '-' || t[1] != 0))
1524 				{
1525 					if (b->flags.b_Swallow)
1526 					{
1527 						fprintf(stderr,
1528 							"%s: a button can not "
1529 							"have a PressIcon and "
1530 							"a swallowed window at "
1531 							"the same time. "
1532 							"Ignoring PressIcon.\n",
1533 							MyName);
1534 					}
1535 					else
1536 					{
1537 						if (b->press_icon_file)
1538 						{
1539 							free(b->press_icon_file);
1540 						}
1541 						b->press_icon_file = t;
1542 						b->flags.b_PressIcon = 1;
1543 					}
1544 				}
1545 				else
1546 				{
1547 					fprintf(stderr,
1548 						"%s: Missing PressIcon "
1549 						"argument\n", MyName);
1550 					if (t)
1551 					{
1552 						free(t);
1553 					}
1554 				}
1555 				break;
1556 
1557 			/* --------------- PressTitle --------------- */
1558 			case 24: /* PressTitle */
1559 				s = trimleft(s);
1560 				if (*s == '(')
1561 				{
1562 					fprintf(stderr,
1563 						"%s: justification not allowed "
1564 						"for PressTitle.\n", MyName);
1565 				}
1566 				t = seekright(&s);
1567 				if (t && *t && (t[0] != '-' || t[1] != 0))
1568 				{
1569 					if (b->pressTitle)
1570 					{
1571 						free(b->pressTitle);
1572 					}
1573 					b->pressTitle = t;
1574 #ifdef DEBUG_PARSER
1575 					fprintf(stderr,
1576 						"PARSE: PressTitle \"%s\"\n",
1577 						b->pressTitle);
1578 #endif
1579 					b->flags.b_PressTitle = 1;
1580 				}
1581 				else
1582 				{
1583 					fprintf(stderr,
1584 						"%s: Missing PressTitle "
1585 						"argument\n", MyName);
1586 					if (t)
1587 					{
1588 						free(t);
1589 					}
1590 				}
1591 				break;
1592 
1593 			/* --------------- --------------- */
1594 			case 25: /* ActiveColorset */
1595 				i = strtol(s, &t, 10);
1596 				if (t > s)
1597 				{
1598 					b->activeColorset = i;
1599 					b->flags.b_ActiveColorset = 1;
1600 					s = t;
1601 					AllocColorset(i);
1602 				}
1603 				else
1604 				{
1605 					b->flags.b_ActiveColorset = 0;
1606 				}
1607 				break;
1608 
1609 			/* --------------- --------------- */
1610 			case 26: /* PressColorset */
1611 				i = strtol(s, &t, 10);
1612 				if (t > s)
1613 				{
1614 					b->pressColorset = i;
1615 					b->flags.b_PressColorset = 1;
1616 					s = t;
1617 					AllocColorset(i);
1618 				}
1619 				else
1620 				{
1621 					b->flags.b_PressColorset = 0;
1622 				}
1623 				break;
1624 
1625 			case 27: /* top */
1626 				b->flags.b_Top = 1;
1627 				break;
1628 			/* --------------- --------------- */
1629 			default:
1630 				t = seekright(&s);
1631 				fprintf(stderr,
1632 					"%s: Illegal button option \"%s\"\n",
1633 					MyName, (t) ? t : "");
1634 				if (t)
1635 				{
1636 					free(t);
1637 				}
1638 				break;
1639 			} /* end switch */
1640 			s = trimleft(s);
1641 		}
1642 		if (s && *s)
1643 		{
1644 			s++;
1645 			s = trimleft(s);
1646 		}
1647 	}
1648 
1649 	/* get title and iconname */
1650 	if (!b->flags.b_Title)
1651 	{
1652 		b->title = seekright(&s);
1653 		if (b->title && *b->title &&
1654 			((b->title)[0] != '-' || (b->title)[1] != 0))
1655 		{
1656 			b->flags.b_Title = 1;
1657 		}
1658 		else if (b->title)
1659 		{
1660 			free(b->title);
1661 		}
1662 	}
1663 	else
1664 	{
1665 		char *temp;
1666 		temp = seekright(&s);
1667 		if (temp)
1668 		{
1669 			free(temp);
1670 		}
1671 	}
1672 
1673 	if (!b->flags.b_Icon)
1674 	{
1675 		b->icon_file = seekright(&s);
1676 		if (b->icon_file && b->icon_file &&
1677 			 ((b->icon_file)[0] != '-'||(b->icon_file)[1] != 0))
1678 		{
1679 			b->flags.b_Icon = 1;
1680 		}
1681 		else if (b->icon_file)
1682 		{
1683 			free(b->icon_file);
1684 		}
1685 	}
1686 	else
1687 	{
1688 		char *temp;
1689 		temp = seekright(&s);
1690 		if (temp)
1691 		{
1692 			free(temp);
1693 		}
1694 	}
1695 
1696 	s = trimleft(s);
1697 
1698 	/* Swallow hangon command */
1699 	if (strncasecmp(s, "swallow", 7) == 0 || strncasecmp(s, "panel", 7) == 0)
1700 	{
1701 		if (b->flags.b_Swallow || b->flags.b_Panel)
1702 		{
1703 			fprintf(stderr,
1704 				"%s: Illegal with both old and new swallow!\n",
1705 				MyName);
1706 			exit(1);
1707 		}
1708 		s += 7;
1709 		/*
1710 		 * Swallow old 'swallowmodule' command
1711 		 */
1712 		if (strncasecmp(s, "module", 6) == 0)
1713 		{
1714 			s += 6;
1715 		}
1716 		if (b->hangon)
1717 		{
1718 			free(b->hangon);
1719 		}
1720 		b->hangon = seekright(&s);
1721 		if (!b->hangon)
1722 		{
1723 			b->hangon = safestrdup("");
1724 		}
1725 		if (tolower(*s) == 's')
1726 		{
1727 			b->flags.b_Swallow = 1;
1728 			b->flags.b_Hangon = 1;
1729 		}
1730 		else
1731 		{
1732 			b->flags.b_Panel = 1;
1733 			b->flags.b_Hangon = 1;
1734 		}
1735 		b->swallow |= 1;
1736 		s = trimleft(s);
1737 		if (!(b->swallow & b_NoHints))
1738 		{
1739 			b->hints = (XSizeHints*)mymalloc(sizeof(XSizeHints));
1740 		}
1741 		if (*s)
1742 		{
1743 			if (!(buttonSwallow(b) & b_UseOld))
1744 			{
1745 				SendText(fd, s, 0);
1746 			}
1747 			b->spawn = safestrdup(s);
1748 		}
1749 	}
1750 	else if (*s)
1751 	{
1752 		AddButtonAction(b, 0, s);
1753 	}
1754 	return;
1755 }
1756 
1757 /**
1758 *** ParseConfigLine
1759 **/
ParseConfigLine(button_info ** ubb,char * s)1760 static void ParseConfigLine(button_info **ubb, char *s)
1761 {
1762 	button_info *ub = *ubb;
1763 	char *opts[] =
1764 	{
1765 		"geometry",
1766 		"buttongeometry",
1767 		"font",
1768 		"padding",
1769 		"columns",
1770 		"rows",
1771 		"back",
1772 		"fore",
1773 		"frame",
1774 		"file",
1775 		"pixmap",
1776 		"boxsize",
1777 		"colorset",
1778 		"activecolorset",
1779 		"presscolorset",
1780 		NULL
1781 	};
1782 	int i, j, k;
1783 
1784 	switch (GetTokenIndex(s, opts, -1, &s))
1785 	{
1786 	case 0:/* Geometry */
1787 	{
1788 		char geom[64];
1789 
1790 		i = sscanf(s, "%63s", geom);
1791 		if (i == 1)
1792 		{
1793 			parse_window_geometry(geom, 0);
1794 		}
1795 		break;
1796 	}
1797 	case 1:/* ButtonGeometry */
1798 	{
1799 		char geom[64];
1800 
1801 		i = sscanf(s, "%63s", geom);
1802 		if (i == 1)
1803 		{
1804 			parse_window_geometry(geom, 1);
1805 		}
1806 		break;
1807 	}
1808 	case 2:/* Font */
1809 		if (ub->c->font_string)
1810 		{
1811 			free(ub->c->font_string);
1812 		}
1813 		CopyStringWithQuotes(&ub->c->font_string, s);
1814 		break;
1815 	case 3:/* Padding */
1816 		i = sscanf(s, "%d %d", &j, &k);
1817 		if (i > 0)
1818 		{
1819 			ub->c->xpad = ub->c->ypad = j;
1820 		}
1821 		if (i > 1)
1822 		{
1823 			ub->c->ypad = k;
1824 		}
1825 		break;
1826 	case 4:/* Columns */
1827 		i = sscanf(s, "%d", &j);
1828 		if (i > 0)
1829 		{
1830 			ub->c->num_columns = j;
1831 		}
1832 		break;
1833 	case 5:/* Rows */
1834 		i = sscanf(s, "%d", &j);
1835 		if (i > 0)
1836 		{
1837 			ub->c->num_rows = j;
1838 		}
1839 		break;
1840 	case 6:/* Back */
1841 		if (ub->c->back)
1842 		{
1843 			free(ub->c->back);
1844 		}
1845 		CopyString(&(ub->c->back), s);
1846 		break;
1847 	case 7:/* Fore */
1848 		if (ub->c->fore)
1849 		{
1850 			free(ub->c->fore);
1851 		}
1852 		CopyString(&(ub->c->fore), s);
1853 		break;
1854 	case 8:/* Frame */
1855 		i = sscanf(s,"%d",&j);
1856 		if (i > 0)
1857 		{
1858 			ub->c->framew = j;
1859 		}
1860 		break;
1861 	case 9:/* File */
1862 		s = trimleft(s);
1863 		if (config_file)
1864 		{
1865 			free(config_file);
1866 		}
1867 		config_file = seekright(&s);
1868 		break;
1869 	case 10:/* Pixmap */
1870 		s = trimleft(s);
1871 		if (strncasecmp(s, "none", 4) == 0)
1872 		{
1873 			ub->c->flags.b_TransBack = 1;
1874 		}
1875 		else
1876 		{
1877 			if (ub->c->back_file)
1878 			{
1879 				free(ub->c->back_file);
1880 			}
1881 			CopyString(&(ub->c->back_file),s);
1882 		}
1883 		ub->c->flags.b_IconBack = 1;
1884 		break;
1885 	case 11: /* BoxSize */
1886 		ParseBoxSize(&s, &ub->c->flags);
1887 		break;
1888 	case 12: /* Colorset */
1889 		i = sscanf(s, "%d", &j);
1890 		if (i > 0)
1891 		{
1892 			ub->c->colorset = j;
1893 			ub->c->flags.b_Colorset = 1;
1894 			AllocColorset(j);
1895 		}
1896 		else
1897 		{
1898 			ub->c->flags.b_Colorset = 0;
1899 		}
1900 		break;
1901 	case 13: /* ActiveColorset */
1902 		i = sscanf(s, "%d", &j);
1903 		if (i > 0)
1904 		{
1905 			ub->c->activeColorset = j;
1906 			ub->c->flags.b_ActiveColorset = 1;
1907 			AllocColorset(j);
1908 		}
1909 		else
1910 		{
1911 			ub->c->flags.b_ActiveColorset = 0;
1912 		}
1913 		break;
1914 	case 14: /* PressColorset */
1915 		i = sscanf(s, "%d", &j);
1916 		if (i > 0)
1917 		{
1918 			ub->c->pressColorset = j;
1919 			ub->c->flags.b_PressColorset = 1;
1920 			AllocColorset(j);
1921 		}
1922 		else
1923 		{
1924 			ub->c->flags.b_PressColorset = 0;
1925 		}
1926 		break;
1927 
1928 	default:
1929 		s = trimleft(s);
1930 		ParseButton(ubb, s);
1931 		break;
1932 	}
1933 }
1934 
1935 /**
1936 *** ParseConfigFile()
1937 *** Parses optional separate configuration file for FvwmButtons
1938 **/
ParseConfigFile(button_info * ub)1939 static void ParseConfigFile(button_info *ub)
1940 {
1941 	char s[1024], *t;
1942 	FILE *f = fopen(config_file, "r");
1943 	int l;
1944 	if (!f)
1945 	{
1946 		fprintf(stderr,
1947 			"%s: Couldn't open config file %s\n", MyName,
1948 			config_file);
1949 		return;
1950 	}
1951 
1952 	while (fgets(s, 1023, f))
1953 	{
1954 		/* Allow for line continuation: */
1955 		while ((l = strlen(s)) < sizeof(s)
1956 			&& l >= 2 && s[l - 1] == '\n' && s[l - 2] == '\\')
1957 		{
1958 			char *p;
1959 
1960 			p = fgets(s + l - 2, sizeof(s) - l, f);
1961 			(void)p;
1962 		}
1963 
1964 		/* And comments: */
1965 		t = s;
1966 		while (*t)
1967 		{
1968 			if (*t == '#' && (t == s || *(t - 1) != '\\'))
1969 			{
1970 				*t = 0;
1971 				break;
1972 			}
1973 			t++;
1974 		}
1975 		t = s;
1976 		t = trimleft(t);
1977 		if (*t)
1978 		{
1979 			ParseConfigLine(&ub, t);
1980 		}
1981 	}
1982 
1983 	fclose(f);
1984 }
1985 
parse_window_geometry(char * geom,int is_button_geometry)1986 void parse_window_geometry(char *geom, int is_button_geometry)
1987 {
1988 	int flags;
1989 	int g_x;
1990 	int g_y;
1991 	unsigned int width;
1992 	unsigned int height;
1993 
1994 	flags = FScreenParseGeometry(geom, &g_x, &g_y, &width, &height);
1995 	UberButton->w = 0;
1996 	UberButton->h = 0;
1997 	UberButton->x = 0;
1998 	UberButton->y = 0;
1999 	if (is_button_geometry)
2000 	{
2001 		if (flags&WidthValue)
2002 		{
2003 			button_width = width;
2004 		}
2005 		if (flags&HeightValue)
2006 		{
2007 			button_height = height;
2008 		}
2009 	}
2010 	else
2011 	{
2012 		if (flags&WidthValue)
2013 		{
2014 			w = width;
2015 		}
2016 		if (flags&HeightValue)
2017 		{
2018 			h = height;
2019 		}
2020 	}
2021 	if (flags&XValue)
2022 	{
2023 		UberButton->x = g_x;
2024 	}
2025 	if (flags&YValue)
2026 	{
2027 		UberButton->y = g_y;
2028 	}
2029 	if (flags&XNegative)
2030 	{
2031 		UberButton->w = 1;
2032 	}
2033 	if (flags&YNegative)
2034 	{
2035 		UberButton->h = 1;
2036 	}
2037 	has_button_geometry = is_button_geometry;
2038 
2039 	return;
2040 }
2041 
2042 /**
2043 *** ParseOptions()
2044 **/
ParseConfiguration(button_info * ub)2045 void ParseConfiguration(button_info *ub)
2046 {
2047 	char *s;
2048 	char *items[] =
2049 	{
2050 		NULL, /* filled out below */
2051 		"imagepath",
2052 		"colorset",
2053 		XINERAMA_CONFIG_STRING,
2054 		NULL
2055 	};
2056 
2057 	items[0] = mymalloc(strlen(MyName) + 2);
2058 	sprintf(items[0], "*%s", MyName);
2059 
2060 	/* send config lines with MyName */
2061 	InitGetConfigLine(fd, items[0]);
2062 	GetConfigLine(fd, &s);
2063 	while (s && s[0])
2064 	{
2065 		char *rest;
2066 		switch (GetTokenIndex(s,items,-1,&rest))
2067 		{
2068 		case -1:
2069 			break;
2070 		case 0:
2071 			if (rest && rest[0] && !config_file)
2072 			{
2073 				ParseConfigLine(&ub, rest);
2074 			}
2075 			break;
2076 		case 1:
2077 			if (imagePath)
2078 			{
2079 				free(imagePath);
2080 			}
2081 			CopyString(&imagePath, rest);
2082 			break;
2083 		case 2:
2084 			/* store colorset sent by fvwm */
2085 			LoadColorset(rest);
2086 			break;
2087 		case 3:
2088 			/* Xinerama state */
2089 			FScreenConfigureModule(rest);
2090 			break;
2091 		}
2092 		GetConfigLine(fd,&s);
2093 	}
2094 
2095 	if (config_file)
2096 	{
2097 		ParseConfigFile(ub);
2098 	}
2099 
2100 	free(items[0]);
2101 	return;
2102 }
2103