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