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