1 /* -*-c-*- */
2 /* FvwmForm is original work of Thomas Zuwei Feng.
3  *
4  * Copyright Feb 1995, Thomas Zuwei Feng.  No guarantees or warantees are
5  * provided or implied in any way whatsoever.  Use this program at your own
6  * risk.  Permission to use, modify, and redistribute this program is hereby
7  * given, provided that this copyright is kept intact. */
8 
9 /* This program is free software; you can redistribute it and/or modify
10  * it under the terms of the GNU General Public License as published by
11  * the Free Software Foundation; either version 2 of the License, or
12  * (at your option) any later version.
13  *
14  * This program is distributed in the hope that it will be useful,
15  * but WITHOUT ANY WARRANTY; without even the implied warranty of
16  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.	 See the
17  * GNU General Public License for more details.
18  *
19  * You should have received a copy of the GNU General Public License
20  * along with this program; if not, see: <http://www.gnu.org/licenses/>
21  */
22 
23 #include "config.h"
24 
25 #include <stdio.h>
26 #include <ctype.h>
27 #include <event2/event.h>
28 
29 #include "libs/ftime.h"
30 #include <fcntl.h>
31 
32 #include "libs/FRender.h"
33 #include "libs/Module.h"		/* for headersize, etc. */
34 #include "libs/fvwmlib.h"
35 #include "libs/fvwmsignal.h"
36 #include "libs/ColorUtils.h"
37 #include "libs/Cursor.h"
38 #include "libs/envvar.h"
39 #include "libs/Graphics.h"
40 #include "libs/Parse.h"
41 #include "libs/Strings.h"
42 #include "libs/System.h"
43 #include "libs/XError.h"
44 #include "libs/FEvent.h"
45 
46 #include "libs/Flocale.h"               /* for font definition stuff */
47 #include "libs/PictureBase.h"		 /* for PictureInitCMap */
48 #include "libs/Colorset.h"
49 #include "libs/FScreen.h"
50 #include "libs/FShape.h"
51 #include "libs/FRenderInit.h"
52 #include "libs/Rectangles.h"
53 
54 #include "FvwmForm.h"			/* common FvwmForm stuff */
55 
56 /* globals that are exported, keep in sync with externs in FvwmForm.h */
57 Form cur_form;			 /* current form */
58 
59 /* Link list roots */
60 Item *root_item_ptr;		 /* pointer to root of item list */
61 Line root_line = {&root_line,	 /* ->next */
62 		  0,		 /* number of items */
63 		  L_CENTER,0,0,	 /* justify, size x/y */
64 		  0,		 /* current array size */
65 		  0};		 /* items ptr */
66 Line *cur_line = &root_line;		/* curr line in parse rtns */
67 char preload_yorn='n';		 /* init to non-preload */
68 Item *item;				/* current during parse */
69 Item *cur_sel, *cur_button;		/* current during parse */
70 Item *timer = NULL;			/* timeout tracking */
71 Display *dpy;
72 Atom wm_del_win;
73 int fd_x;		   /* fd for X connection */
74 Window root, ref;
75 int screen;
76 char *color_names[4];
77 char bg_state = 'd';			/* in default state */
78   /* d = default state */
79   /* s = set by command (must be in "d" state for first "back" cmd to set it) */
80   /* u = used (color allocated, too late to accept "back") */
81 char endDefaultsRead = 'n';
82 char *font_names[4];
83 char *screen_background_color;
84 char *mname;
85 static ModuleArgs *module;
86 int Channel[2];
87 Bool Swallowed = False;
88 
89 /* Font/color stuff
90    The colors are:
91    . defaults are changed by commands during parse
92    . copied into items during parse
93    . displayed in the customization dialog
94    */
95 int colorset = -1;
96 int itemcolorset = 0;
97 
98 /* global not exported */
99 const struct timeval tv_100ms = {0L, 100000L};
100 static struct event *pev;
101 
102 /* prototypes */
103 static void RedrawSeparator(Item *item);
104 static void AssignDrawTable(Item *);
105 static void AddItem(void);
106 static void PutDataInForm(char *);
107 static void ReadFormData(void);
108 static void FormVarsCheck(char **);
109 static void TimerHandler(evutil_socket_t, short int, void *);
110 static int ErrorHandler(Display *dpy, XErrorEvent *error_event);
SetupTimer(void)111 static void SetupTimer(void)
112 {
113   struct event_base *pevbase = event_base_new();
114 
115   pev = event_new(pevbase, -1, EV_PERSIST, TimerHandler, NULL);
116 
117   evtimer_add(pev, &tv_100ms);
118   event_base_dispatch(pevbase);
119 }
120 
121 /* copy a string until '"', or '\n', or '\0' */
CopyQuotedString(char * cp)122 static char *CopyQuotedString (char *cp)
123 {
124   char *dp, *bp, c;
125   bp = dp = fxmalloc(strlen(cp) + 1);
126   while (1) {
127     switch (c = *(cp++)) {
128     case '\\':
129       *(dp++) = *(cp++);
130       break;
131     case '\"':
132     case '\n':
133     case '\0':
134       *dp = '\0';
135       return bp;
136       break;
137     default:
138       *(dp++) = c;
139       break;
140     }
141   }
142 }
143 
144 /* copy a string until the first space */
CopySolidString(char * cp)145 static char *CopySolidString (char *cp)
146 {
147   char *dp, *bp, c;
148   bp = dp = fxmalloc(strlen(cp) + 1);
149   while (1) {
150     c = *(cp++);
151     if (c == '\\') {
152       *(dp++) = '\\';
153       *(dp++) = *(cp++);
154     } else if (isspace((unsigned char)c) || c == '\0') {
155       *dp = '\0';
156       return bp;
157     } else
158       *(dp++) = c;
159   }
160 }
161 
162 /* Command parsing section */
163 
164 /* FvwmAnimate++ type command table */
165 typedef struct CommandTable
166 {
167   char *name;
168   void (*function)(char *);
169 } ct;
170 static void ct_ActivateOnPress(char *);
171 static void ct_Back(char *);
172 static void ct_Button(char *);
173 static void ct_ButtonFont(char *);
174 static void ct_ButtonInPointer(char *);
175 static void ct_ButtonInPointerBack(char *);
176 static void ct_ButtonInPointerFore(char *);
177 static void ct_ButtonPointer(char *);
178 static void ct_ButtonPointerBack(char *);
179 static void ct_ButtonPointerFore(char *);
180 static void ct_Choice(char *);
181 static void ct_Command(char *);
182 static void ct_Font(char *);
183 static void ct_Fore(char *);
184 static void ct_GrabServer(char *);
185 static void ct_Input(char *);
186 static void ct_InputFont(char *);
187 static void ct_ItemBack(char *);
188 static void ct_ItemFore(char *);
189 static void ct_Line(char *);
190 static void ct_Message(char *);
191 static void ct_Geometry(char *);
192 static void ct_Position(char *);
193 static void ct_Read(char *);
194 static void ct_Selection(char *);
195 static void ct_Separator(char *);
196 static void ct_Text(char *);
197 static void ct_InputPointer(char *);
198 static void ct_InputPointerBack(char *);
199 static void ct_InputPointerFore(char *);
200 static void ct_Timeout(char *);
201 static void ct_TimeoutFont(char *);
202 static void ct_Title(char *);
203 static void ct_UseData(char *);
204 static void ct_padVText(char *);
205 static void ct_WarpPointer(char *);
206 static void ct_Colorset(char *);
207 static void ct_ItemColorset(char *);
208 
209 /* Must be in Alphabetic order (caseless) */
210 static struct CommandTable ct_table[] =
211 {
212   {"ActivateOnPress",ct_ActivateOnPress},
213   {"Back",ct_Back},
214   {"Button",ct_Button},
215   {"ButtonFont",ct_ButtonFont},
216   {"ButtonInPointer",ct_ButtonInPointer},
217   {"ButtonInPointerBack",ct_ButtonInPointerBack},
218   {"ButtonInPointerFore",ct_ButtonInPointerFore},
219   {"ButtonPointer",ct_ButtonPointer},
220   {"ButtonPointerBack",ct_ButtonPointerBack},
221   {"ButtonPointerFore",ct_ButtonPointerFore},
222   {"Choice",ct_Choice},
223   {"Colorset",ct_Colorset},
224   {"Command",ct_Command},
225   {"Font",ct_Font},
226   {"Fore",ct_Fore},
227   {"Geometry",ct_Geometry},
228   {"GrabServer",ct_GrabServer},
229   {"Input",ct_Input},
230   {"InputFont",ct_InputFont},
231   {"InputPointer",ct_InputPointer},
232   {"InputPointerBack",ct_InputPointerBack},
233   {"InputPointerFore",ct_InputPointerFore},
234   {"ItemBack",ct_ItemBack},
235   {"ItemColorset",ct_ItemColorset},
236   {"ItemFore",ct_ItemFore},
237   {"Line",ct_Line},
238   {"Message",ct_Message},
239   {"PadVText",ct_padVText},
240   {"Position",ct_Position},
241   {"Selection",ct_Selection},
242   {"Separator",ct_Separator},
243   {"Text",ct_Text},
244   {"Timeout",ct_Timeout},
245   {"TimeoutFont",ct_TimeoutFont},
246   {"Title",ct_Title},
247   {"UseData",ct_UseData},
248   {"WarpPointer",ct_WarpPointer}
249 };
250 /* These commands are the default setting commands,
251    read before the other form defining commands. */
252 static struct CommandTable def_table[] =
253 {
254   {"ActivateOnPress",ct_ActivateOnPress},
255   {"Back",ct_Back},
256   {"ButtonFont",ct_ButtonFont},
257   {"ButtonInPointer",ct_ButtonInPointer},
258   {"ButtonInPointerBack",ct_ButtonInPointerBack},
259   {"ButtonInPointerFore",ct_ButtonInPointerFore},
260   {"ButtonPointer",ct_ButtonPointer},
261   {"ButtonPointerBack",ct_ButtonPointerBack},
262   {"ButtonPointerFore",ct_ButtonPointerFore},
263   {"Colorset",ct_Colorset},
264   {"Font",ct_Font},
265   {"Fore",ct_Fore},
266   {"InputFont",ct_InputFont},
267   {"InputPointer",ct_InputPointer},
268   {"InputPointerBack",ct_InputPointerBack},
269   {"InputPointerFore",ct_InputPointerFore},
270   {"ItemBack",ct_ItemBack},
271   {"ItemColorset",ct_ItemColorset},
272   {"ItemFore",ct_ItemFore},
273   {"Read",ct_Read},
274   {"TimeoutFont",ct_TimeoutFont}
275 };
276 
277 /* If there were vars on the command line, do env var sustitution on
278    all input. */
FormVarsCheck(char ** p)279 static void FormVarsCheck(char **p)
280 {
281   if (CF.have_env_var) {		/* if cmd line vars */
282     if (strlen(*p) + 200 > CF.expand_buffer_size) { /* fast and loose */
283       CF.expand_buffer_size = strlen(*p) + 2000; /* new size */
284       if (CF.expand_buffer) {		/* already have one */
285 	CF.expand_buffer = fxrealloc(CF.expand_buffer, CF.expand_buffer_size,
286 			sizeof(CF.expand_buffer));
287       } else {				/* first time */
288 	CF.expand_buffer = fxmalloc(CF.expand_buffer_size);
289       }
290     }
291     strcpy(CF.expand_buffer,*p);
292     *p = CF.expand_buffer;
293     envExpand(*p,CF.expand_buffer_size); /* expand the command in place */
294   }
295 }
296 
ParseDefaults(char * buf)297 static void ParseDefaults(char *buf)
298 {
299   char *p;
300   struct CommandTable *e;
301   if (buf[strlen(buf)-1] == '\n') {	/* if line ends with newline */
302     buf[strlen(buf)-1] = '\0';	/* strip off \n */
303   }
304   /* Accept commands beginning with "*FvwmFormDefault".
305      This is to make sure defaults are read first.
306      Note the hack w. bg_state. */
307   if (strncasecmp(buf, "*FvwmFormDefault", 16) == 0) {
308     p=buf+16;
309     FormVarsCheck(&p);			 /* do var substitution if called for */
310     e = FindToken(p,def_table,struct CommandTable);/* find cmd in table */
311     if (e != 0) {			/* if its valid */
312       p=p+strlen(e->name);		/* skip over name */
313       while (isspace((unsigned char)*p)) p++;	       /* skip whitespace */
314       e->function(p);			/* call cmd processor */
315       bg_state = 'd';			/* stay in default state */
316     }
317   }
318 } /* end function */
319 
320 
ParseConfigLine(char * buf)321 static void ParseConfigLine(char *buf)
322 {
323   char *p;
324   struct CommandTable *e;
325   if (buf[strlen(buf)-1] == '\n') {	/* if line ends with newline */
326     buf[strlen(buf)-1] = '\0';	/* strip off \n */
327   }
328 
329 #if 0
330   if (strncasecmp(buf, XINERAMA_CONFIG_STRING,
331 		  sizeof(XINERAMA_CONFIG_STRING)-1) == 0)
332   {
333     FScreenConfigureModule(buf + sizeof(XINERAMA_CONFIG_STRING)-1);
334     return;
335   }
336 #endif
337   if (strncasecmp(buf, "Colorset", 8) == 0) {
338     LoadColorset(&buf[8]);
339     return;
340   }
341   if (strncasecmp(buf, mname, module->namelen+1) != 0) {/* If its not for me */
342     return;
343   } /* Now I know its for me. */
344   p = buf+module->namelen+1;		      /* jump to end of my name */
345   /* at this point we have recognized "*FvwmForm" */
346   FormVarsCheck(&p);
347   e = FindToken(p,ct_table,struct CommandTable);/* find cmd in table */
348   if (e == 0) {			      /* if no match */
349     fprintf(stderr,"%s: unknown command: %s\n",module->name,buf);
350     return;
351   }
352 
353   p=p+strlen(e->name);			/* skip over name */
354   while (isspace((unsigned char)*p)) p++;	       /* skip whitespace */
355 
356   FormVarsCheck(&p);			 /* do var substitution if called for */
357 
358   e->function(p);			/* call cmd processor */
359   return;
360 } /* end function */
361 
362 /* Expands item array */
ExpandArray(Line * this_line)363 static void ExpandArray(Line *this_line)
364 {
365   if (this_line->n + 1 >= this_line->item_array_size) { /* no empty space */
366     this_line->item_array_size += ITEMS_PER_EXPANSION; /* get bigger */
367     this_line->items =
368       fxrealloc((void *)this_line->items,
369                (sizeof(Item *) * this_line->item_array_size),
370 	       sizeof(this_line->items));
371   } /* end array full */
372 }
373 
374 /* Function to add an item to the current line */
AddToLine(Item * newItem)375 static void AddToLine(Item *newItem)
376 {
377   ExpandArray(cur_line);		/* expand item array if needed */
378   cur_line->items[cur_line->n++] = newItem; /* add to lines item array */
379   cur_line->size_x += newItem->header.size_x; /* incr lines width */
380   if (cur_line->size_y < newItem->header.size_y) { /* new item bigger */
381     cur_line->size_y = newItem->header.size_y; /* then line is bigger */
382   }
383 }
384 
385 
386 /* All the functions starting with "ct_" (command table) are called thru
387    their function pointers. Arg 1 is always the rest of the command. */
ct_ActivateOnPress(char * cp)388 static void ct_ActivateOnPress(char *cp)
389 {
390   /* arg can be "on", "off", "0", 1", "true", "false", "" */
391   char option[6];
392   int i,j;
393   if (strlen(cp) > 5) {
394     fprintf(stderr,"%s: arg for ActivateOnPress (%s) too long\n",
395 	    module->name,cp);
396     return;
397   }
398   for (i=0,j=0;i<strlen(cp);i++) {
399     if (cp[i] != ' ') {			  /* remove any spaces */
400       option[j++]=tolower(cp[i]);
401     }
402   }
403   option[j]=0;
404   if (strcmp(option,"on") == 0
405       || strcmp(option,"true") == 0
406       || strcmp(option,"1") == 0
407       || (cp == 0 || strcmp(option,"")) == 0) {
408     CF.activate_on_press = 1;
409   } else if (strcmp(option,"off") == 0
410 	     || strcmp(option,"false") == 0
411 	     || strcmp(option,"0") == 0) {
412     CF.activate_on_press = 0;
413   } else {
414     fprintf(stderr,"%s: arg for ActivateOnPress (%s/%s) invalid\n",
415 	    module->name,option,cp);
416   }
417 }
ct_GrabServer(char * cp)418 static void ct_GrabServer(char *cp)
419 {
420   CF.grab_server = 1;
421 }
ct_WarpPointer(char * cp)422 static void ct_WarpPointer(char *cp)
423 {
424   CF.warp_pointer = 1;
425 }
ct_Position(char * cp)426 static void ct_Position(char *cp)
427 {
428   CF.have_geom = 1;
429   CF.gx = atoi(cp);
430   CF.xneg = 0;
431   if (CF.gx < 0)
432   {
433     CF.gx = -1 - CF.gx;
434     CF.xneg = 1;
435   }
436   while (!isspace((unsigned char)*cp)) cp++;
437   while (isspace((unsigned char)*cp)) cp++;
438   CF.gy = atoi(cp);
439   CF.yneg = 0;
440   if (CF.gy < 0)
441   {
442     CF.gy = -1 - CF.gy;
443     CF.yneg = 1;
444   }
445   myfprintf((stderr, "Position @ (%c%d%c%d)\n",
446 	     (CF.xneg)?'-':'+',CF.gx, (CF.yneg)?'-':'+',CF.gy));
447 }
ct_Geometry(char * cp)448 static void ct_Geometry(char *cp)
449 {
450   int x = 0;
451   int y = 0;
452   int flags;
453   unsigned int dummy;
454 
455   CF.gx = 0;
456   CF.gy = 0;
457   CF.xneg = 0;
458   CF.yneg = 0;
459   while (isspace(*cp))
460     cp++;
461   flags = FScreenParseGeometry(cp, &x, &y, &dummy, &dummy);
462   if (flags&XValue)
463   {
464     CF.have_geom = 1;
465     CF.gx = x;
466     CF.xneg = (flags&XNegative);
467   }
468   if (flags&YValue)
469   {
470     CF.have_geom = 1;
471     CF.gy = y;
472     CF.yneg = (flags&YNegative);
473   }
474   myfprintf((stderr, "Geometry @ (%c%d%c%d)\n",
475 	     (CF.xneg)?'-':'+',CF.gx, (CF.yneg)?'-':'+',CF.gy));
476 }
ct_Fore(char * cp)477 static void ct_Fore(char *cp)
478 {
479   if (color_names[c_fg])
480     free(color_names[c_fg]);
481   color_names[c_fg] = fxstrdup(cp);
482   colorset = -1;
483   myfprintf((stderr, "ColorFore: %s\n", color_names[c_fg]));
484 }
ct_Back(char * cp)485 static void ct_Back(char *cp)
486 {
487   if (color_names[c_bg])
488     free(color_names[c_bg]);
489   color_names[c_bg] = fxstrdup(cp);
490   if (bg_state == 'd')
491   {
492     if (screen_background_color)
493       free(screen_background_color);
494     screen_background_color = fxstrdup(color_names[c_bg]);
495     bg_state = 's';			/* indicate set by command */
496   }
497   colorset = -1;
498   myfprintf((stderr, "ColorBack: %s, screen background %s, bg_state %c\n",
499 	     color_names[c_bg],screen_background_color,(int)bg_state));
500 }
ct_Colorset(char * cp)501 static void ct_Colorset(char *cp)
502 {
503   sscanf(cp, "%d", &colorset);
504   AllocColorset(colorset);
505 }
ct_ItemFore(char * cp)506 static void ct_ItemFore(char *cp)
507 {
508   if (color_names[c_item_fg])
509     free(color_names[c_item_fg]);
510   color_names[c_item_fg] = fxstrdup(cp);
511   itemcolorset = -1;
512   myfprintf((stderr, "ColorItemFore: %s\n", color_names[c_item_fg]));
513 }
ct_ItemBack(char * cp)514 static void ct_ItemBack(char *cp)
515 {
516   if (color_names[c_item_bg])
517     free(color_names[c_item_bg]);
518   color_names[c_item_bg] = fxstrdup(cp);
519   itemcolorset = -1;
520   myfprintf((stderr, "ColorItemBack: %s\n", color_names[c_item_bg]));
521 }
ct_ItemColorset(char * cp)522 static void ct_ItemColorset(char *cp)
523 {
524   sscanf(cp, "%d", &itemcolorset);
525   AllocColorset(itemcolorset);
526 }
ct_Font(char * cp)527 static void ct_Font(char *cp)
528 {
529   if (font_names[f_text])
530     free(font_names[f_text]);
531   CopyStringWithQuotes(&font_names[f_text], cp);
532   myfprintf((stderr, "Font: %s\n", font_names[f_text]));
533 }
ct_TimeoutFont(char * cp)534 static void ct_TimeoutFont(char *cp)
535 {
536   if (font_names[f_timeout])
537     free(font_names[f_timeout]);
538   CopyStringWithQuotes(&font_names[f_timeout], cp);
539   myfprintf((stderr, "TimeoutFont: %s\n", font_names[f_timeout]));
540 }
ct_ButtonFont(char * cp)541 static void ct_ButtonFont(char *cp)
542 {
543   if (font_names[f_button])
544     free(font_names[f_button]);
545   CopyStringWithQuotes(&font_names[f_button], cp);
546   myfprintf((stderr, "ButtonFont: %s\n", font_names[f_button]));
547 }
ct_ButtonInPointer(char * cp)548 static void ct_ButtonInPointer(char *cp)
549 {
550   int cursor;
551   cursor=fvwmCursorNameToIndex(cp);
552   if (cursor == -1) {
553     fprintf(stderr,"ButtonInPointer: invalid cursor name %s\n",cp);
554   } else {
555     CF.pointer[button_in_pointer] = XCreateFontCursor(dpy,cursor);
556   }
557 }
ct_ButtonPointer(char * cp)558 static void ct_ButtonPointer(char *cp)
559 {
560   int cursor;
561   cursor=fvwmCursorNameToIndex(cp);
562   if (cursor == -1) {
563     fprintf(stderr,"ButtonPointer: invalid cursor name %s\n",cp);
564   } else {
565     CF.pointer[button_pointer] = XCreateFontCursor(dpy,cursor);
566   }
567 }
ct_InputFont(char * cp)568 static void ct_InputFont(char *cp)
569 {
570   if (font_names[f_input])
571     free(font_names[f_input]);
572   CopyStringWithQuotes(&font_names[f_input], cp);
573   myfprintf((stderr, "InputFont: %s\n", font_names[f_input]));
574 }
ct_InputPointer(char * cp)575 static void ct_InputPointer(char *cp)
576 {
577   int cursor;
578   cursor=fvwmCursorNameToIndex(cp);
579   if (cursor == -1) {
580     fprintf(stderr,"InputPointer: invalid cursor name %s\n",cp);
581   } else {
582     CF.pointer[input_pointer] = XCreateFontCursor(dpy,cursor);
583   }
584 }
585 /* process buttons using an index to the ___ array */
586 static void color_arg(Ptr_color *color_cell, char *color_name);
color_arg(Ptr_color * color_cell,char * color_name)587 static void color_arg(Ptr_color *color_cell, char *color_name) {
588   if (color_name && *color_name) {
589     color_cell->pointer_color.pixel = GetColor(color_name);
590     color_cell->used=1;
591   }
592 }
593 
594 /* arg is a color name, alloc the color */
ct_ButtonInPointerBack(char * cp)595 static void ct_ButtonInPointerBack(char *cp) {
596   color_arg(&CF.p_c[button_in_back],cp);
597 }
ct_ButtonInPointerFore(char * cp)598 static void ct_ButtonInPointerFore(char *cp) {
599   color_arg(&CF.p_c[button_in_fore],cp);
600 }
ct_ButtonPointerBack(char * cp)601 static void ct_ButtonPointerBack(char *cp) {
602   color_arg(&CF.p_c[button_back],cp);
603 }
ct_ButtonPointerFore(char * cp)604 static void ct_ButtonPointerFore(char *cp) {
605   color_arg(&CF.p_c[button_fore],cp);
606 }
ct_InputPointerBack(char * cp)607 static void ct_InputPointerBack(char *cp) {
608   color_arg(&CF.p_c[input_back],cp);
609 }
ct_InputPointerFore(char * cp)610 static void ct_InputPointerFore(char *cp) {
611   color_arg(&CF.p_c[input_fore],cp);
612 }
613 
ct_Line(char * cp)614 static void ct_Line(char *cp)
615 {
616   /* malloc new line */
617   cur_line->next = fxmalloc(sizeof(struct _line));
618   memset(cur_line->next, 0, sizeof(struct _line));
619   cur_line = cur_line->next;		/* new current line */
620   cur_line->next = &root_line;		/* new next ptr, (actually root) */
621 
622   if (strncasecmp(cp, "left", 4) == 0)
623     cur_line->justify = L_LEFT;
624   else if (strncasecmp(cp, "right", 5) == 0)
625     cur_line->justify = L_RIGHT;
626   else if (strncasecmp(cp, "center", 6) == 0)
627     cur_line->justify = L_CENTER;
628   else
629     cur_line->justify = L_LEFTRIGHT;
630 }
631 /* Define an area on the form that contains the current
632    fvwm error message.
633    syntax: *FFMessage Length nn, Font fn, Fore color, Back color
634    len default is 70
635    font,fg.bg default to text.
636   */
637 
ct_Message(char * cp)638 static void ct_Message(char *cp)
639 {
640   AddItem();
641   bg_state = 'u';			/* indicate b/g color now used. */
642   item->type = I_TEXT;
643   /* Item now added to list of items, now it needs a pointer
644      to the correct DrawTable. */
645   AssignDrawTable(item);
646   item->header.name = "FvwmMessage";	/* No purpose to this? dje */
647   item->text.value = fxmalloc(80);	/* point at last error recvd */
648   item->text.n = 80;
649   strcpy(item->text.value,"A mix of chars. MM20"); /* 20 mixed width chars */
650   item->header.size_x = (FlocaleTextWidth(item->header.dt_ptr->dt_Ffont,
651 					  item->text.value,
652 					  item->text.n/4) * 4) + 2 * TEXT_SPC;
653   item->header.size_y = item->header.dt_ptr->dt_Ffont->height
654     + CF.padVText;
655   memset(item->text.value,' ',80);	/* Clear it out */
656   myfprintf((stderr, "Message area [%d, %d]\n",
657 	     item->header.size_x, item->header.size_y));
658   AddToLine(item);
659   CF.last_error = item;			/* save location of message item */
660 }
661 
662 /* allocate colors and fonts needed */
CheckAlloc(Item * this_item,DrawTable * dt)663 static void CheckAlloc(Item *this_item,DrawTable *dt)
664 {
665   XGCValues xgcv;
666   int xgcv_mask = GCForeground;
667 
668   if (dt->dt_used == 2) {		/* fonts colors shadows */
669     return;
670   }
671   if (dt->dt_used == 0) {		/* if nothing allocated */
672     dt->dt_colors[c_fg] = (colorset < 0)
673       ? GetColor(dt->dt_color_names[c_fg])
674       : Colorset[colorset].fg;
675     dt->dt_colors[c_bg] = (colorset < 0)
676       ? GetColor(dt->dt_color_names[c_bg])
677       : Colorset[colorset].bg;
678     xgcv.foreground = dt->dt_colors[c_fg];
679     xgcv.background = dt->dt_colors[c_bg];
680     if (dt->dt_Ffont->font != NULL)
681     {
682       xgcv_mask |= GCFont;
683       xgcv.font = dt->dt_Ffont->font->fid;
684     }
685     xgcv_mask |= GCBackground;
686     dt->dt_GC = fvwmlib_XCreateGC(dpy, CF.frame, xgcv_mask, &xgcv);
687 
688     dt->dt_used = 1;			/* fore/back font allocated */
689   }
690   if (this_item->type == I_TEXT
691       || this_item->type == I_TIMEOUT) {      /* If no shadows needed */
692     return;
693   }
694   dt->dt_colors[c_item_fg] = (itemcolorset < 0)
695     ? GetColor(dt->dt_color_names[c_item_fg])
696     : Colorset[itemcolorset].fg;
697   dt->dt_colors[c_item_bg] = (itemcolorset < 0)
698     ? GetColor(dt->dt_color_names[c_item_bg])
699     : Colorset[itemcolorset].bg;
700   xgcv.foreground = dt->dt_colors[c_item_fg];
701   xgcv.background = dt->dt_colors[c_item_bg];
702   xgcv_mask = GCForeground;
703   if (dt->dt_Ffont->font != NULL)
704   {
705     xgcv_mask |= GCFont;
706     xgcv.font = dt->dt_Ffont->font->fid;
707   }
708   dt->dt_item_GC = fvwmlib_XCreateGC(dpy, CF.frame, xgcv_mask, &xgcv);
709   if (Pdepth < 2) {
710     dt->dt_colors[c_itemlo] = PictureBlackPixel();
711     dt->dt_colors[c_itemhi] = PictureWhitePixel();
712   } else {
713     dt->dt_colors[c_itemlo] = (itemcolorset < 0)
714       ? GetShadow(dt->dt_colors[c_item_bg])
715       : Colorset[itemcolorset].shadow;
716     dt->dt_colors[c_itemhi] = (itemcolorset < 0)
717       ? GetHilite(dt->dt_colors[c_item_bg])
718       : Colorset[itemcolorset].hilite;
719   }
720   dt->dt_used = 2;		       /* fully allocated */
721 }
722 
723 
724 /* Input is the current item.  Assign a drawTable entry to it. */
AssignDrawTable(Item * adt_item)725 static void AssignDrawTable(Item *adt_item)
726 {
727   DrawTable *find_dt, *last_dt;
728   char *match_text_fore;
729   char *match_text_back;
730   char *match_item_fore;
731   char *match_item_back;
732   char *match_font;
733   DrawTable *new_dt;			/* pointer to a new one */
734 
735   match_text_fore = color_names[c_fg];
736   match_text_back = color_names[c_bg];
737   match_item_fore = color_names[c_item_fg];
738   match_item_back = color_names[c_item_bg];
739 
740   switch(adt_item->type) {
741   case I_TEXT:
742   case I_SEPARATOR:			/* hack */
743     match_font = font_names[f_text];
744     break;
745   case	I_TIMEOUT:
746     match_font = font_names[f_timeout];
747     break;
748   case I_INPUT:
749     match_font = font_names[f_input];
750     break;
751   default:
752     match_font = font_names[f_button]; /* choices same as buttons */
753     break;
754   }
755   last_dt = 0;
756   for (find_dt = CF.roots_dt;		   /* start at front */
757        find_dt != 0;			/* until end */
758        find_dt = find_dt->dt_next) {	/* follow next pointer */
759     last_dt = find_dt;
760     if ((strcasecmp(match_text_fore,find_dt->dt_color_names[c_fg]) == 0) &&
761 	(strcasecmp(match_text_back,find_dt->dt_color_names[c_bg]) == 0) &&
762 	(strcasecmp(match_item_fore,find_dt->dt_color_names[c_item_fg]) == 0) &&
763 	(strcasecmp(match_item_back,find_dt->dt_color_names[c_item_bg]) == 0) &&
764 	(strcasecmp(match_font,find_dt->dt_font_name) == 0)) { /* Match */
765       adt_item->header.dt_ptr = find_dt;       /* point item to drawtable */
766       return;				/* done */
767     } /* end match */
768   } /* end all drawtables checked, no match */
769 
770   /* Time to add a DrawTable */
771   /* get one */
772   new_dt = fxmalloc(sizeof(struct _drawtable));
773   memset(new_dt, 0, sizeof(struct _drawtable));
774   new_dt->dt_next = 0;			/* new end of list */
775   if (CF.roots_dt == 0) {		   /* If first entry in list */
776     CF.roots_dt = new_dt;		   /* set root pointer */
777   } else {				/* not first entry */
778     last_dt->dt_next = new_dt;		/* link old to new */
779   }
780 
781   new_dt->dt_font_name = fxstrdup(match_font);
782   new_dt->dt_color_names[c_fg]	    = fxstrdup(match_text_fore);
783   new_dt->dt_color_names[c_bg]	    = fxstrdup(match_text_back);
784   new_dt->dt_color_names[c_item_fg] = fxstrdup(match_item_fore);
785   new_dt->dt_color_names[c_item_bg] = fxstrdup(match_item_back);
786   new_dt->dt_used = 0;			/* show nothing allocated */
787   new_dt->dt_Ffont = FlocaleLoadFont(dpy, new_dt->dt_font_name, module->name);
788   FlocaleAllocateWinString(&new_dt->dt_Fstr);
789 
790   myfprintf((stderr,"Created drawtable with %s %s %s %s %s\n",
791 	     new_dt->dt_color_names[c_fg], new_dt->dt_color_names[c_bg],
792 	     new_dt->dt_color_names[c_item_fg],
793 	     new_dt->dt_color_names[c_item_bg],
794 	     new_dt->dt_font_name));
795   adt_item->header.dt_ptr = new_dt;	       /* point item to new drawtable */
796 }
797 
798 /* input/output is global "item" - currently allocated last item */
AddItem(void)799 static void AddItem(void)
800 {
801   Item *save_item;
802   save_item = (Item *)item;		/* save current item */
803   item = fxcalloc(sizeof(Item), 1); /* get a new item */
804   if (save_item == 0) {			/* if first item */
805     root_item_ptr = item;		/* save root item */
806   } else {				/* else not first item */
807     save_item->header.next = item;	/* link prior to new */
808   }
809 }
810 
ct_Separator(char * cp)811 static void ct_Separator(char *cp)
812 {
813   AddItem();
814   item->header.name = "";		/* null = create no variables in form */
815   item->type = I_SEPARATOR;
816   item->header.size_y = 2;		/* 2 pixels high */
817   AssignDrawTable(item);
818   AddToLine(item);
819   myfprintf((stderr, "ct_separator command set max width %d\n",(int)item->header.size_x));
820 }
821 
ct_Text(char * cp)822 static void ct_Text(char *cp)
823 {
824   /* syntax: *FFText "<text>" */
825   AddItem();
826   bg_state = 'u';			/* indicate b/g color now used. */
827   item->type = I_TEXT;
828   /* Item now added to list of items, now it needs a pointer
829      to the correct DrawTable. */
830   AssignDrawTable(item);
831   item->header.name = "";
832   if (*cp == '\"')
833     item->text.value = CopyQuotedString(++cp);
834   else
835     item->text.value = "";
836   item->text.n = strlen(item->text.value);
837 
838   item->header.size_x = FlocaleTextWidth(item->header.dt_ptr->dt_Ffont,
839 				   item->text.value,
840 				   item->text.n) + 2 * TEXT_SPC;
841   item->header.size_y = item->header.dt_ptr->dt_Ffont->height
842      + CF.padVText;
843   myfprintf((stderr, "Text \"%s\" [%d, %d]\n", item->text.value,
844 	     item->header.size_x, item->header.size_y));
845   AddToLine(item);
846 }
847 /* Set the form's title.
848    The default is the aliasname.
849    If there is no quoted string, create a blank title. */
ct_Title(char * cp)850 static void ct_Title(char *cp)
851 {
852   /* syntax: *FFTitle "<text>" */
853   if (*cp == '\"')
854     CF.title = CopyQuotedString(++cp);
855   else
856     CF.title = "";
857   myfprintf((stderr, "Title \"%s\"\n", CF.title));
858 }
ct_Timeout(char * cp)859 static void ct_Timeout(char *cp)
860 {
861   /* syntax: *FFTimeout tenth_of_seconds <Command> "Text" */
862   char *tmpcp, *tmpbuf;
863 
864   if (timer != NULL) {
865     fprintf(stderr,"Only one timeout per form allowed, skipped %s.\n",cp);
866     return;
867   }
868   AddItem();
869   bg_state = 'u';			/* indicate b/g color now used. */
870   item->type = I_TIMEOUT;
871   /* Item now added to list of items, now it needs a pointer
872      to the correct DrawTable. */
873   AssignDrawTable(item);
874   item->header.name = "";
875 
876   item->timeout.timeleft = atoi(cp);
877   if (item->timeout.timeleft < 0)
878   {
879     item->timeout.timeleft = 0;
880   }
881   else if (item->timeout.timeleft > 99999)
882   {
883     item->timeout.timeleft = 99999;
884   }
885   timer = item;
886 
887   while (*cp && *cp != '\n' && !isspace((unsigned char)*cp)) cp++;
888 							/* skip timeout */
889   while (*cp && *cp != '\n' && isspace((unsigned char)*cp)) cp++;
890 							/* move up to command */
891 
892   if (!*cp || *cp == '\n') {
893     fprintf(stderr,"Improper arguments specified for FvwmForm Timeout.\n");
894     return;
895   }
896 
897   if (*cp == '\"') {
898     item->timeout.command = CopyQuotedString(++cp);
899     /* skip over the whole quoted string to continue parsing */
900     cp += strlen(item->timeout.command) + 1;
901   }
902   else {
903     tmpbuf = fxstrdup(cp);
904     tmpcp = tmpbuf;
905     while (!isspace((unsigned char)*tmpcp)) tmpcp++;
906     *tmpcp = '\0';			  /* cutoff command at first word */
907     item->timeout.command = fxstrdup(tmpbuf);
908     free(tmpbuf);
909     while (!isspace((unsigned char)*cp)) cp++; /* move past command again */
910   }
911 
912   while (*cp && *cp != '\n' && isspace((unsigned char)*cp)) cp++;
913 						/* move up to next arg */
914 
915   if (!*cp || *cp == '\n') {
916     fprintf(stderr,"Improper arguments specified for FvwmForm Timeout.\n");
917     return;
918   }
919 
920   if (*cp == '\"') {
921     item->timeout.text = CopyQuotedString(++cp);
922   } else
923     item->timeout.text = "";
924   item->timeout.len = strlen(item->timeout.text);
925 
926   item->header.size_x = FlocaleTextWidth(item->header.dt_ptr->dt_Ffont,
927 				   item->timeout.text,
928 				   item->timeout.len) + 2 * TEXT_SPC;
929   item->header.size_y = item->header.dt_ptr->dt_Ffont->height
930      + CF.padVText;
931   myfprintf((stderr, "Timeout %d \"%s\" [%d, %d]\n", item->timeout.timeleft,
932 		item->timeout.text, item->header.size_x, item->header.size_y));
933   AddToLine(item);
934 }
ct_padVText(char * cp)935 static void ct_padVText(char *cp)
936 {
937   /* syntax: *FFText "<padVText pixels>" */
938   CF.padVText = atoi(cp);
939   myfprintf((stderr, "Text Vertical Padding %d\n", CF.padVText));
940 }
ct_Input(char * cp)941 static void ct_Input(char *cp)
942 {
943   int j;
944   /* syntax: *FFInput <name> <size> "<init_value>" */
945   AddItem();
946   item->type = I_INPUT;
947   AssignDrawTable(item);
948   item->header.name = CopySolidString(cp);
949   cp += strlen(item->header.name);
950   while (isspace((unsigned char)*cp)) cp++;
951   item->input.size = atoi(cp);
952   while (!isspace((unsigned char)*cp)) cp++;
953   while (isspace((unsigned char)*cp)) cp++;
954   item->input.init_value = fxstrdup("");	    /* init */
955   if (*cp == '\"') {
956     free(item->input.init_value);
957     item->input.init_value = CopyQuotedString(++cp);
958   }
959   item->input.blanks = fxmalloc(item->input.size);
960   for (j = 0; j < item->input.size; j++)
961     item->input.blanks[j] = ' ';
962   item->input.buf = strlen(item->input.init_value) + 1;
963   item->input.value = fxmalloc(item->input.buf);
964   item->input.value[0] = 0;		/* avoid reading unitialized data */
965 
966   item->header.size_x = item->header.dt_ptr->dt_Ffont->height * item->input.size / 2
967 			+ 2 * TEXT_SPC + 2 * BOX_SPC;
968   item->header.size_y = item->header.dt_ptr->dt_Ffont->height
969     + 3 * TEXT_SPC + 2 * BOX_SPC;
970   myfprintf((stderr,"Input size_y is %d\n",item->header.size_y));
971 
972   if (CF.cur_input == 0) {		   /* first input field */
973     item->input.next_input = item;	/* ring, next field is first field */
974     item->input.prev_input = item;	/* ring, prev field is first field */
975     CF.first_input = item;		   /* save loc of first item */
976   } else {				/* not first field */
977     CF.cur_input->input.next_input = item; /* old next ptr point to this item */
978     item->input.prev_input = CF.cur_input; /* current items prev is old item */
979     item->input.next_input = CF.first_input; /* next is first item */
980     CF.first_input->input.prev_input = item; /* prev in first is this item */
981   }
982   CF.cur_input = item;			   /* new current input item */
983   myfprintf((stderr, "Input, %s, [%d], \"%s\"\n", item->header.name,
984 	  item->input.size, item->input.init_value));
985   AddToLine(item);
986 }
ct_Read(char * cp)987 static void ct_Read(char *cp)
988 {
989   /* syntax: *FFRead 0 | 1 */
990   myfprintf((stderr,"Got read command, char is %c\n",(int)*cp));
991   endDefaultsRead = *cp;		/* copy whatever it is */
992 }
993 /* read and save vars from a file for later use in form
994    painting.
995 */
ct_UseData(char * cp)996 static void ct_UseData(char *cp)
997 {
998   /* syntax: *FFUseData filename cmd_prefix */
999   CF.file_to_read = CopySolidString(cp);
1000   if (*CF.file_to_read == 0) {
1001     fprintf(stderr,"UseData command missing first arg, File to read\n");
1002     return;
1003   }
1004   cp += strlen(CF.file_to_read);
1005   while (isspace((unsigned char)*cp)) cp++;
1006   CF.leading = CopySolidString(cp);
1007   if (*CF.leading == 0) {
1008     fprintf(stderr,"UseData command missing second arg, Leading\n");
1009     CF.file_to_read = 0;		   /* stop read */
1010     return;
1011   }
1012   /* Cant do the actual reading of the data file here,
1013      we are already in a readconfig loop. */
1014 }
ReadFormData(void)1015 static void ReadFormData(void)
1016 {
1017   int leading_len;
1018   char *line_buf;			/* ptr to curr config line */
1019   char cmd_buffer[200];
1020   sprintf(cmd_buffer,"read %s Quiet",CF.file_to_read);
1021   SendText(Channel,cmd_buffer,0);	/* read data */
1022   leading_len = strlen(CF.leading);
1023   InitGetConfigLine(Channel, CF.leading); /* ask for certain lines */
1024   while (GetConfigLine(Channel,&line_buf),line_buf) { /* while there is some */
1025     if (strncasecmp(line_buf, CF.leading, leading_len) == 0) { /* leading = */
1026       if (line_buf[strlen(line_buf)-1] == '\n') { /* if line ends with nl */
1027 	line_buf[strlen(line_buf)-1] = '\0'; /* strip off \n */
1028       }
1029       PutDataInForm(line_buf+leading_len); /* pass arg, space, value */
1030     } /* end match on arg 2, "leading" */
1031   } /* end while there is config data */
1032   free(CF.file_to_read);		/* dont need it anymore */
1033   free(CF.leading);
1034   CF.file_to_read = 0;
1035   CF.leading = 0;
1036 }
1037 /*
1038   Input is a line with varname space value.
1039   Search form for matching input fields and set values.
1040   If you don't get a match on an input field, try a choice.
1041 */
PutDataInForm(char * cp)1042 static void PutDataInForm(char *cp)
1043 {
1044   char *var_name;
1045   char *var_value;
1046   int var_len, i;
1047   Item *item;
1048   Line *line;
1049 
1050   var_name = CopySolidString(cp);	/* var */
1051   if (*var_name == 0) {
1052     return;
1053   }
1054   cp += strlen(var_name);
1055   while (isspace((unsigned char)*cp)) cp++;
1056   var_value = cp;
1057   if (CF.cur_input != 0) {
1058     item = CF.cur_input;
1059     do {
1060       if (strcasecmp(var_name,item->header.name) == 0) {
1061 	var_len = strlen(cp);
1062 	if (item->input.init_value)
1063 	  free(item->input.init_value);
1064 	item->input.init_value = fxmalloc(var_len + 1);
1065 	strcpy(item->input.init_value,cp); /* new initial value in field */
1066 	if (item->input.value)
1067 	  free(item->input.value);
1068 	item->input.buf = var_len+1;
1069 	item->input.value = fxmalloc(item->input.buf);
1070 	strcpy(item->input.value,cp);	  /* new value in field */
1071 	free(var_name);			/* goto's have their uses */
1072 	return;
1073       }
1074       item=item->input.next_input;	  /* next input field */
1075     } while (item != CF.cur_input);	  /* while not end of ring */
1076   }
1077   /* You have a matching line, but it doesn't match an input
1078      field.  What to do?  I know, try a choice. */
1079   line = &root_line;			 /* start at first line */
1080   do {					/* for all lines */
1081     for (i = 0; i < line->n; i++) {	/* all items on line */
1082       item = line->items[i];
1083       if (item->type == I_CHOICE) {	/* choice is good */
1084 	if (strcasecmp(var_name,item->header.name) == 0) { /* match */
1085 	  item->choice.init_on = 0;
1086 	  if (strncasecmp(cp, "on", 2) == 0) {
1087 	    item->choice.init_on = 1;	/* set default state */
1088 	    free(var_name);		/* goto's have their uses */
1089 	    return;
1090 	  }
1091 	}
1092       }
1093     } /* end all items in line */
1094     line = line->next;			/* go to next line */
1095   } while (line != &root_line);		/* do all lines */
1096   /* You have a matching line, it didn't match an input field,
1097      and it didn't match a choice.  I've got it, it may match a
1098      selection, in which case we should use the value to
1099      set the choices! */
1100   for (item = root_item_ptr; item != 0;
1101        item = item->header.next) {/* all items */
1102     if (item->type == I_SELECT) {     /* selection is good */
1103       if (strcasecmp(var_name,item->header.name) == 0) { /* match */
1104 	/* Now find the choices for this selection... */
1105 	Item *choice_ptr;
1106 	for (i = 0;
1107 	     i<item->selection.n;
1108 	     i++) {
1109 	  choice_ptr=item->selection.choices[i];
1110 	  /* if the choice value matches the selection */
1111 	  if (strcmp(choice_ptr->choice.value,var_value) == 0) {
1112 	    choice_ptr->choice.init_on = 1;
1113 	  } else {
1114 	    choice_ptr->choice.init_on = 0;
1115 	  }
1116 	} /* end all choices */
1117       } /* end match */
1118     } /* end selection */
1119   } /* end all items */
1120   free(var_name);			/* not needed now */
1121 }
ct_Selection(char * cp)1122 static void ct_Selection(char *cp)
1123 {
1124   /* syntax: *FFSelection <name> single | multiple */
1125   AddItem();
1126   cur_sel = item;			/* save ptr as cur_sel */
1127   cur_sel->type = I_SELECT;
1128   cur_sel->header.name = CopySolidString(cp);
1129   cp += strlen(cur_sel->header.name);
1130   while (isspace((unsigned char)*cp)) cp++;
1131   if (strncasecmp(cp, "multiple", 8) == 0)
1132     cur_sel->selection.key = IS_MULTIPLE;
1133   else
1134     cur_sel->selection.key = IS_SINGLE;
1135 }
ct_Choice(char * cp)1136 static void ct_Choice(char *cp)
1137 {
1138   /* syntax: *FFChoice <name> <value> [on | _off_] ["<text>"] */
1139   /* This next edit is a liitle weak, the selection should be right
1140      before the choice. At least a core dump is avoided. */
1141   if (cur_sel == 0) {			/* need selection for a choice */
1142     fprintf(stderr,"%s: Need selection for choice %s\n",
1143 	    module->name, cp);
1144     return;
1145   }
1146   bg_state = 'u';			/* indicate b/g color now used. */
1147   AddItem();
1148   item->type = I_CHOICE;
1149   AssignDrawTable(item);
1150   item->header.name = CopySolidString(cp);
1151   cp += strlen(item->header.name);
1152   while (isspace((unsigned char)*cp)) cp++;
1153   item->choice.value = CopySolidString(cp);
1154   cp += strlen(item->choice.value);
1155   while (isspace((unsigned char)*cp)) cp++;
1156   if (strncasecmp(cp, "on", 2) == 0)
1157     item->choice.init_on = 1;
1158   else
1159     item->choice.init_on = 0;
1160   while (!isspace((unsigned char)*cp)) cp++;
1161   while (isspace((unsigned char)*cp)) cp++;
1162   if (*cp == '\"')
1163     item->choice.text = CopyQuotedString(++cp);
1164   else
1165     item->choice.text = "";
1166   item->choice.n = strlen(item->choice.text);
1167   item->choice.sel = cur_sel;
1168 
1169   if (cur_sel->selection.choices_array_count
1170       <= cur_sel->selection.n) {	   /* no room */
1171     cur_sel->selection.choices_array_count += CHOICES_PER_SEL_EXPANSION;
1172     cur_sel->selection.choices =
1173       fxrealloc((void *)cur_sel->selection.choices,
1174                sizeof(Item *) * cur_sel->selection.choices_array_count,
1175 	       sizeof(cur_sel->selection.choices)); /* expand */
1176   }
1177 
1178   cur_sel->selection.choices[cur_sel->selection.n++] = item;
1179   item->header.size_y = item->header.dt_ptr->dt_Ffont->height
1180      + 2 * TEXT_SPC;
1181   /* this is weird, the x dimension is the sum of the height and width? */
1182   item->header.size_x = item->header.dt_ptr->dt_Ffont->height
1183      + 4 * TEXT_SPC +
1184      FlocaleTextWidth(item->header.dt_ptr->dt_Ffont,
1185        item->choice.text, item->choice.n);
1186   myfprintf((stderr, "Choice %s, \"%s\", [%d, %d]\n", item->header.name,
1187 	  item->choice.text, item->header.size_x, item->header.size_y));
1188   AddToLine(item);
1189 }
ct_Button(char * cp)1190 static void ct_Button(char *cp)
1191 {
1192   /* syntax: *FFButton continue | restart | quit "<text>" */
1193   AddItem();
1194   item->type = I_BUTTON;
1195   AssignDrawTable(item);
1196   item->header.name = "";
1197   if (strncasecmp(cp, "restart", 7) == 0)
1198     item->button.key = IB_RESTART;
1199   else if (strncasecmp(cp, "quit", 4) == 0)
1200     item->button.key = IB_QUIT;
1201   else
1202     item->button.key = IB_CONTINUE;
1203   while (!isspace((unsigned char)*cp)) cp++;
1204   while (isspace((unsigned char)*cp)) cp++;
1205   if (*cp == '\"') {
1206     item->button.text = CopyQuotedString(++cp);
1207     cp += strlen(item->button.text) + 1;
1208     while (isspace((unsigned char)*cp)) cp++;
1209   } else
1210     item->button.text = "";
1211   if (*cp == '^')
1212     item->button.keypress = *(++cp) - '@';
1213   else if (*cp == 'F')
1214     item->button.keypress = 256 + atoi(++cp);
1215   else
1216     item->button.keypress = -1;
1217   item->button.len = strlen(item->button.text);
1218   item->header.size_y = item->header.dt_ptr->dt_Ffont->height
1219      + 2 * TEXT_SPC + 2 * BOX_SPC;
1220   item->header.size_x = 2 * TEXT_SPC + 2 * BOX_SPC
1221   + FlocaleTextWidth(item->header.dt_ptr->dt_Ffont, item->button.text,
1222     item->button.len);
1223   AddToLine(item);
1224   cur_button = item;
1225   myfprintf((stderr,"Created button, fore %s, bg %s, text %s\n",
1226 	     item->header.dt_ptr->dt_color_names[c_item_fg],
1227 	     item->header.dt_ptr->dt_color_names[c_item_bg],
1228 	     item->button.text));
1229 }
ct_Command(char * cp)1230 static void ct_Command(char *cp)
1231 {
1232   /* syntax: *FFCommand <command> */
1233   if (cur_button->button.button_array_size <= cur_button->button.n)
1234   {
1235     cur_button->button.button_array_size += BUTTON_COMMAND_EXPANSION;
1236     cur_button->button.commands =
1237       fxrealloc((void *)cur_button->button.commands,
1238                sizeof(char *) * cur_button->button.button_array_size,
1239 	       sizeof(cur_button->button.commands));
1240   }
1241   cur_button->button.commands[cur_button->button.n++] = fxstrdup(cp);
1242 }
1243 
1244 /* End of ct_ routines */
1245 
1246 /* Init constants with values that can be freed later. */
InitConstants(void)1247 static void InitConstants(void) {
1248   color_names[0]=fxstrdup("Light Gray");
1249   color_names[1]=fxstrdup("Black");
1250   color_names[2]=fxstrdup("Gray50");
1251   color_names[3]=fxstrdup("Wheat");
1252   font_names[0]=fxstrdup("8x13bold");
1253   font_names[1]=fxstrdup("8x13bold");
1254   font_names[2]=fxstrdup("8x13bold");
1255   font_names[3]=fxstrdup("8x13bold");
1256   screen_background_color=fxstrdup("Light Gray");
1257   CF.p_c[input_fore].pointer_color.pixel = PictureWhitePixel();
1258   CF.p_c[input_back].pointer_color.pixel = PictureBlackPixel();
1259   CF.p_c[button_fore].pointer_color.pixel = PictureBlackPixel();
1260   CF.p_c[button_back].pointer_color.pixel = PictureWhitePixel();
1261   /* The in pointer is the reverse of the hover pointer. */
1262   CF.p_c[button_in_fore].pointer_color.pixel = PictureWhitePixel();
1263   CF.p_c[button_in_back].pointer_color.pixel = PictureBlackPixel();
1264 }
1265 
1266 /* read the configuration file */
ReadDefaults(void)1267 static void ReadDefaults(void)
1268 {
1269   char *line_buf;			/* ptr to curr config line */
1270 
1271   /* default button is for initial functions */
1272   cur_button = &CF.def_button;
1273   CF.def_button.button.key = IB_CONTINUE;
1274 
1275    /*
1276     * Reading .FvwmFormDefault for every form seems slow.
1277     *
1278     * This next bit puts a command at the end of the module command
1279     * queue in fvwm that indicates whether the file has to be read.
1280     *
1281     * Read defaults looking for "*FvwmFormDefaultRead"
1282     * if not there, send read,
1283     * then "*FvwmFormDefaultRead y",
1284     * then look thru defaults again.
1285     * The customization dialog sends "*FvwmFormDefaultRead n"
1286     * to start over.
1287     */
1288   InitGetConfigLine(Channel,"*FvwmFormDefault");
1289   while (GetConfigLine(Channel,&line_buf),line_buf) { /* get config from fvwm */
1290     ParseDefaults(line_buf);		 /* process default config lines 1st */
1291   }
1292   if (endDefaultsRead == 'y') {		/* defaults read already */
1293     myfprintf((stderr,"Defaults read, no need to read file.\n"));
1294     return;
1295   } /* end defaults read already */
1296   SendText(Channel,"read .FvwmForm Quiet",0); /* read default config */
1297   SendText(Channel,"*FvwmFormDefaultRead y",0); /* remember you read it */
1298 
1299   InitGetConfigLine(Channel,"*FvwmFormDefault");
1300   while (GetConfigLine(Channel,&line_buf),line_buf) { /* get config from fvwm */
1301     ParseDefaults(line_buf);		 /* process default config lines 1st */
1302   }
1303 } /* done */
1304 
ReadConfig(void)1305 static void ReadConfig(void)
1306 {
1307   char *line_buf;			/* ptr to curr config line */
1308 
1309   InitGetConfigLine(Channel, mname);
1310   while (GetConfigLine(Channel,&line_buf),line_buf) { /* get config from fvwm */
1311     ParseConfigLine(line_buf);		/* process config lines */
1312   }
1313 } /* done */
1314 
1315 /* After this config is read, figure it out */
MassageConfig(void)1316 static void MassageConfig(void)
1317 {
1318   int i, extra;
1319   Line *line;				/* for scanning form lines */
1320 
1321   if (CF.file_to_read) {		/* if theres a data file to read */
1322     ReadFormData();			/* go read it */
1323   }
1324   /* get the geometry right */
1325   CF.max_width = 0;
1326   CF.total_height = ITEM_VSPC;
1327   line = &root_line;			 /* start at first line */
1328   do {					/* for all lines */
1329     for (i = 0; i < line->n; i++) {
1330       line->items[i]->header.pos_y = CF.total_height;
1331       if (line->items[i]->header.size_y < line->size_y)
1332 	line->items[i]->header.pos_y +=
1333 	  (line->size_y - line->items[i]->header.size_y) / 2 + 1 ;
1334     } /* end all items in line */
1335     CF.total_height += ITEM_VSPC + line->size_y;
1336     line->size_x += (line->n + 1) * ITEM_HSPC;
1337     if (line->size_x > CF.max_width)
1338       CF.max_width = line->size_x;
1339     line = line->next;			/* go to next line */
1340   } while (line != &root_line);		/* do all lines */
1341   do {					/* note, already back at root_line */
1342     int width;
1343     switch (line->justify) {
1344     case L_LEFT:
1345       width = ITEM_HSPC;
1346       for (i = 0; i < line->n; i++) {
1347 	line->items[i]->header.pos_x = width;
1348 	width += ITEM_HSPC + line->items[i]->header.size_x;
1349       }
1350       break;
1351     case L_RIGHT:
1352       width = CF.max_width - line->size_x + ITEM_HSPC;
1353       for (i = 0; i < line->n; i++) {
1354 	line->items[i]->header.pos_x = width;
1355 	width += ITEM_HSPC + line->items[i]->header.size_x;
1356       }
1357       break;
1358     case L_CENTER:
1359       width = (CF.max_width - line->size_x) / 2 + ITEM_HSPC;
1360       for (i = 0; i < line->n; i++) {
1361 	line->items[i]->header.pos_x = width;
1362 	myfprintf((stderr, "Line Item[%d] @ (%d, %d)\n", i,
1363 	       line->items[i]->header.pos_x, line->items[i]->header.pos_y));
1364 	width += ITEM_HSPC + line->items[i]->header.size_x;
1365       }
1366       break;
1367     case L_LEFTRIGHT:
1368     /* count the number of inputs on the line - the extra space will be
1369      * shared amongst these if there are any, otherwise it will be added
1370      * as space in between the elements
1371      */
1372       extra = 0 ;
1373       for (i = 0 ; i < line->n ; i++) {
1374 	if (line->items[i]->type == I_INPUT)
1375 	  extra++ ;
1376       }
1377       if (extra == 0) {
1378 	if (line->n < 2) {  /* same as L_CENTER */
1379 	  width = (CF.max_width - line->size_x) / 2 + ITEM_HSPC;
1380 	  for (i = 0; i < line->n; i++) {
1381 	    line->items[i]->header.pos_x = width;
1382 	    width += ITEM_HSPC + line->items[i]->header.size_x;
1383 	  }
1384 	} else {
1385 	  extra = (CF.max_width - line->size_x) / (line->n - 1);
1386 	  width = ITEM_HSPC;
1387 	  for (i = 0; i < line->n; i++) {
1388 	    line->items[i]->header.pos_x = width;
1389 	    width += ITEM_HSPC + line->items[i]->header.size_x + extra;
1390 	  }
1391 	}
1392       } else {
1393 	extra = (CF.max_width - line->size_x) / extra ;
1394 	width = ITEM_HSPC ;
1395 	for (i = 0 ; i < line->n ; i++) {
1396 	  line->items[i]->header.pos_x = width ;
1397 	  if (line->items[i]->type == I_INPUT)
1398 	    line->items[i]->header.size_x += extra ;
1399 	  width += ITEM_HSPC + line->items[i]->header.size_x ;
1400 	}
1401       }
1402       break;
1403     }
1404     line = line->next;			/* go to next line */
1405   } while (line != &root_line);		 /* do all lines */
1406 }
1407 
1408 /* reset all the values (also done on first display) */
Restart(void)1409 static void Restart(void)
1410 {
1411   Item *item;
1412 
1413   CF.cur_input = NULL;
1414   CF.abs_cursor = CF.rel_cursor = 0;
1415   for (item = root_item_ptr; item != 0;
1416        item = item->header.next) {/* all items */
1417     switch (item->type) {
1418     case I_INPUT:
1419       if (!CF.cur_input)
1420 	CF.cur_input = item;
1421 
1422       /* save old input values in a recall ring. */
1423       if (item->input.value && item->input.value[0] != 0) { /* ? to save */
1424 	if (item->input.value_history_ptr == 0) {  /* no history yet */
1425 	  item->input.value_history_ptr =
1426 	    fxcalloc(sizeof(char *), 50);
1427 	  item->input.value_history_ptr[0] = fxstrdup(item->input.value);
1428 	  item->input.value_history_count = 1; /* next insertion point */
1429 	  myfprintf((stderr,"Initial save of %s in slot 0\n",
1430 		     item->input.value_history_ptr[0]));
1431 	} else {			/* we have a history */
1432 	  int prior;
1433 	  prior = item->input.value_history_count - 1;
1434 	  if (prior < 0) {
1435 	    for (prior = VH_SIZE - 1;
1436 		 CF.cur_input->input.value_history_ptr[prior] == 0;
1437 		 --prior);		/* find last used slot */
1438 	  }
1439 	  myfprintf((stderr,"Prior is %d, compare %s to %s\n",
1440 		     prior, item->input.value,
1441 		     item->input.value_history_ptr[prior]));
1442 
1443 	  if ( strcmp(item->input.value, item->input.value_history_ptr[prior])
1444 	       != 0) {			/* different value */
1445 	    if (item->input.value_history_ptr[item->input.value_history_count])
1446 	    {
1447 	      free(item->input.value_history_ptr[
1448 			   item->input.value_history_count]);
1449 	      myfprintf((stderr,"Freeing old item in slot %d\n",
1450 			 item->input.value_history_count));
1451 	    }
1452 	    item->input.value_history_ptr[item->input.value_history_count] =
1453 	      fxstrdup(item->input.value); /* save value ptr in array */
1454 	    myfprintf((stderr,"Save of %s in slot %d\n",
1455 		       item->input.value,
1456 		       item->input.value_history_count));
1457 
1458 	    /* leave count pointing at the next insertion point. */
1459 	    if (item->input.value_history_count < VH_SIZE - 1) { /* not full */
1460 	      ++item->input.value_history_count;    /* next slot */
1461 	    } else {
1462 	      item->input.value_history_count = 0;  /* wrap around */
1463 	    }
1464 	  } /* end something different */
1465 	} /* end have a history */
1466 	myfprintf((stderr,"New history yankat %d\n",
1467 		   item->input.value_history_yankat));
1468       } /* end something to save */
1469       item->input.value_history_yankat = item->input.value_history_count;
1470       item->input.n = strlen(item->input.init_value);
1471       strcpy(item->input.value, item->input.init_value);
1472       item->input.left = 0;
1473       break;
1474     case I_CHOICE:
1475       item->choice.on = item->choice.init_on;
1476       break;
1477     }
1478   }
1479 }
1480 
1481 /* redraw the frame */
RedrawFrame(XEvent * pev)1482 void RedrawFrame(XEvent *pev)
1483 {
1484 	Item *item;
1485 	Region region = None;
1486 
1487 	Bool clear = False;
1488 	if (FftSupport)
1489 	{
1490 		item = root_item_ptr;
1491 		while(item != 0 && !clear)
1492 		{
1493 			if ((item->type == I_TEXT || item->type == I_CHOICE) &&
1494 			    item->header.dt_ptr->dt_Ffont->fftf.fftfont != NULL)
1495 				clear = True;
1496 			item = item->header.next;
1497 		}
1498 		if (clear && pev)
1499 		{
1500 			XClearArea(
1501 				dpy, CF.frame,
1502 				pev->xexpose.x, pev->xexpose.y,
1503 				pev->xexpose.width, pev->xexpose.height,
1504 				False);
1505 		}
1506 		else
1507 		{
1508 			XClearWindow(dpy, CF.frame);
1509 		}
1510 	}
1511 	if (pev)
1512 	{
1513 		XRectangle r;
1514 
1515 		r.x = pev->xexpose.x;
1516 		r.y =  pev->xexpose.y;
1517 		r.width = pev->xexpose.width;
1518 		r.height = pev->xexpose.height;
1519 		region = XCreateRegion();
1520 		XUnionRectWithRegion (&r, region, region);
1521 	}
1522 	for (item = root_item_ptr; item != 0;
1523 	     item = item->header.next) {      /* all items */
1524 		DrawTable *dt_ptr = item->header.dt_ptr;
1525 
1526 		if (dt_ptr && dt_ptr->dt_Fstr)
1527 		{
1528 			if (region)
1529 			{
1530 				dt_ptr->dt_Fstr->flags.has_clip_region = True;
1531 				dt_ptr->dt_Fstr->clip_region = region;
1532 			}
1533 			else
1534 			{
1535 				dt_ptr->dt_Fstr->flags.has_clip_region = False;
1536 			}
1537 		}
1538 		switch (item->type) {
1539 		case I_TEXT:
1540 			RedrawText(item);
1541 			break;
1542 		case I_TIMEOUT:
1543 			RedrawTimeout(item);
1544 			break;
1545 		case I_CHOICE:
1546 			dt_ptr->dt_Fstr->win = CF.frame;
1547 			dt_ptr->dt_Fstr->gc  = dt_ptr->dt_GC;
1548 			dt_ptr->dt_Fstr->str = item->choice.text;
1549 			dt_ptr->dt_Fstr->x   = item->header.pos_x
1550 				+ TEXT_SPC + item->header.size_y;
1551 			dt_ptr->dt_Fstr->y   = item->header.pos_y
1552 				+ TEXT_SPC + dt_ptr->dt_Ffont->ascent;
1553 			dt_ptr->dt_Fstr->len = item->choice.n;
1554 			dt_ptr->dt_Fstr->flags.has_colorset = False;
1555 			if (itemcolorset >= 0)
1556 			{
1557 				dt_ptr->dt_Fstr->colorset =
1558 					&Colorset[itemcolorset];
1559 				dt_ptr->dt_Fstr->flags.has_colorset
1560 					= True;
1561 			}
1562 			FlocaleDrawString(dpy,
1563 					  dt_ptr->dt_Ffont,
1564 					  dt_ptr->dt_Fstr,
1565 					  FWS_HAVE_LENGTH);
1566 			break;
1567 		case I_SEPARATOR:
1568 			myfprintf((stderr, "redraw_frame calling RedrawSeparator\n"));
1569 			RedrawSeparator(item);
1570 			break;
1571 		}
1572 		if (dt_ptr && dt_ptr->dt_Fstr)
1573 		{
1574 			dt_ptr->dt_Fstr->flags.has_clip_region = False;
1575 		}
1576 	}
1577 	if (region)
1578 	{
1579 		XDestroyRegion(region);
1580 	}
1581 }
1582 
RedrawText(Item * item)1583 void RedrawText(Item *item)
1584 {
1585   char *p;
1586 
1587   CheckAlloc(item,item->header.dt_ptr); /* alloc colors and fonts needed */
1588   item->header.dt_ptr->dt_Fstr->len = item->text.n;
1589   if ((p = memchr(item->text.value, '\0', item->header.dt_ptr->dt_Fstr->len))
1590       != NULL)
1591     item->header.dt_ptr->dt_Fstr->len = p - item->text.value;
1592   item->header.dt_ptr->dt_Fstr->win = CF.frame;
1593   item->header.dt_ptr->dt_Fstr->gc  = item->header.dt_ptr->dt_GC;
1594   item->header.dt_ptr->dt_Fstr->str = item->text.value;
1595   item->header.dt_ptr->dt_Fstr->x   = item->header.pos_x + TEXT_SPC;
1596   item->header.dt_ptr->dt_Fstr->y   = item->header.pos_y + ( CF.padVText / 2 ) +
1597     item->header.dt_ptr->dt_Ffont->ascent;
1598   item->header.dt_ptr->dt_Fstr->flags.has_colorset = False;
1599   if (colorset >= 0)
1600   {
1601     item->header.dt_ptr->dt_Fstr->colorset = &Colorset[colorset];
1602     item->header.dt_ptr->dt_Fstr->flags.has_colorset = True;
1603   }
1604   FlocaleDrawString(dpy,
1605 		    item->header.dt_ptr->dt_Ffont,
1606 		    item->header.dt_ptr->dt_Fstr, FWS_HAVE_LENGTH);
1607   return;
1608 }
1609 
1610 /*
1611  *  Draw horizontal lines to form a separator
1612  *
1613  */
RedrawSeparator(Item * item)1614 static void RedrawSeparator(Item *item)
1615 {
1616 
1617   item->header.size_x = CF.max_width - 6;
1618   CheckAlloc(item,item->header.dt_ptr); /* alloc colors and fonts needed */
1619   if ( item->header.dt_ptr && item->header.dt_ptr->dt_colors[c_itemlo] ) { /* safety */
1620     XSetForeground(dpy, item->header.dt_ptr->dt_item_GC,item->header.dt_ptr->dt_colors[c_itemlo]);
1621     XDrawLine(dpy, item->header.win,item->header.dt_ptr->dt_item_GC, 0, 0, item->header.size_x, 0);
1622     XSetForeground(dpy, item->header.dt_ptr->dt_item_GC,item->header.dt_ptr->dt_colors[c_itemhi]);
1623     XDrawLine(dpy, item->header.win,item->header.dt_ptr->dt_item_GC, 0, 1, item->header.size_x, 1);
1624 
1625   } else {
1626     fprintf(stderr,"%s: Separators, no colors %p\n",module->name,item->header.dt_ptr);
1627   }
1628   return;
1629 }
1630 
RedrawTimeout(Item * item)1631 void RedrawTimeout(Item *item)
1632 {
1633   char *p;
1634   char *tmpbuf, *tmpptr, *tmpbptr;
1635   int reallen;
1636 
1637   XClearArea(dpy, CF.frame,
1638 	       item->header.pos_x, item->header.pos_y,
1639 	       item->header.size_x, item->header.size_y,
1640 	       False);
1641 
1642   tmpbuf = fxmalloc(item->timeout.len + 6);
1643   tmpbptr = tmpbuf;
1644   for (tmpptr = item->timeout.text; *tmpptr != '\0' &&
1645 		!(tmpptr[0] == '%' && tmpptr[1] == '%'); tmpptr++) {
1646     *tmpbptr = *tmpptr;
1647     tmpbptr++;
1648   }
1649   if (tmpptr[0] == '%') {
1650     tmpptr++; tmpptr++;
1651     sprintf(tmpbptr, "%d", item->timeout.timeleft);
1652     tmpbptr += strlen(tmpbptr);
1653   }
1654   for (; *tmpptr != '\0'; tmpptr++) {
1655     *tmpbptr = *tmpptr;
1656     tmpbptr++;
1657   }
1658   *tmpbptr = '\0';
1659 
1660   reallen = strlen(tmpbuf);
1661   item->header.size_x = FlocaleTextWidth(item->header.dt_ptr->dt_Ffont,
1662 				   tmpbuf, reallen) + 2 * TEXT_SPC;
1663   item->header.size_y = item->header.dt_ptr->dt_Ffont->height + CF.padVText;
1664 
1665   CheckAlloc(item,item->header.dt_ptr); /* alloc colors and fonts needed */
1666   item->header.dt_ptr->dt_Fstr->len = reallen;
1667   if ((p = memchr(item->timeout.text, '\0', item->header.dt_ptr->dt_Fstr->len))
1668       != NULL)
1669     item->header.dt_ptr->dt_Fstr->len = p - tmpbuf;
1670   item->header.dt_ptr->dt_Fstr->win = CF.frame;
1671   item->header.dt_ptr->dt_Fstr->gc  = item->header.dt_ptr->dt_GC;
1672   item->header.dt_ptr->dt_Fstr->flags.has_colorset = False;
1673   if (colorset >= 0)
1674   {
1675     item->header.dt_ptr->dt_Fstr->colorset = &Colorset[colorset];
1676     item->header.dt_ptr->dt_Fstr->flags.has_colorset = True;
1677   }
1678   if (item->header.dt_ptr->dt_Fstr->str != NULL)
1679     free(item->header.dt_ptr->dt_Fstr->str);
1680   item->header.dt_ptr->dt_Fstr->str = fxstrdup(tmpbuf);
1681   item->header.dt_ptr->dt_Fstr->x   = item->header.pos_x + TEXT_SPC;
1682   item->header.dt_ptr->dt_Fstr->y   = item->header.pos_y + ( CF.padVText / 2 ) +
1683     item->header.dt_ptr->dt_Ffont->ascent;
1684   FlocaleDrawString(dpy,
1685 		    item->header.dt_ptr->dt_Ffont,
1686 		    item->header.dt_ptr->dt_Fstr, FWS_HAVE_LENGTH);
1687   free(tmpbuf);
1688   return;
1689 }
1690 
1691 /* redraw an item */
RedrawItem(Item * item,int click,XEvent * pev)1692 void RedrawItem (Item *item, int click, XEvent *pev)
1693 {
1694   int dx, dy, len, x;
1695   static XSegment xsegs[4];
1696   XRectangle r,inter;
1697   Region region = None;
1698   Bool text_inter = True;
1699   DrawTable *dt_ptr = item->header.dt_ptr;
1700 
1701   /* Init intersection to size of the item. */
1702   inter.x = BOX_SPC + TEXT_SPC - 1;
1703   inter.y = BOX_SPC;
1704   inter.width = item->header.size_x - (2 * BOX_SPC) - 2 - TEXT_SPC;
1705   inter.height = (item->header.size_y - 1) - 2 * BOX_SPC + 1;
1706 
1707   myfprintf((stderr,"%s: RedrawItem expose x=%d/y=%d h=%d/w=%d\n",module->name,
1708 	     (int)pev->xexpose.x,
1709 	     (int)pev->xexpose.y,
1710 	     (int)pev->xexpose.width,
1711 	     (int)pev->xexpose.height));
1712 
1713   /* This is a slightly altered expose event from ReadXServer. */
1714   if (pev)
1715   {
1716 	  r.x = pev->xexpose.x;
1717 	  r.y =	 pev->xexpose.y;
1718 	  r.width = pev->xexpose.width;
1719 	  r.height = pev->xexpose.height;
1720 	  text_inter = frect_get_intersection(
1721 		  r.x, r.y, r.width, r.height,
1722 		  inter.x,inter.y,inter.width,inter.height,
1723 		  &inter);
1724   }
1725   else
1726   {
1727 	  /* If its not an expose event, the area assume the
1728 	     whole item is intersected. */
1729 	  r.x = inter.x;
1730 	  r.y = inter.y;
1731 	  r.width = inter.width;
1732 	  r.height = inter.height;
1733   }
1734   if (pev && text_inter && dt_ptr && dt_ptr->dt_Fstr)
1735   {
1736 	  region = XCreateRegion();
1737 	  XUnionRectWithRegion (&r, region, region);
1738 	  if (region)
1739 	  {
1740 		  dt_ptr->dt_Fstr->flags.has_clip_region = True;
1741 		  dt_ptr->dt_Fstr->clip_region = region;
1742 	  }
1743 	  else
1744 	  {
1745 		  dt_ptr->dt_Fstr->flags.has_clip_region = False;
1746 	  }
1747   }
1748 
1749   switch (item->type) {
1750   case I_INPUT:
1751     if (!text_inter)
1752     {
1753 	    return;
1754     }
1755     /* Create frame (pressed in): */
1756     dx = item->header.size_x - 1;
1757     dy = item->header.size_y - 1;
1758     /*fprintf(stderr,"GC: %lu\n", item->header.dt_ptr->dt_item_GC);*/
1759     XSetForeground(dpy, item->header.dt_ptr->dt_item_GC,
1760 		   item->header.dt_ptr->dt_colors[c_itemlo]);
1761 
1762     /* around 12/26/99, added XClearArea to this function.
1763        this was done to deal with display corruption during
1764        multifield paste.  dje */
1765     if (frect_get_intersection(
1766 	    r.x, r.y, r.width, r.height,
1767 	    inter.x, inter.y, inter.width, inter.height,
1768 	    &inter))
1769     {
1770 	    XClearArea(
1771 		       dpy, item->header.win,
1772 		       inter.x, inter.y, inter.width, inter.height, False);
1773     }
1774 
1775     xsegs[0].x1 = 0, xsegs[0].y1 = 0;
1776     xsegs[0].x2 = 0, xsegs[0].y2 = dy;
1777     xsegs[1].x1 = 0, xsegs[1].y1 = 0;
1778     xsegs[1].x2 = dx, xsegs[1].y2 = 0;
1779     xsegs[2].x1 = 1, xsegs[2].y1 = 1;
1780     xsegs[2].x2 = 1, xsegs[2].y2 = dy - 1;
1781     xsegs[3].x1 = 1, xsegs[3].y1 = 1;
1782     xsegs[3].x2 = dx - 1, xsegs[3].y2 = 1;
1783     XDrawSegments(dpy, item->header.win, item->header.dt_ptr->dt_item_GC,
1784 		  xsegs, 4);
1785     XSetForeground(dpy, item->header.dt_ptr->dt_item_GC,
1786 		   item->header.dt_ptr->dt_colors[c_itemhi]);
1787     xsegs[0].x1 = 1, xsegs[0].y1 = dy;
1788     xsegs[0].x2 = dx, xsegs[0].y2 = dy;
1789     xsegs[1].x1 = 2, xsegs[1].y1 = dy - 1;
1790     xsegs[1].x2 = dx, xsegs[1].y2 = dy - 1;
1791     xsegs[2].x1 = dx, xsegs[2].y1 = 1;
1792     xsegs[2].x2 = dx, xsegs[2].y2 = dy;
1793     xsegs[3].x1 = dx - 1, xsegs[3].y1 = 2;
1794     xsegs[3].x2 = dx - 1, xsegs[3].y2 = dy;
1795     XDrawSegments(dpy, item->header.win, item->header.dt_ptr->dt_item_GC,
1796 		  xsegs, 4);
1797 
1798     if (click) {
1799       x = BOX_SPC + TEXT_SPC +
1800 	      FlocaleTextWidth(item->header.dt_ptr->dt_Ffont,
1801 			       item->input.value, CF.abs_cursor) - 1;
1802       XSetForeground(dpy, item->header.dt_ptr->dt_item_GC,
1803 		     item->header.dt_ptr->dt_colors[c_item_bg]);
1804       XDrawLine(dpy, item->header.win, item->header.dt_ptr->dt_item_GC,
1805 		x, BOX_SPC, x, dy - BOX_SPC);
1806       myfprintf((stderr,"Line %d/%d - %d/%d (first)\n",
1807 		     x, BOX_SPC, x, dy - BOX_SPC));
1808     }
1809     len = item->input.n - item->input.left;
1810     XSetForeground(dpy, item->header.dt_ptr->dt_item_GC,
1811 		   item->header.dt_ptr->dt_colors[c_item_fg]);
1812     item->header.dt_ptr->dt_Fstr->win = item->header.win;
1813     item->header.dt_ptr->dt_Fstr->gc  = item->header.dt_ptr->dt_item_GC;
1814     item->header.dt_ptr->dt_Fstr->flags.has_colorset = False;
1815     if (itemcolorset >= 0)
1816     {
1817       item->header.dt_ptr->dt_Fstr->colorset = &Colorset[itemcolorset];
1818       item->header.dt_ptr->dt_Fstr->flags.has_colorset = True;
1819     }
1820     if (len > item->input.size)
1821       len = item->input.size;
1822     else
1823     {
1824       item->header.dt_ptr->dt_Fstr->str = item->input.blanks;
1825       item->header.dt_ptr->dt_Fstr->x  = BOX_SPC + TEXT_SPC +
1826 	      FlocaleTextWidth(item->header.dt_ptr->dt_Ffont,
1827 			       item->input.blanks, len);
1828       item->header.dt_ptr->dt_Fstr->y	= BOX_SPC + TEXT_SPC
1829 		  + item->header.dt_ptr->dt_Ffont->ascent;
1830       item->header.dt_ptr->dt_Fstr->len = item->input.size - len;
1831       FlocaleDrawString(dpy,
1832 			item->header.dt_ptr->dt_Ffont,
1833 			item->header.dt_ptr->dt_Fstr, FWS_HAVE_LENGTH);
1834     }
1835     item->header.dt_ptr->dt_Fstr->str = item->input.value;
1836     item->header.dt_ptr->dt_Fstr->x   = BOX_SPC + TEXT_SPC;
1837     item->header.dt_ptr->dt_Fstr->y   = BOX_SPC + TEXT_SPC
1838       + item->header.dt_ptr->dt_Ffont->ascent;
1839     item->header.dt_ptr->dt_Fstr->len = len;
1840     FlocaleDrawString(dpy,
1841 		      item->header.dt_ptr->dt_Ffont,
1842 		      item->header.dt_ptr->dt_Fstr, FWS_HAVE_LENGTH);
1843     if (item == CF.cur_input && !click) {
1844       x = BOX_SPC + TEXT_SPC +
1845 	FlocaleTextWidth(item->header.dt_ptr->dt_Ffont,
1846 			 item->input.value,CF.abs_cursor)
1847 	- 1;
1848       XDrawLine(dpy, item->header.win, item->header.dt_ptr->dt_item_GC,
1849 		x, BOX_SPC, x, dy - BOX_SPC);
1850       myfprintf((stderr,"Line %d/%d - %d/%d\n",
1851 		 x, BOX_SPC, x, dy - BOX_SPC));
1852     }
1853     myfprintf((stderr,"Just drew input field. click %d\n",(int)click));
1854     break;
1855   case I_CHOICE:
1856     dx = dy = item->header.size_y - 1;
1857     if (item->choice.on) {
1858 	XSetForeground(dpy, item->header.dt_ptr->dt_item_GC,
1859 		       item->header.dt_ptr->dt_colors[c_item_fg]);
1860       if (item->choice.sel->selection.key == IS_MULTIPLE) {
1861 	xsegs[0].x1 = 5, xsegs[0].y1 = 5;
1862 	xsegs[0].x2 = dx - 5, xsegs[0].y2 = dy - 5;
1863 	xsegs[1].x1 = 5, xsegs[1].y1 = dy - 5;
1864 	xsegs[1].x2 = dx - 5, xsegs[1].y2 = 5;
1865 	XDrawSegments(dpy, item->header.win, item->header.dt_ptr->dt_item_GC,
1866 		      xsegs, 2);
1867       } else {
1868 	XDrawArc(dpy, item->header.win, item->header.dt_ptr->dt_item_GC,
1869 		 5, 5, dx - 10, dy - 10, 0, 360 * 64);
1870       }
1871     } else
1872       XClearWindow(dpy, item->header.win);
1873     if (item->choice.on)
1874       XSetForeground(dpy, item->header.dt_ptr->dt_item_GC,
1875 		     item->header.dt_ptr->dt_colors[c_itemlo]);
1876     else
1877       XSetForeground(dpy, item->header.dt_ptr->dt_item_GC,
1878 		     item->header.dt_ptr->dt_colors[c_itemhi]);
1879     xsegs[0].x1 = 0, xsegs[0].y1 = 0;
1880     xsegs[0].x2 = 0, xsegs[0].y2 = dy;
1881     xsegs[1].x1 = 0, xsegs[1].y1 = 0;
1882     xsegs[1].x2 = dx, xsegs[1].y2 = 0;
1883     xsegs[2].x1 = 1, xsegs[2].y1 = 1;
1884     xsegs[2].x2 = 1, xsegs[2].y2 = dy - 1;
1885     xsegs[3].x1 = 1, xsegs[3].y1 = 1;
1886     xsegs[3].x2 = dx - 1, xsegs[3].y2 = 1;
1887     XDrawSegments(dpy, item->header.win, item->header.dt_ptr->dt_item_GC,
1888 		  xsegs, 4);
1889     if (item->choice.on)
1890       XSetForeground(dpy, item->header.dt_ptr->dt_item_GC,
1891 		     item->header.dt_ptr->dt_colors[c_itemhi]);
1892     else
1893       XSetForeground(dpy, item->header.dt_ptr->dt_item_GC,
1894 		     item->header.dt_ptr->dt_colors[c_itemlo]);
1895     xsegs[0].x1 = 1, xsegs[0].y1 = dy;
1896     xsegs[0].x2 = dx, xsegs[0].y2 = dy;
1897     xsegs[1].x1 = 2, xsegs[1].y1 = dy - 1;
1898     xsegs[1].x2 = dx, xsegs[1].y2 = dy - 1;
1899     xsegs[2].x1 = dx, xsegs[2].y1 = 1;
1900     xsegs[2].x2 = dx, xsegs[2].y2 = dy;
1901     xsegs[3].x1 = dx - 1, xsegs[3].y1 = 2;
1902     xsegs[3].x2 = dx - 1, xsegs[3].y2 = dy;
1903     XDrawSegments(dpy, item->header.win, item->header.dt_ptr->dt_item_GC,
1904 		  xsegs, 4);
1905     break;
1906   case I_BUTTON:
1907     if (!text_inter)
1908     {
1909 	    return;
1910     }
1911     dx = item->header.size_x - 1;
1912     dy = item->header.size_y - 1;
1913     if (click)
1914       XSetForeground(dpy, item->header.dt_ptr->dt_item_GC,
1915 		     item->header.dt_ptr->dt_colors[c_itemlo]);
1916     else
1917       XSetForeground(dpy, item->header.dt_ptr->dt_item_GC,
1918 		     item->header.dt_ptr->dt_colors[c_itemhi]);
1919     xsegs[0].x1 = 0, xsegs[0].y1 = 0;
1920     xsegs[0].x2 = 0, xsegs[0].y2 = dy;
1921     xsegs[1].x1 = 0, xsegs[1].y1 = 0;
1922     xsegs[1].x2 = dx, xsegs[1].y2 = 0;
1923     xsegs[2].x1 = 1, xsegs[2].y1 = 1;
1924     xsegs[2].x2 = 1, xsegs[2].y2 = dy - 1;
1925     xsegs[3].x1 = 1, xsegs[3].y1 = 1;
1926     xsegs[3].x2 = dx - 1, xsegs[3].y2 = 1;
1927     XDrawSegments(dpy, item->header.win, item->header.dt_ptr->dt_item_GC,
1928 		  xsegs, 4);
1929     if (click)
1930       XSetForeground(dpy, item->header.dt_ptr->dt_item_GC,
1931 		     item->header.dt_ptr->dt_colors[c_itemhi]);
1932     else
1933       XSetForeground(dpy, item->header.dt_ptr->dt_item_GC,
1934 		     item->header.dt_ptr->dt_colors[c_itemlo]);
1935     xsegs[0].x1 = 1, xsegs[0].y1 = dy;
1936     xsegs[0].x2 = dx, xsegs[0].y2 = dy;
1937     xsegs[1].x1 = 2, xsegs[1].y1 = dy - 1;
1938     xsegs[1].x2 = dx, xsegs[1].y2 = dy - 1;
1939     xsegs[2].x1 = dx, xsegs[2].y1 = 1;
1940     xsegs[2].x2 = dx, xsegs[2].y2 = dy;
1941     xsegs[3].x1 = dx - 1, xsegs[3].y1 = 2;
1942     xsegs[3].x2 = dx - 1, xsegs[3].y2 = dy;
1943     XDrawSegments(dpy, item->header.win, item->header.dt_ptr->dt_item_GC,
1944 		  xsegs, 4);
1945     XSetForeground(dpy, item->header.dt_ptr->dt_item_GC,
1946 		   item->header.dt_ptr->dt_colors[c_item_fg]);
1947     item->header.dt_ptr->dt_Fstr->win = item->header.win;
1948     item->header.dt_ptr->dt_Fstr->gc  = item->header.dt_ptr->dt_item_GC;
1949     item->header.dt_ptr->dt_Fstr->flags.has_colorset = False;
1950     if (itemcolorset >= 0)
1951     {
1952       item->header.dt_ptr->dt_Fstr->colorset = &Colorset[itemcolorset];
1953       item->header.dt_ptr->dt_Fstr->flags.has_colorset = True;
1954     }
1955     item->header.dt_ptr->dt_Fstr->str = item->button.text;
1956     item->header.dt_ptr->dt_Fstr->x   = BOX_SPC + TEXT_SPC;
1957     item->header.dt_ptr->dt_Fstr->y   = BOX_SPC + TEXT_SPC
1958       + item->header.dt_ptr->dt_Ffont->ascent;
1959     item->header.dt_ptr->dt_Fstr->len = item->button.len;
1960     if (FftSupport)
1961     {
1962       if (item->header.dt_ptr->dt_Ffont->fftf.fftfont != NULL)
1963 	XClearArea(dpy, item->header.win,
1964 		   inter.x, inter.y, inter.width, inter.height, False);
1965     }
1966     FlocaleDrawString(dpy,
1967 		      item->header.dt_ptr->dt_Ffont,
1968 		      item->header.dt_ptr->dt_Fstr, FWS_HAVE_LENGTH);
1969     myfprintf((stderr,"Just put %s into a button\n",
1970 	       item->button.text));
1971     break;
1972   case I_SEPARATOR:
1973     RedrawSeparator(item);
1974     break;
1975   }
1976   if (dt_ptr && dt_ptr->dt_Fstr)
1977   {
1978 	  dt_ptr->dt_Fstr->flags.has_clip_region = False;
1979   }
1980   if (region)
1981   {
1982 	  XDestroyRegion(region);
1983   }
1984   XFlush(dpy);
1985 }
1986 
1987 /* update transparency if background colorset is transparent */
1988 /* window has moved redraw the background if it is transparent */
UpdateRootTransapency(Bool pr_only,Bool do_draw)1989 void UpdateRootTransapency(Bool pr_only, Bool do_draw)
1990 {
1991 	Item *item;
1992 
1993 	if (CSET_IS_TRANSPARENT(colorset))
1994 	{
1995 		if (CSET_IS_TRANSPARENT_PR_PURE(colorset))
1996 		{
1997 			XClearArea(dpy, CF.frame, 0,0,0,0, False);
1998 			if (do_draw)
1999 			{
2000 				RedrawFrame(NULL);
2001 			}
2002 		}
2003 		else if (!pr_only || CSET_IS_TRANSPARENT_PR(colorset))
2004 		{
2005 			SetWindowBackground(
2006 				dpy, CF.frame, CF.max_width, CF.total_height,
2007 				&Colorset[(colorset)], Pdepth,
2008 				root_item_ptr->header.dt_ptr->dt_GC, False);
2009 			if (do_draw)
2010 			{
2011 				XClearArea(dpy, CF.frame, 0,0,0,0, False);
2012 				RedrawFrame(NULL);
2013 			}
2014 		}
2015 	}
2016 	if (!root_item_ptr->header.next || !CSET_IS_TRANSPARENT(itemcolorset))
2017 	{
2018 		return;
2019 	}
2020 	for (item = root_item_ptr->header.next; item != NULL;
2021 	     item = item->header.next)
2022 	{
2023 		if (item->header.win != None)
2024 		{
2025 			if (CSET_IS_TRANSPARENT_PR(itemcolorset) &&
2026 			    !CSET_IS_TRANSPARENT(colorset))
2027 			{
2028 				continue;
2029 			}
2030 			if (CSET_IS_TRANSPARENT_PR_PURE(itemcolorset))
2031 			{
2032 				XClearArea(
2033 					dpy, item->header.win, 0,0,0,0, False);
2034 				if (do_draw)
2035 				{
2036 					RedrawItem(item, 0, NULL);
2037 				}
2038 			}
2039 			else if (!pr_only ||
2040 				 CSET_IS_TRANSPARENT_PR(itemcolorset))
2041 			{
2042 				SetWindowBackground(
2043 					dpy, item->header.win,
2044 					item->header.size_x, item->header.size_y,
2045 					&Colorset[(itemcolorset)], Pdepth,
2046 					item->header.dt_ptr->dt_GC, False);
2047 				XClearArea(
2048 					dpy, item->header.win, 0,0,0,0, False);
2049 				if (do_draw)
2050 				{
2051 					RedrawItem(item, 0, NULL);
2052 				}
2053 			}
2054 		}
2055 	}
2056 }
2057 
2058 /* execute a command */
DoCommand(Item * cmd)2059 void DoCommand (Item *cmd)
2060 {
2061   int k, dn;
2062   char *sp;
2063   Item *item;
2064 
2065   /* pre-command */
2066   if (cmd->button.key == IB_QUIT)
2067   {
2068     if (!XWithdrawWindow(dpy, CF.frame, screen))
2069     {
2070       /* hm, what can we do now? just ignore this situation. */
2071     }
2072   }
2073 
2074   for (k = 0; k < cmd->button.n; k++) {
2075     char *parsed_command;
2076     /* construct command */
2077     parsed_command = ParseCommand(0, cmd->button.commands[k], '\0', &dn, &sp);
2078     myfprintf((stderr, "Final command[%d]: [%s]\n", k, parsed_command));
2079 
2080     /* send command */
2081     if ( parsed_command[0] == '!') {	/* If command starts with ! */
2082       int n;
2083 
2084       n = system(parsed_command+1);		/* Need synchronous execution */
2085       (void)n;
2086     } else {
2087       SendText(Channel,parsed_command, ref);
2088     }
2089   }
2090 
2091   /* post-command */
2092   if (CF.last_error) {			/* if form has last_error field */
2093     memset(CF.last_error->text.value, ' ', CF.last_error->text.n); /* clear */
2094     /* To do this more elegantly, the window resize logic should recalculate
2095        size_x for the Message as the window resizes.  Right now, just clear
2096        a nice wide area. dje */
2097     XClearArea(dpy,CF.frame,
2098 	       CF.last_error->header.pos_x,
2099 	       CF.last_error->header.pos_y,
2100 	       /* CF.last_error->header.size_x, */
2101 	       2000,
2102 	       CF.last_error->header.size_y, False);
2103   } /* end form has last_error field */
2104   if (cmd->button.key == IB_QUIT) {
2105     if (CF.grab_server)
2106       XUngrabServer(dpy);
2107     /* This is a temporary bug workaround for the pipe drainage problem */
2108     SendQuitNotification(Channel);    /* let commands complete */
2109     /* Note how the window is withdrawn, but execution continues until
2110        the quit notifcation catches up with this module...
2111        Should not be a problem, there shouldn't be any more commands
2112        coming into FvwmForm.  dje */
2113   }
2114   else if (cmd->button.key == IB_RESTART) {
2115     Restart();
2116     for (item = root_item_ptr; item != 0;
2117 	 item = item->header.next) {	/* all items */
2118       if (item->type == I_INPUT) {
2119 	XClearWindow(dpy, item->header.win);
2120 	RedrawItem(item, 0, NULL);
2121       }
2122       if (item->type == I_CHOICE)
2123 	RedrawItem(item, 0, NULL);
2124     }
2125   }
2126 }
2127 
2128 /* open the windows */
OpenWindows(void)2129 static void OpenWindows(void)
2130 {
2131   int x, y;
2132   int gravity = NorthWestGravity;
2133   Item *item;
2134   static XSetWindowAttributes xswa;
2135   static XWMHints wmh = { InputHint, True };
2136   static XSizeHints sh =
2137     { PPosition | PSize | USPosition | USSize | PWinGravity};
2138   XClassHint myclasshints;
2139 
2140   if (!CF.pointer[input_pointer]) {
2141     CF.pointer[input_pointer] = XCreateFontCursor(dpy, XC_xterm);
2142   }
2143   if (!CF.pointer[button_in_pointer]) {
2144     CF.pointer[button_in_pointer] = XCreateFontCursor(dpy, XC_hand2);
2145   }
2146   if (!CF.pointer[button_pointer]) {
2147     CF.pointer[button_pointer] = XCreateFontCursor(dpy,XC_hand2);
2148   }
2149   CF.screen_background = (colorset < 0)
2150     ? GetColor(screen_background_color)
2151     : Colorset[colorset].bg;
2152 
2153   if (!CF.p_c[input_back].used) {  /* if not set, use screen b/g */
2154     CF.p_c[input_back].pointer_color.pixel = CF.screen_background;
2155   }
2156   myfprintf((stderr,
2157 	     "screen bg %X, getcolor bg %X, colorset bg %X colorset %d\n",
2158 	     (int)CF.screen_background,
2159 	     (int)GetColor(screen_background_color),
2160 	     (int)Colorset[colorset].bg,
2161 	     (int)colorset));
2162   XQueryColor(dpy, Pcmap, &CF.p_c[input_fore].pointer_color);
2163   XQueryColor(dpy, Pcmap, &CF.p_c[input_back].pointer_color);
2164   XRecolorCursor(dpy, CF.pointer[input_pointer],
2165 		 &CF.p_c[input_fore].pointer_color,
2166 		 &CF.p_c[input_back].pointer_color);
2167   myfprintf((stderr,"input fore %X, back %X\n",
2168 	  (int)CF.p_c[input_fore].pointer_color.pixel,
2169 	  (int)CF.p_c[input_back].pointer_color.pixel));
2170   /* The input cursor is handled differently than the 2 button cursors. */
2171   XQueryColor(dpy, Pcmap, &CF.p_c[button_fore].pointer_color);
2172   XQueryColor(dpy, Pcmap, &CF.p_c[button_back].pointer_color);
2173   XRecolorCursor(dpy, CF.pointer[button_pointer],
2174 		 &CF.p_c[button_fore].pointer_color,
2175 		 &CF.p_c[button_back].pointer_color);
2176   myfprintf((stderr,"button fore %X, back %X\n",
2177 	  (int)CF.p_c[button_fore].pointer_color.pixel,
2178 	  (int)CF.p_c[button_back].pointer_color.pixel));
2179   XQueryColor(dpy, Pcmap, &CF.p_c[button_in_fore].pointer_color);
2180   XQueryColor(dpy, Pcmap, &CF.p_c[button_in_back].pointer_color);
2181   XRecolorCursor(dpy, CF.pointer[button_in_pointer],
2182 		 &CF.p_c[button_in_fore].pointer_color,
2183 		 &CF.p_c[button_in_back].pointer_color);
2184   myfprintf((stderr,"button in fore %X, back %X\n",
2185 	  (int)CF.p_c[button_in_fore].pointer_color.pixel,
2186 	  (int)CF.p_c[button_in_back].pointer_color.pixel));
2187   /* the frame window first */
2188   if (CF.have_geom)
2189   {
2190     if (CF.xneg)
2191     {
2192       x = DisplayWidth(dpy, screen) - CF.max_width + CF.gx;
2193       gravity = NorthEastGravity;
2194     }
2195     else
2196     {
2197       x = CF.gx;
2198     }
2199     if (CF.yneg)
2200     {
2201       y = DisplayHeight(dpy, screen) - CF.total_height + CF.gy;
2202       gravity = SouthWestGravity;
2203     }
2204     else
2205     {
2206       y = CF.gy;
2207     }
2208     if (CF.xneg && CF.yneg)
2209     {
2210       gravity = SouthEastGravity;
2211     }
2212   } else {
2213     FScreenCenterOnScreen(
2214       NULL, FSCREEN_CURRENT, &x, &y, CF.max_width, CF.total_height);
2215   }
2216   /* hack to prevent mapping on wrong screen with StartsOnScreen */
2217   FScreenMangleScreenIntoUSPosHints(FSCREEN_CURRENT, &sh);
2218   xswa.background_pixel = CF.screen_background;
2219   xswa.border_pixel = 0;
2220   xswa.colormap = Pcmap;
2221   myfprintf((stderr,
2222 	  "going to create window w. bg %s, b/g pixel %X, black pixel %X\n",
2223 	     screen_background_color,
2224 	     (int)xswa.background_pixel,
2225 	     (int)BlackPixel(dpy, screen)));
2226   CF.frame = XCreateWindow(dpy, root, x, y, CF.max_width, CF.total_height, 0,
2227 			   Pdepth, InputOutput, Pvisual,
2228 			   CWColormap | CWBackPixel | CWBorderPixel, &xswa);
2229   wm_del_win = XInternAtom(dpy, "WM_DELETE_WINDOW", False);
2230   XSetWMProtocols(dpy, CF.frame, &wm_del_win, 1);
2231   XSelectInput(dpy, CF.frame,
2232 	       KeyPressMask | ExposureMask | StructureNotifyMask |
2233 	       VisibilityChangeMask);
2234   if (!CF.title) {
2235     CF.title = module->name;
2236   }
2237   XStoreName(dpy, CF.frame, CF.title);
2238   XSetWMHints(dpy, CF.frame, &wmh);
2239   myclasshints.res_name = module->name;
2240   myclasshints.res_class = "FvwmForm";
2241   XSetClassHint(dpy,CF.frame,&myclasshints);
2242   sh.width = CF.max_width;
2243   sh.height = CF.total_height;
2244   sh.win_gravity = gravity;
2245   XSetWMNormalHints(dpy, CF.frame, &sh);
2246 
2247   for (item = root_item_ptr; item != 0;
2248        item = item->header.next) {	/* all items */
2249     switch (item->type) {
2250     case I_INPUT:
2251       myfprintf((stderr,"Checking alloc during OpenWindow on input\n"));
2252       CheckAlloc(item,item->header.dt_ptr); /* alloc colors and fonts needed */
2253       item->header.win =
2254 	XCreateSimpleWindow(dpy, CF.frame,
2255 			    item->header.pos_x, item->header.pos_y,
2256 			    item->header.size_x, item->header.size_y,
2257 			    0, CF.screen_background,
2258 			    item->header.dt_ptr->dt_colors[c_item_bg]);
2259       XSelectInput(dpy, item->header.win, ButtonPressMask | ExposureMask);
2260       xswa.cursor = CF.pointer[input_pointer];
2261       XChangeWindowAttributes(dpy, item->header.win, CWCursor, &xswa);
2262       if (itemcolorset >= 0)
2263       {
2264 	SetWindowBackground(dpy, item->header.win,
2265 			    item->header.size_x, item->header.size_y,
2266 			    &Colorset[(itemcolorset)], Pdepth,
2267 			    item->header.dt_ptr->dt_GC, True);
2268       }
2269       break;
2270     case I_CHOICE:
2271       myfprintf((stderr,"Checking alloc during Openwindow on choice\n"));
2272       CheckAlloc(item,item->header.dt_ptr); /* alloc colors and fonts needed */
2273       item->header.win =
2274 	XCreateSimpleWindow(dpy, CF.frame,
2275 			    item->header.pos_x, item->header.pos_y,
2276 			    item->header.size_y, item->header.size_y,
2277 			    0, CF.screen_background,
2278 			    item->header.dt_ptr->dt_colors[c_item_bg]);
2279       XSelectInput(dpy, item->header.win, ButtonPressMask | ExposureMask);
2280       xswa.cursor = CF.pointer[button_pointer];
2281       XChangeWindowAttributes(dpy, item->header.win, CWCursor, &xswa);
2282       if (itemcolorset >= 0)
2283       {
2284 	SetWindowBackground(dpy, item->header.win,
2285 			    item->header.size_x, item->header.size_y,
2286 			    &Colorset[(itemcolorset)], Pdepth,
2287 			    item->header.dt_ptr->dt_GC, True);
2288       }
2289       break;
2290     case I_BUTTON:
2291       myfprintf((stderr,"Checking alloc during Openwindow on button\n"));
2292       CheckAlloc(item,item->header.dt_ptr); /* alloc colors and fonts needed */
2293       item->header.win =
2294 	XCreateSimpleWindow(dpy, CF.frame,
2295 			    item->header.pos_x, item->header.pos_y,
2296 			    item->header.size_x, item->header.size_y,
2297 			    0, CF.screen_background,
2298 			    item->header.dt_ptr->dt_colors[c_item_bg]);
2299       XSelectInput(dpy, item->header.win,
2300 		   ButtonPressMask | ExposureMask);
2301       xswa.cursor = CF.pointer[button_pointer];
2302       XChangeWindowAttributes(dpy, item->header.win, CWCursor, &xswa);
2303       if (itemcolorset >= 0)
2304       {
2305 	SetWindowBackground(dpy, item->header.win,
2306 			    item->header.size_x, item->header.size_y,
2307 			    &Colorset[(itemcolorset)], Pdepth,
2308 			    item->header.dt_ptr->dt_GC, True);
2309       }
2310       break;
2311     case I_SEPARATOR:
2312       myfprintf((stderr,"Checking alloc during OpenWindow on separator\n"));
2313       CheckAlloc(item,item->header.dt_ptr); /* alloc colors and fonts needed */
2314       item->header.size_x = CF.max_width - 6;
2315       myfprintf((stderr,"Create win %d/%d %d/%d\n",3,item->header.pos_y,
2316 			    item->header.size_x, 2));
2317       item->header.win =
2318 	XCreateSimpleWindow(dpy, CF.frame,
2319 			    3, item->header.pos_y,
2320 			    item->header.size_x, 2,
2321 			    0, CF.screen_background,
2322 			    item->header.dt_ptr->dt_colors[c_bg]);
2323       XSelectInput(dpy, item->header.win, ExposureMask);
2324       if (itemcolorset >= 0)
2325       {
2326 	SetWindowBackground(dpy, item->header.win,
2327 			    item->header.size_x, 2,
2328 			    &Colorset[(itemcolorset)], Pdepth,
2329 			    item->header.dt_ptr->dt_GC, True);
2330       }
2331       break;
2332     }
2333   }
2334   Restart();
2335   if (colorset >= 0)
2336   {
2337     CheckAlloc(root_item_ptr,root_item_ptr->header.dt_ptr);
2338     SetWindowBackground(dpy, CF.frame, CF.max_width, CF.total_height,
2339 			&Colorset[(colorset)], Pdepth,
2340 			root_item_ptr->header.dt_ptr->dt_GC, True);
2341   }
2342   if (preload_yorn != 'y') {		/* if not a preload */
2343     XMapRaised(dpy, CF.frame);
2344     XMapSubwindows(dpy, CF.frame);
2345     if (CF.warp_pointer) {
2346       FWarpPointer(dpy, None, CF.frame, 0, 0, 0, 0,
2347 		   CF.max_width / 2, CF.total_height - 1);
2348     }
2349   }
2350   DoCommand(&CF.def_button);
2351 }
2352 
2353 static void process_message(unsigned long, unsigned long *); /* proto */
2354 static void ParseActiveMessage(char *); /* proto */
2355 
2356 /* read something from Fvwm */
ReadFvwm(void)2357 static void ReadFvwm(void)
2358 {
2359 
2360     FvwmPacket* packet = ReadFvwmPacket(Channel[1]);
2361     if ( packet == NULL )
2362 	exit(0);
2363     else
2364 	process_message( packet->type, packet->body );
2365 }
process_message(unsigned long type,unsigned long * body)2366 static void process_message(unsigned long type, unsigned long *body)
2367 {
2368   switch (type) {
2369   case M_CONFIG_INFO:			/* any module config command */
2370     myfprintf((stderr,"process_message: Got command: %s\n", (char *)&body[3]));
2371     ParseActiveMessage((char *)&body[3]);
2372     break;
2373   case MX_PROPERTY_CHANGE:
2374     if (body[0] == MX_PROPERTY_CHANGE_BACKGROUND &&
2375 	((!Swallowed && body[2] == 0) || (Swallowed && body[2] == CF.frame)))
2376     {
2377       UpdateRootTransapency(True, True);
2378     }
2379     else if  (body[0] == MX_PROPERTY_CHANGE_SWALLOW && body[2] == CF.frame)
2380     {
2381 	Swallowed = body[1];
2382     }
2383     break;
2384   case M_ERROR:
2385   case M_STRING:
2386     if (CF.last_error) {		/* if form has message area */
2387       /* ignore form size, its OK to write outside the window boundary */
2388       int msg_len;
2389       char *msg_ptr;
2390       /* Clear old message first */
2391       memset(CF.last_error->text.value, ' ', CF.last_error->text.n); /* clear */
2392       XClearArea(dpy,CF.frame,
2393 		 CF.last_error->header.pos_x,
2394 		 CF.last_error->header.pos_y,
2395 		 2000,
2396 		 CF.last_error->header.size_y, False);
2397       msg_ptr = (char *)&body[3];
2398       msg_len = strlen(msg_ptr);
2399       if (msg_ptr[msg_len-1] == '\n') { /* line ends w newline */
2400 	msg_ptr[msg_len-1] = '\0'; /* strip off \n */
2401       }
2402       if (CF.last_error->text.n <= msg_len) { /* if message wont fit */
2403 	CF.last_error->text.value = fxrealloc(CF.last_error->text.value,
2404                                              msg_len * 2,
2405 					     sizeof(CF.last_error->text.value));
2406 	CF.last_error->text.n = msg_len * 2;
2407       }
2408       strncpy(CF.last_error->text.value,msg_ptr,
2409 	      CF.last_error->text.n);
2410       RedrawText(CF.last_error);
2411       break;
2412     } /* module has last_error field */
2413   } /* end switch header */
2414 }
2415 
2416 /* These are the message from fvwm FvwmForm understands after form is
2417    active. */
2418 static void am_Map(char *);
2419 static void am_UnMap(char *);
2420 static void am_Stop(char *);
2421 static struct CommandTable am_table[] =
2422 {
2423   {"Map",am_Map},
2424   {"Stop",am_Stop},
2425   {"UnMap",am_UnMap}
2426 };
2427 
2428 /* This is similar to the other 2 "Parse" functions. */
ParseActiveMessage(char * buf)2429 static void ParseActiveMessage(char *buf)
2430 {
2431 	char *p;
2432 	struct CommandTable *e;
2433 	if (buf[strlen(buf)-1] == '\n')
2434 	{     /* if line ends with newline */
2435 		buf[strlen(buf)-1] = '\0';  /* strip off \n */
2436 	}
2437 
2438 	if (strncasecmp(buf, "Colorset", 8) == 0)
2439 	{
2440 		Item *item;
2441 		int n = LoadColorset(&buf[8]);
2442 		if(n == colorset || n == itemcolorset)
2443 		{
2444 			for (item = root_item_ptr; item != 0;
2445 			     item = item->header.next)
2446 			{
2447 				DrawTable *dt_ptr = item->header.dt_ptr;
2448 				if (dt_ptr)
2449 				{
2450 					dt_ptr->dt_used = 0;
2451 					if(dt_ptr->dt_GC)
2452 					{
2453 						XFreeGC(dpy, dt_ptr->dt_GC);
2454 						dt_ptr->dt_GC = None;
2455 					}
2456 					if(dt_ptr->dt_item_GC)
2457 					{
2458 						XFreeGC(
2459 							dpy,
2460 							dt_ptr->dt_item_GC);
2461 						dt_ptr->dt_item_GC = None;
2462 					}
2463 				}
2464 			}
2465 			for (item = root_item_ptr; item != 0;
2466 			     item = item->header.next)
2467 			{
2468 				DrawTable *dt_ptr = item->header.dt_ptr;
2469 				if (dt_ptr)
2470 				{
2471 					CheckAlloc(item, dt_ptr);
2472 				}
2473 			}
2474 			if (colorset >= 0)
2475 			{
2476 				SetWindowBackground(
2477 					dpy, CF.frame, CF.max_width,
2478 					CF.total_height,
2479 					&Colorset[(colorset)], Pdepth,
2480 					root_item_ptr->header.dt_ptr->dt_GC,
2481 					False);
2482 				RedrawFrame(NULL);
2483 			}
2484 			for (item = root_item_ptr->header.next; item != 0;
2485 			     item = item->header.next)
2486 			{
2487 				DrawTable *dt_ptr = item->header.dt_ptr;
2488 				if (dt_ptr && itemcolorset >= 0 &&
2489 				    item->header.win != 0)
2490 				{
2491 					SetWindowBackground(
2492 						dpy, item->header.win,
2493 						item->header.size_x,
2494 						item->header.size_y,
2495 						&Colorset[(itemcolorset)],
2496 						Pdepth, dt_ptr->dt_GC, True);
2497 					RedrawItem(item, 0, NULL);
2498 				} /* end item has a drawtable */
2499 			} /* end all items */
2500 		}
2501 		return;
2502 	} /* end colorset command */
2503 #if 0
2504 	if (strncasecmp(
2505 		buf, XINERAMA_CONFIG_STRING, sizeof(XINERAMA_CONFIG_STRING)-1)
2506 	    == 0)
2507 	{
2508 		FScreenConfigureModule(buf + sizeof(XINERAMA_CONFIG_STRING)-1);
2509 		return;
2510 	}
2511 #endif
2512 	if (strncasecmp(buf, mname, module->namelen+1) != 0)
2513 	{
2514 		/* If its not for me */
2515 		return;
2516 	} /* Now I know its for me. */
2517 	p = buf+module->namelen+1;		    /* jump to end of my name */
2518 	/* at this point we have recognized "*FvwmForm" */
2519 	e = FindToken(p,am_table,struct CommandTable);/* find cmd in table */
2520 	if (e == 0)
2521 	{
2522 		/* if no match */
2523 		/* this may be a configuration command of another same form */
2524 		if (FindToken(p, ct_table, struct CommandTable) == 0)
2525 			fprintf(
2526 				stderr,"%s: Active command unknown: %s\n",
2527 				module->name,buf);
2528 		return;				    /* ignore it */
2529 	}
2530 
2531 	p=p+strlen(e->name);			/* skip over name */
2532 	while (isspace((unsigned char)*p)) p++; /* skip whitespace */
2533 
2534 	FormVarsCheck(&p);
2535 	e->function(p);			      /* call cmd processor */
2536 	return;
2537 } /* end function */
2538 
am_Map(char * cp)2539 static void am_Map(char *cp)
2540 {
2541   XMapRaised(dpy, CF.frame);
2542   XMapSubwindows(dpy, CF.frame);
2543   if (CF.warp_pointer) {
2544     FWarpPointer(dpy, None, CF.frame, 0, 0, 0, 0,
2545 		 CF.max_width / 2, CF.total_height - 1);
2546   }
2547   myfprintf((stderr, "Map: got it\n"));
2548 }
am_UnMap(char * cp)2549 static void am_UnMap(char *cp)
2550 {
2551   XUnmapWindow(dpy, CF.frame);
2552   myfprintf((stderr, "UnMap: got it\n"));
2553 }
am_Stop(char * cp)2554 static void am_Stop(char *cp)
2555 {
2556   /* syntax: *FFStop */
2557   myfprintf((stderr,"Got stop command.\n"));
2558   exit (0);				/* why bother, just exit. */
2559 }
2560 
2561 /* main event loop */
MainLoop(void)2562 static void MainLoop(void)
2563 {
2564   fd_set fds;
2565   fd_set_size_t fd_width = GetFdWidth();
2566 
2567   while ( !isTerminated ) {
2568     /* TA:  20091219:  Automatically flush the buffer from the XServer and
2569      * process each request as we receive them.
2570      */
2571     while(FPending(dpy))
2572 	    ReadXServer();
2573 
2574     FD_ZERO(&fds);
2575     FD_SET(Channel[1], &fds);
2576     FD_SET(fd_x, &fds);
2577 
2578     /* TA:  20091219:  Using XFlush() here was always a nasty hack!  See
2579      * comments above.
2580      */
2581     /*XFlush(dpy);*/
2582     if (fvwmSelect(fd_width, &fds, NULL, NULL, NULL) > 0) {
2583       if (FD_ISSET(Channel[1], &fds))
2584 	ReadFvwm();
2585       if (FD_ISSET(fd_x, &fds))
2586 	ReadXServer();
2587     }
2588   }
2589 }
2590 
2591 
2592 /* signal-handler to make the application quit */
2593 static RETSIGTYPE
TerminateHandler(int sig)2594 TerminateHandler(int sig)
2595 {
2596   fvwmSetTerminate(sig);
2597   SIGNAL_RETURN;
2598 }
2599 
2600 /* signal-handler to make the timer work */
2601 static void
TimerHandler(evutil_socket_t fd,short ev,void * arg)2602 TimerHandler(evutil_socket_t fd, short ev, void *arg)
2603 {
2604   int dn;
2605   char *sp;
2606   char *parsed_command;
2607 
2608   timer->timeout.timeleft--;
2609   if (timer->timeout.timeleft <= 0) {
2610     evtimer_del(pev);
2611 
2612     /* pre-command */
2613     if (!XWithdrawWindow(dpy, CF.frame, screen))
2614     {
2615       /* hm, what can we do now? just ignore this situation. */
2616     }
2617 
2618     /* construct command */
2619     parsed_command = ParseCommand(0, timer->timeout.command, '\0', &dn, &sp);
2620     myfprintf((stderr, "Final command: %s\n", parsed_command));
2621 
2622     /* send command */
2623     if ( parsed_command[0] == '!') {	/* If command starts with ! */
2624       int n;
2625 
2626       n = system(parsed_command+1);		/* Need synchronous execution */
2627       (void)n;
2628     } else {
2629       SendText(Channel,parsed_command, ref);
2630     }
2631 
2632     /* post-command */
2633     if (CF.last_error) {		  /* if form has last_error field */
2634       memset(CF.last_error->text.value, ' ', CF.last_error->text.n); /* clear */
2635       /* To do this more elegantly, the window resize logic should recalculate
2636 	 size_x for the Message as the window resizes.	Right now, just clear
2637 	 a nice wide area. dje */
2638       XClearArea(dpy,CF.frame,
2639 		 CF.last_error->header.pos_x,
2640 		 CF.last_error->header.pos_y,
2641 		 /* CF.last_error->header.size_x, */
2642 		 2000,
2643 		 CF.last_error->header.size_y, False);
2644     } /* end form has last_error field */
2645     if (CF.grab_server)
2646       XUngrabServer(dpy);
2647     /* This is a temporary bug workaround for the pipe drainage problem */
2648     SendQuitNotification(Channel);    /* let commands complete */
2649     /* Note how the window is withdrawn, but execution continues until
2650        the quit notifcation catches up with this module...
2651        Should not be a problem, there shouldn't be any more commands
2652        coming into FvwmForm.  dje */
2653   }
2654   else {
2655     RedrawTimeout(timer);
2656   }
2657 
2658   SIGNAL_RETURN;
2659 }
2660 
2661 
2662 /* main procedure */
main(int argc,char ** argv)2663 int main (int argc, char **argv)
2664 {
2665   int i;
2666   char cmd[200];
2667 
2668 #ifdef DEBUGTOFILE
2669   freopen(".FvwmFormDebug","w",stderr);
2670 #endif
2671 
2672   FlocaleInit(LC_CTYPE, "", "", "FvwmForm");
2673 
2674   module = ParseModuleArgs(argc,argv,1); /* allow an alias */
2675   if (module == NULL)
2676   {
2677     fprintf(
2678 	    stderr,
2679 	    "FvwmForm Version "VERSION" should only be executed by fvwm!\n");
2680     exit(1);
2681   }
2682 
2683   xasprintf(&mname, "*%s", module->name);
2684 
2685 #ifdef HAVE_SIGACTION
2686   {
2687     struct sigaction  sigact;
2688 
2689 #ifdef SA_INTERRUPT
2690     sigact.sa_flags = SA_INTERRUPT;
2691 #else
2692     sigact.sa_flags = 0;
2693 #endif
2694     sigemptyset(&sigact.sa_mask);
2695     sigaddset(&sigact.sa_mask, SIGTERM);
2696     sigaddset(&sigact.sa_mask, SIGPIPE);
2697     sigaddset(&sigact.sa_mask, SIGINT);
2698     sigact.sa_handler = TerminateHandler;
2699 
2700     sigaction(SIGPIPE, &sigact, NULL);
2701     sigaction(SIGTERM, &sigact, NULL);
2702     sigaction(SIGINT, &sigact, NULL);
2703   }
2704 #else
2705 #ifdef USE_BSD_SIGNALS
2706   fvwmSetSignalMask( sigmask(SIGPIPE) | sigmask(SIGTERM) | sigmask(SIGINT) );
2707 #endif
2708   signal(SIGPIPE, TerminateHandler);  /* Dead pipe == Fvwm died */
2709   signal(SIGTERM, TerminateHandler);
2710   signal(SIGINT, TerminateHandler);
2711 #ifdef HAVE_SIGINTERRUPT
2712   siginterrupt(SIGPIPE, 1);
2713   siginterrupt(SIGTERM, 1);
2714   siginterrupt(SIGINT, 1);
2715 #endif
2716 #endif
2717 
2718   Channel[0] = module->to_fvwm;
2719   Channel[1] = module->from_fvwm;
2720 
2721   dpy = XOpenDisplay("");
2722   if (dpy==NULL) {
2723     fprintf(stderr,"%s: could not open display\n",module->name);
2724     exit(1);
2725   }
2726   /* From FvwmAnimate end */
2727 
2728   i = 7;
2729   if (argc >= 8) {			/* if have arg 7 */
2730     if (strcasecmp(argv[7],"preload") == 0) { /* if its preload */
2731       preload_yorn = 'y';		/* remember that. */
2732       i = 8;
2733     }
2734   }
2735   for (;i<argc;i++) {			/* look at remaining args */
2736     if (strchr(argv[i],'=')) {		/* if its a candidate */
2737       putenv(argv[i]);			/* save it away */
2738       CF.have_env_var = 'y';		/* remember we have at least one */
2739     }
2740   }
2741   ref = strtol(argv[4], NULL, 16);	/* capture reference window */
2742   if (ref == 0) ref = None;
2743   myfprintf((stderr, "ref == %d\n", (int)ref));
2744 
2745   flib_init_graphics(dpy);
2746 
2747   fd_x = XConnectionNumber(dpy);
2748 
2749   screen = DefaultScreen(dpy);
2750   root = RootWindow(dpy, screen);
2751 
2752   InitConstants();
2753   ReadDefaults();			/* get config from fvwm */
2754 
2755   if (strcasecmp(module->name,"FvwmForm") != 0) { /* if not already read */
2756     sprintf(cmd,"read %s Quiet",module->name); /* read quiet modules config */
2757     SendText(Channel,cmd,0);
2758   }
2759 
2760   ReadConfig();				/* get config from fvwm */
2761 
2762   MassageConfig();			/* add data, calc window x/y */
2763 
2764   /* tell fvwm about our mask */
2765   SetMessageMask(Channel, M_SENDCONFIG|M_CONFIG_INFO|M_ERROR|M_STRING);
2766   SetMessageMask(Channel, MX_PROPERTY_CHANGE);
2767   XSetErrorHandler(ErrorHandler);
2768   OpenWindows();			/* create initial window */
2769   SendFinishedStartupNotification(Channel);/* tell fvwm we're running */
2770   if (timer != NULL) {
2771      SetupTimer();
2772   }
2773   MainLoop();				/* start */
2774 
2775   return 0;				/* */
2776 }
2777 
2778 
DeadPipe(int nonsense)2779 RETSIGTYPE DeadPipe(int nonsense)
2780 {
2781   exit(0);
2782   SIGNAL_RETURN;
2783 }
2784 
2785 /*
2786   X Error Handler
2787 */
2788 static int
ErrorHandler(Display * dpy,XErrorEvent * event)2789 ErrorHandler(Display *dpy, XErrorEvent *event)
2790 {
2791   /* some errors are OK=ish */
2792   if (event->error_code == BadPixmap)
2793     return 0;
2794   if (event->error_code == BadDrawable)
2795     return 0;
2796   if (FRenderGetErrorCodeBase() + FRenderBadPicture == event->error_code)
2797     return 0;
2798 
2799   PrintXErrorAndCoredump(dpy, event, module->name);
2800   return 0;
2801 }
2802 /*  Local Variables: */
2803 /*  c-basic-offset: 8 */
2804 /*  indent-tabs-mode: t */
2805 /*  End: */
2806