1 /*
2 * Copyright (c) 2000 Andrew Ferguson <andrew@owsla.cjb.net>
3 * Copyright (c) 1998 Sasha Vasko <sasha at aftercode.net>
4 *
5 * This program is free software; you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License as published by
7 * the Free Software Foundation; either version 2 of the License, or
8 * (at your option) any later version.
9 *
10 * This program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
14 *
15 * You should have received a copy of the GNU General Public License
16 * along with this program; if not, write to the Free Software
17 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
18 *
19 */
20
21 /*#define DO_CLOCKING */
22
23 #define LOCAL_DEBUG
24 #include "../configure.h"
25 #include "asapp.h"
26 #include "session.h"
27 #include "afterstep.h"
28 #include "screen.h"
29 #include "parser.h"
30 #include "functions.h"
31 #include "freestor.h"
32 #include "../libAfterImage/afterimage.h"
33
34
change_func_code(const char * func_name,FunctionCode new_code)35 FunctionCode change_func_code (const char *func_name,
36 FunctionCode new_code)
37 {
38 TermDef *fterm;
39 if (IsValidFunc (new_code)
40 && (fterm = txt2fterm (func_name, True)) != NULL)
41 fterm->id = new_code;
42 }
43
44 /*************************************************************************/
45 /* parsing code :
46 */
txt2fterm(const char * txt,int quiet)47 TermDef *txt2fterm (const char *txt, int quiet)
48 {
49 TermDef *fterm;
50
51 if (pFuncSyntax->term_hash == NULL)
52 PrepareSyntax ((SyntaxDef *) pFuncSyntax);
53 if ((fterm =
54 FindStatementTerm ((char *)txt, (SyntaxDef *) pFuncSyntax)) == NULL
55 && !quiet)
56 show_error ("unknown function name in function specification [%s].\n",
57 txt);
58
59 return fterm;
60 }
61
txt2func_code(const char * text)62 int txt2func_code (const char *text)
63 {
64 TermDef *fterm;
65
66 for (; isspace (*text); text++) ;
67 fterm = txt2fterm (text, True);
68 return (fterm != NULL) ? fterm->id : F_FUNCTIONS_NUM;
69 }
70
txt2func(const char * text,FunctionData * fdata,int quiet)71 int txt2func (const char *text, FunctionData * fdata, int quiet)
72 {
73 TermDef *fterm;
74
75 for (; isspace (*text); text++) ;
76 fterm = txt2fterm (text, quiet);
77 if (fterm != NULL) {
78 init_func_data (fdata);
79 fdata->func = fterm->id;
80 for (; !isspace (*text) && *text; text++) ;
81 for (; isspace (*text); text++) ;
82 if (*text) {
83 const char *ptr = text + strlen ((char *)text);
84
85 for (; isspace (*(ptr - 1)); ptr--) ;
86 fdata->text = mystrndup (text, ptr - text);
87 }
88 }
89 return (fterm != NULL);
90 }
91
parse_func(const char * text,FunctionData * data,int quiet)92 int parse_func (const char *text, FunctionData * data, int quiet)
93 {
94 TermDef *fterm;
95 char *ptr;
96 int curr_arg = 0;
97 int sign = 0;
98
99 init_func_data (data);
100 for (ptr = (char *)text; isspace (*ptr); ptr++) ;
101 if (*ptr == '\0') {
102 if (!quiet)
103 show_error ("empty function specification encountered.%s");
104 return -1;
105 }
106
107 if ((fterm = txt2fterm (ptr, quiet)) == NULL)
108 return -2;
109
110 if (IsInternFunc (fterm->id))
111 return 0;
112
113 while (!isspace (*ptr) && *ptr)
114 ptr++;
115 data->func = fterm->id;
116 if (fterm->flags & TF_SYNTAX_TERMINATOR)
117 return 0;
118
119 set_func_val (data, -1, default_func_val (data->func));
120
121 /* now let's do actual parsing */
122 if (!(fterm->flags & NEED_CMD))
123 ptr = stripcomments (ptr);
124 else { /* we still want to strip trailing whitespaces */
125 char *tail = ptr + strlen (ptr) - 1;
126
127 for (; isspace (*tail) && tail > ptr; tail--) ;
128 *(tail + 1) = '\0';
129 }
130 /* this function is very often called so we try to use as little
131 calls to other function as possible */
132 for (; *ptr; ptr++) {
133 if (!isspace (*ptr)) {
134 int is_text = 0;
135
136 if (*ptr == '"') {
137 char *tail = ptr;
138 char *text;
139
140 while (*(tail + 1) && *(tail + 1) != '"')
141 tail++;
142 if (*(tail + 1) == '\0') {
143 show_error ("impaired doublequotes encountered in [%s].", ptr);
144 return -3;
145 }
146 text = mystrndup (ptr + 1, (tail - ptr));
147 if (data->name == NULL)
148 data->name = text;
149 else if (data->text == NULL)
150 data->text = text;
151 ptr = tail + 1;
152 } else if (isdigit (*ptr)) {
153 int count;
154 char unit = '\0';
155 int val = 0;
156
157 for (count = 1; isdigit (*(ptr + count)); count++) ;
158 if (*(ptr + count) != '\0' && !isspace (*(ptr + count)))
159 is_text = (!isspace (*(ptr + count + 1))
160 && *(ptr + count + 1) != '\0') ? 1 : 0;
161 if (is_text == 0)
162 ptr = parse_func_args (ptr, &unit, &val) - 1;
163 if (curr_arg < MAX_FUNC_ARGS) {
164 data->func_val[curr_arg] = (sign != 0) ? val * sign : val;
165 data->unit[curr_arg] = unit;
166 curr_arg++;
167 }
168 } else if (*ptr == '-') {
169 if (sign == 0) {
170 sign--;
171 continue;
172 } else
173 is_text = 1;
174 } else if (*ptr == '+') {
175 if (sign == 0) {
176 sign++;
177 continue;
178 } else
179 is_text = 1;
180 } else
181 is_text = 1;
182
183 if (is_text) {
184 if (sign != 0)
185 ptr--;
186 if (data->text == NULL) {
187 if (fterm->flags & NEED_CMD) {
188 data->text = mystrdup (ptr);
189 break;
190 }
191 ptr = parse_token (ptr, &(data->text)) - 1;
192 } else
193 while (*(ptr + 1) && !isspace (*(ptr + 1)))
194 ptr++;
195 }
196 sign = 0;
197 }
198 }
199
200 decode_func_units (data);
201 data->hotkey = scan_for_hotkey (data->name);
202
203 /* now let's check for valid number of arguments */
204 if ((fterm->flags & NEED_NAME) && data->name == NULL) {
205 show_error ("function specification requires \"name\" in [%s].", text);
206 return FUNC_ERR_NO_NAME;
207 }
208 if (data->text == NULL) {
209 if ((fterm->flags & NEED_WINDOW)
210 || ((fterm->flags & NEED_WINIFNAME) && data->name != NULL)) {
211 show_error ("function specification requires window name in [%s].",
212 text);
213 return FUNC_ERR_NO_TEXT;
214 }
215 if (fterm->flags & NEED_CMD) {
216 show_error
217 ("function specification requires shell command or full file name in [%s].",
218 text);
219 return FUNC_ERR_NO_TEXT;
220 }
221 }
222 /*
223 if( data->func == F_SCROLL )
224 {
225 fprintf( stderr,"Function parsed: [%s] [%s] [%s] [%d] [%d] [%c]\n",fterm->keyword,data->name,data->text,data->func_val[0], data->func_val[1],data->hotkey );
226 fprintf( stderr,"from: [%s]\n", text );
227 }
228 */
229 return 0;
230 }
231
232 #if 0
233 FunctionData *String2Func (const char *string, FunctionData * p_fdata,
234 Bool quiet)
235 {
236 if (p_fdata)
237 free_func_data (p_fdata);
238 else
239 p_fdata = safecalloc (1, sizeof (FunctionData));
240
241 LOCAL_DEBUG_OUT ("parsing message \"%s\"", string);
242 if (parse_func (string, p_fdata, quiet) < 0) {
243 LOCAL_DEBUG_OUT ("parsing failed%s", "");
244 free_func_data (p_fdata);
245 free (p_fdata);
246 p_fdata = NULL;
247 } else
248 LOCAL_DEBUG_OUT ("parsing success with func = %d", p_fdata->func);
249 return p_fdata;
250 }
251
252 #endif
253 /****************************************************************************/
254 /* FunctionData - related code */
init_func_data(FunctionData * data)255 void init_func_data (FunctionData * data)
256 {
257 int i;
258
259 if (data) {
260 data->func = F_NOP;
261 for (i = 0; i < MAX_FUNC_ARGS; i++) {
262 data->func_val[i] = DEFAULT_OTHERS;
263 data->unit_val[i] = 0;
264 data->unit[i] = '\0';
265 }
266 data->hotkey = '\0';
267 data->name = data->text = NULL;
268 data->name_encoding = 0;
269 data->popup = NULL;
270 }
271 }
272
copy_func_data(FunctionData * dst,FunctionData * src)273 void copy_func_data (FunctionData * dst, FunctionData * src)
274 {
275 if (dst && src) {
276 register int i;
277
278 dst->func = src->func;
279 dst->name = src->name;
280 dst->name_encoding = src->name_encoding;
281 dst->text = src->text;
282 for (i = 0; i < MAX_FUNC_ARGS; i++) {
283 dst->func_val[i] = src->func_val[i];
284 dst->unit[i] = src->unit[i];
285 dst->unit_val[i] = src->unit_val[i];
286 }
287 dst->hotkey = src->hotkey;
288 dst->popup = src->popup;
289 }
290 }
291
dup_func_data(FunctionData * dst,FunctionData * src)292 void dup_func_data (FunctionData * dst, FunctionData * src)
293 {
294 if (dst && src) {
295 register int i;
296
297 dst->func = src->func;
298 dst->name = mystrdup (src->name);
299 dst->text = mystrdup (src->text);
300 for (i = 0; i < MAX_FUNC_ARGS; i++) {
301 dst->func_val[i] = src->func_val[i];
302 dst->unit[i] = src->unit[i];
303 dst->unit_val[i] = src->unit_val[i];
304 }
305 dst->hotkey = src->hotkey;
306 dst->popup = src->popup;
307 }
308 }
309
create_named_function(int func,char * name)310 inline FunctionData *create_named_function (int func, char *name)
311 {
312 FunctionData *fdata = safecalloc (1, sizeof (FunctionData));
313
314 init_func_data (fdata);
315 fdata->func = func;
316 if (name)
317 fdata->name = mystrdup (name);
318 return fdata;
319 }
320
321
322
set_func_val(FunctionData * data,int arg,int value)323 void set_func_val (FunctionData * data, int arg, int value)
324 {
325 int i;
326
327 if (arg >= 0 && arg < MAX_FUNC_ARGS)
328 data->func_val[arg] = value;
329 else
330 for (i = 0; i < MAX_FUNC_ARGS; i++)
331 data->func_val[i] = value;
332 }
333
free_func_data(FunctionData * data)334 int free_func_data (FunctionData * data)
335 {
336 if (data) {
337 #ifdef DEBUG_ALLOCS
338 LOCAL_DEBUG_OUT ("freeing func = \"%s\"",
339 data->name ? data->name : "(null)");
340 #endif
341 if (data->name) {
342 free (data->name);
343 data->name = NULL;
344 }
345 if (data->text) {
346 #ifdef DEBUG_ALLOCS
347 LOCAL_DEBUG_OUT ("func->text = \"%s\"", data->text);
348 #endif
349 free (data->text);
350 data->text = NULL;
351 }
352 return data->func;
353 }
354 return F_NOP;
355 }
356
destroy_func_data(FunctionData ** pdata)357 void destroy_func_data (FunctionData ** pdata)
358 {
359 if (pdata && *pdata) {
360 free_func_data (*pdata);
361 free (*pdata);
362 *pdata = NULL;
363 }
364 }
365
default_func_val(FunctionCode func)366 long default_func_val (FunctionCode func)
367 {
368 long val = 0;
369
370 switch (func) {
371 case F_MAXIMIZE:
372 val = DEFAULT_MAXIMIZE;
373 break;
374 case F_MOVE:
375 case F_RESIZE:
376 val = INVALID_POSITION;
377 break;
378 default:
379 break;
380 }
381 return val;
382 }
383
decode_func_units(FunctionData * data)384 void decode_func_units (FunctionData * data)
385 {
386 register int i;
387
388 #if 0
389 int defaults[MAX_FUNC_ARGS];
390
391 defaults[0] = ASDefaultScrWidth;
392 defaults[1] = ASDefaultScrHeight;
393 #endif
394 for (i = 0; i < MAX_FUNC_ARGS; i++)
395 switch (data->unit[i]) {
396 case 'p':
397 case 'P':
398 data->unit_val[i] = 1;
399 break;
400 default:
401 data->unit_val[i] = 0 /*defaults[i] */ ;
402 }
403 }
404
405 /**********************************************************************
406 * complex function management code :
407 **********************************************************************/
really_destroy_complex_func(ComplexFunction * cf)408 void really_destroy_complex_func (ComplexFunction * cf)
409 {
410 if (cf) {
411 if (cf->magic == MAGIC_COMPLEX_FUNC) {
412 register int i;
413
414 cf->magic = 0;
415 if (cf->name)
416 free (cf->name);
417 if (cf->items) {
418 for (i = 0; i < cf->items_num; i++)
419 free_func_data (&(cf->items[i]));
420 free (cf->items);
421 }
422 free (cf);
423 }
424 }
425 }
426
complex_function_destroy(ASHashableValue value,void * data)427 void complex_function_destroy (ASHashableValue value, void *data)
428 {
429 ComplexFunction *cf = data;
430
431 if ((char *)value)
432 free ((char *)value);
433 if (cf && cf->magic == MAGIC_COMPLEX_FUNC) {
434 if (cf->name == (char *)value)
435 cf->name = NULL;
436 really_destroy_complex_func (cf);
437 } else if (data)
438 free (data);
439 }
440
init_list_of_funcs(struct ASHashTable ** list,Bool force)441 void init_list_of_funcs (struct ASHashTable **list, Bool force)
442 {
443 if (list == NULL)
444 return;
445
446 if (force && *list != NULL)
447 destroy_ashash (list);
448
449 if (*list == NULL)
450 *list =
451 create_ashash (0, casestring_hash_value, casestring_compare,
452 complex_function_destroy);
453 }
454
455 /* list could be NULL here : */
new_complex_func(struct ASHashTable * list,char * name)456 ComplexFunction *new_complex_func (struct ASHashTable *list, char *name)
457 {
458 ComplexFunction *cf = NULL;
459
460 if (name == NULL)
461 return NULL;
462 /* enlisting complex function is optional */
463 cf = (ComplexFunction *) safecalloc (1, sizeof (ComplexFunction));
464 cf->name = mystrdup (name);
465 cf->magic = MAGIC_COMPLEX_FUNC;
466 if (list) {
467 remove_hash_item (list, AS_HASHABLE (name), NULL, True); /* we want only one copy */
468 if (add_hash_item (list, AS_HASHABLE (cf->name), cf) != ASH_Success) {
469 really_destroy_complex_func (cf);
470 cf = NULL;
471 }
472 }
473 return cf;
474 }
475
find_complex_func(struct ASHashTable * list,char * name)476 ComplexFunction *find_complex_func (struct ASHashTable * list, char *name)
477 {
478 ASHashData hdata = { 0 };
479 if (name && list)
480 if (get_hash_item (list, AS_HASHABLE (name), &hdata.vptr) !=
481 ASH_Success)
482 hdata.vptr = NULL; /* we are being paranoid */
483 return (ComplexFunction *) hdata.vptr;
484 }
485
free_minipixmap_data(MinipixmapData * minipixmap)486 void free_minipixmap_data (MinipixmapData * minipixmap)
487 {
488 #ifdef DEBUG_ALLOCS
489 LOCAL_DEBUG_OUT ("filename = \"%s\", image = %p", minipixmap->filename,
490 minipixmap->image);
491 #endif
492 if (minipixmap->filename)
493 free (minipixmap->filename);
494 if (minipixmap->image) {
495 safe_asimage_destroy (minipixmap->image);
496 minipixmap->image = NULL;
497 }
498 }
499
500 /***************************************************************
501 * MenuData code :
502 ***************************************************************/
503 /****************************************************************************
504 * Implementing create-destroy functions :
505 ****************************************************************************/
menu_data_item_destroy(MenuDataItem * mdi)506 void menu_data_item_destroy (MenuDataItem * mdi)
507 {
508 #ifdef DEBUG_ALLOCS
509 LOCAL_DEBUG_CALLER_OUT ("menu_data_item_destroy(\"%s\",%p)",
510 ((mdi
511 && mdi->fdata) ? (mdi->fdata->name) : "NULL"),
512 mdi);
513 #endif
514 if (mdi) {
515 if (mdi->magic == MAGIC_MENU_DATA_ITEM) {
516 int i;
517
518 mdi->magic = 0;
519 #ifdef DEBUG_ALLOCS
520 LOCAL_DEBUG_OUT ("freeing func data %p", mdi->fdata);
521 #endif
522 if (mdi->fdata) {
523 free_func_data (mdi->fdata);
524 free (mdi->fdata);
525 }
526 for (i = 0; i < MINIPIXMAP_TypesNum; ++i)
527 free_minipixmap_data (&(mdi->minipixmap[i]));
528
529 if (mdi->item != NULL)
530 free (mdi->item);
531 if (mdi->item2 != NULL)
532 free (mdi->item2);
533 if (mdi->comment != NULL)
534 free (mdi->comment);
535 }
536 free (mdi);
537 }
538 }
539
purge_menu_data_items(MenuData * md)540 void purge_menu_data_items (MenuData * md)
541 {
542 if (md) {
543 MenuDataItem *mdi;
544
545 while ((mdi = md->first) != NULL) {
546 md->first = mdi->next;
547 mdi->next = NULL;
548 menu_data_item_destroy (mdi);
549 }
550 }
551 }
552
destroy_menu_data(MenuData ** pmd)553 void destroy_menu_data (MenuData ** pmd)
554 {
555 if (pmd && *pmd) {
556 MenuData *md = *pmd;
557
558 if (md->magic == MAGIC_MENU_DATA) {
559 #ifdef DEBUG_ALLOCS
560 LOCAL_DEBUG_CALLER_OUT ("menu_data_destroy(\"%s\", %p)",
561 md->name ? md->name : "(null)", md);
562 #endif
563 if (md->name)
564 free (md->name);
565 if (md->comment)
566 free (md->comment);
567
568 purge_menu_data_items (md);
569 md->magic = 0;
570 free (md);
571 *pmd = NULL;
572 }
573 }
574 }
575
create_menu_data(char * name)576 MenuData *create_menu_data (char *name)
577 {
578 MenuData *md = (MenuData *) safecalloc (1, sizeof (MenuData));
579
580 md->name = mystrdup (name);
581 md->magic = MAGIC_MENU_DATA;
582 return md;
583 }
584
new_menu_data(ASHashTable * list,char * name)585 MenuData *new_menu_data (ASHashTable * list, char *name)
586 {
587 ASHashData hdata = { 0 };
588 MenuData *md = NULL;
589
590 if (name == NULL)
591 return NULL;
592 if (list == NULL)
593 return NULL;
594
595 if (get_hash_item (list, AS_HASHABLE (name), &hdata.vptr) == ASH_Success)
596 return (MenuData *) hdata.vptr;
597
598 md = create_menu_data (name);
599
600 if (add_hash_item (list, AS_HASHABLE (md->name), md) != ASH_Success)
601 destroy_menu_data (&md);
602 return md;
603 }
604
find_menu_data(ASHashTable * list,char * name)605 MenuData *find_menu_data (ASHashTable * list, char *name)
606 {
607 ASHashData hdata = { 0 };
608
609 if (name && list)
610 if (get_hash_item (list, AS_HASHABLE (name), &hdata.vptr) !=
611 ASH_Success)
612 hdata.vptr = NULL; /* we are being paranoid */
613 return (MenuData *) hdata.vptr;
614 }
615
616
617
new_menu_data_item(MenuData * menu)618 MenuDataItem *new_menu_data_item (MenuData * menu)
619 {
620 MenuDataItem *mdi = NULL;
621
622 if (menu) {
623 mdi = safecalloc (1, sizeof (MenuDataItem));
624 mdi->magic = MAGIC_MENU_DATA_ITEM;
625 mdi->prev = menu->last;
626 if (menu->first == NULL)
627 menu->first = mdi;
628 else
629 menu->last->next = mdi;
630 menu->last = mdi;
631 ++(menu->items_num);
632 }
633 return mdi;
634 }
635
assign_minipixmaps(MenuDataItem * mdi,MinipixmapData * minipixmaps)636 void assign_minipixmaps (MenuDataItem * mdi, MinipixmapData * minipixmaps)
637 {
638 if (mdi && minipixmaps) {
639 int i;
640
641 for (i = 0; i < MINIPIXMAP_TypesNum; ++i) {
642 LOCAL_DEBUG_OUT ("type = %d, filename = \"%s\"", i,
643 minipixmaps[i].filename);
644 if (minipixmaps[i].filename) {
645 free_minipixmap_data (&(mdi->minipixmap[i]));
646 mdi->minipixmap[i].filename = mystrdup (minipixmaps[i].filename);
647 mdi->minipixmap[i].image = minipixmaps[i].image;
648 }
649 }
650 }
651 }
652
is_web_background(FunctionData * fdata)653 Bool is_web_background (FunctionData * fdata)
654 {
655 return (fdata->func == F_CHANGE_BACKGROUND_FOREIGN
656 && is_url (fdata->text));
657 }
658
check_fdata_availability(FunctionData * fdata)659 Bool check_fdata_availability (FunctionData * fdata)
660 {
661 if (fdata == NULL)
662 return False;
663 if (fdata->func < F_ExecToolStart || fdata->func > F_ExecToolEnd) {
664 if (IsSwallowFunc (fdata->func) || IsExecFunc (fdata->func)) {
665 LOCAL_DEBUG_OUT ("now really checking availability for \"%s\"",
666 fdata->name ? fdata->name : "nameless");
667 if (!is_executable_in_path (fdata->text)) {
668 LOCAL_DEBUG_OUT ("unavailable : \"%s\"",
669 fdata->name ? fdata->name : "nameless");
670 return False;
671 }
672 } else if (fdata->func == F_CHANGE_BACKGROUND_FOREIGN
673 && !is_web_background (fdata)) {
674 ASImageFileTypes type = check_asimage_file_type (fdata->text);
675
676 LOCAL_DEBUG_OUT ("foreign back image \"%s\" has type %d",
677 fdata->text, type);
678 if (type > ASIT_Supported) {
679 LOCAL_DEBUG_OUT ("foreign back image of unknown type : \"%s\"",
680 fdata->text);
681 return False;
682 }
683 }
684 } else if (fdata->func == F_ExecInTerm) {
685 char *target = strstr (fdata->text, "-e ");
686
687 target = target ? target + 3 : fdata->text;
688 if (!is_executable_in_path (target)) {
689 LOCAL_DEBUG_OUT ("unavailable : \"%s\", target = \"%s\"",
690 fdata->name ? fdata->name : "nameless", target);
691 return False;
692 }
693 }
694
695 return True;
696 }
697
check_availability(MenuDataItem * mdi)698 static void check_availability (MenuDataItem * mdi)
699 {
700 clear_flags (mdi->flags, MD_Disabled);
701 #ifndef NO_AVAILABILITYCHECK
702 LOCAL_DEBUG_OUT ("checking availability for \"%s\"",
703 mdi->fdata->name ? mdi->fdata->name : "nameless");
704 check_fdata_availability (mdi->fdata);
705 #endif /* NO_AVAILABILITYCHECK */
706 }
707
add_menu_data_item(MenuData * menu,int func,char * name,MinipixmapData * minipixmaps)708 MenuDataItem *add_menu_data_item (MenuData * menu, int func, char *name,
709 MinipixmapData * minipixmaps)
710 {
711 MenuDataItem *mdi = new_menu_data_item (menu);
712
713 if (mdi) {
714 mdi->fdata->func = func;
715 mdi->fdata->name = mystrdup (name);
716 check_availability (mdi);
717 assign_minipixmaps (mdi, minipixmaps);
718 }
719 return mdi;
720 }
721
add_menu_fdata_item(MenuData * menu,FunctionData * fdata,MinipixmapData * minipixmaps)722 MenuDataItem *add_menu_fdata_item (MenuData * menu, FunctionData * fdata,
723 MinipixmapData * minipixmaps)
724 {
725 MenuDataItem *mdi = NULL;
726
727 if (fdata)
728 if ((mdi = new_menu_data_item (menu)) != NULL) {
729 mdi->fdata = safecalloc (1, sizeof (FunctionData));
730 copy_func_data (mdi->fdata, fdata);
731 memset (fdata, 0x00, sizeof (FunctionData));
732 parse_menu_item_name (mdi, &(mdi->fdata->name));
733 check_availability (mdi);
734 assign_minipixmaps (mdi, minipixmaps);
735
736 LOCAL_DEBUG_OUT ("mdi_fdata_encoding = %d, fdata_encoding = %d",
737 mdi->fdata->name_encoding, fdata->name_encoding);
738 }
739 return mdi;
740 }
741
check_scale_menu_pmap(ASImage * im,ASFlagType flags)742 ASImage *check_scale_menu_pmap (ASImage * im, ASFlagType flags)
743 {
744 if (im) {
745 int w = im->width;
746 int h = im->height;
747
748 if (w > h) {
749 if (w > MAX_MENU_ITEM_HEIGHT) {
750 w = MAX_MENU_ITEM_HEIGHT;
751 h = (h * w) / im->width;
752 if (h == 0)
753 h = 1;
754 }
755 } else if (h > MAX_MENU_ITEM_HEIGHT) {
756 h = MAX_MENU_ITEM_HEIGHT;
757 w = (w * h) / im->height;
758 if (w == 0)
759 w = 1;
760 }
761 if (get_flags (flags, MD_ScaleMinipixmapDown)) {
762 int tmp_h = asxml_var_get (ASXMLVAR_MenuFontSize) + 8;
763 int tmp_w = (w * tmp_h) / h;
764
765 if (w > tmp_w || h > tmp_h) {
766 w = tmp_w;
767 h = tmp_h;
768 }
769 } else if (get_flags (flags, MD_ScaleMinipixmapUp)) {
770 int tmp_w = asxml_var_get (ASXMLVAR_MinipixmapWidth);
771 int tmp_h = asxml_var_get (ASXMLVAR_MinipixmapHeight);
772
773 if (w > tmp_w || h > tmp_h) {
774 w = tmp_w;
775 h = tmp_h;
776 }
777 }
778
779 if (w != im->width || h != im->height) {
780 return scale_asimage (ASDefaultVisual, im, w, h, ASA_ASImage, 100,
781 ASIMAGE_QUALITY_DEFAULT);
782 }
783 }
784 return im;
785 }
786
free_menu_pmaps(MenuData * menu)787 void free_menu_pmaps (MenuData * menu)
788 {
789 MenuDataItem *curr;
790
791 LOCAL_DEBUG_OUT ("menu = %p, image_manager = %p", menu,
792 ASDefaultScr->image_manager);
793
794 for (curr = menu ? menu->first : NULL; curr != NULL; curr = curr->next) {
795 int i;
796
797 for (i = 0; i < MINIPIXMAP_TypesNum; ++i)
798 if (curr->minipixmap[i].image) {
799 safe_asimage_destroy (curr->minipixmap[i].image);
800 curr->minipixmap[i].image = NULL;
801 }
802 }
803 }
804
805 void
load_menuitem_pmap(MenuDataItem * mdi,MinipixmapTypes type,Bool force)806 load_menuitem_pmap (MenuDataItem * mdi, MinipixmapTypes type, Bool force)
807 {
808 MinipixmapData *minipixmap = &(mdi->minipixmap[type]);
809 int func = mdi->fdata->func;
810 char *filename = minipixmap->filename;
811
812 if (minipixmap->image != NULL)
813 return;
814
815 if (filename == NULL) {
816 if (type == MINIPIXMAP_Icon) {
817 if (func == F_CHANGE_BACKGROUND_FOREIGN
818 && !is_web_background (mdi->fdata))
819 filename = mdi->fdata->text;
820 } else if (type == MINIPIXMAP_Preview) {
821 if (func == F_CHANGE_BACKGROUND_FOREIGN
822 || func == F_CHANGE_BACKGROUND)
823 filename = mdi->fdata->text;
824 }
825 }
826
827 LOCAL_DEBUG_OUT ("type = %d, filename = \"%s\", fdata->text = \"%s\"",
828 type, filename, mdi->fdata->text);
829 if (filename) {
830 char *cachedFileName = NULL;
831 int h = MAX_MENU_ITEM_HEIGHT;
832
833 if (type == MINIPIXMAP_Preview)
834 h = ASDefaultScr->MyDisplayHeight / 5;
835 else if (get_flags (mdi->flags, MD_ScaleMinipixmapDown))
836 h = asxml_var_get (ASXMLVAR_MenuFontSize) + 8;
837 else if (get_flags (mdi->flags, MD_ScaleMinipixmapUp))
838 h = asxml_var_get (ASXMLVAR_MinipixmapHeight);
839 LOCAL_DEBUG_OUT ("minipixmap target height = %d for \"%s\"", h,
840 minipixmap->filename);
841
842 if (func == F_CHANGE_BACKGROUND || func == F_CHANGE_BACKGROUND_FOREIGN) {
843 Bool use_thumbnail = True;
844
845 if (is_web_background (mdi->fdata) && is_url (filename)) {
846 int s1 = 0, s2 = 0;
847
848 cachedFileName = make_session_webcache_file (Session, filename);
849 use_thumbnail =
850 check_download_complete (0, cachedFileName, &s1, &s2);
851 use_thumbnail = use_thumbnail && ((s1 > 0 || s2 == s1));
852 if (use_thumbnail)
853 filename = cachedFileName;
854 }
855
856 if (type == MINIPIXMAP_Preview) {
857 if (is_web_background (mdi->fdata) && is_url (filename)) {
858 if (!use_thumbnail && force && minipixmap->loadCount == 0) {
859 spawn_download (filename, cachedFileName);
860 minipixmap->loadCount++;
861 }
862 } else if (filename != minipixmap->filename) {
863 use_thumbnail = force;
864 }
865 }
866
867 if (use_thumbnail)
868 minipixmap->image =
869 get_thumbnail_asimage (ASDefaultScr->image_manager, filename,
870 0, h,
871 AS_THUMBNAIL_PROPORTIONAL |
872 AS_THUMBNAIL_DONT_ENLARGE);
873 destroy_string (&cachedFileName);
874 } else {
875 minipixmap->image = load_environment_icon_any (filename, h);
876 }
877 LOCAL_DEBUG_OUT ("minipixmap = \"%s\", minipixmap_image = %p",
878 filename, minipixmap->image);
879 }
880 }
881
882
883 void
reload_menuitem_pmap(MenuDataItem * mdi,MinipixmapTypes type,Bool force)884 reload_menuitem_pmap (MenuDataItem * mdi, MinipixmapTypes type, Bool force)
885 {
886 MinipixmapData *minipixmap = &(mdi->minipixmap[type]);
887
888 LOCAL_DEBUG_OUT ("type = %d, fdata->text = \"%s\"", type,
889 mdi->fdata->text);
890
891 if (minipixmap->image) {
892 if (minipixmap->filename != NULL && !force) {
893 if (get_asimage_file_type
894 (ASDefaultScr->image_manager,
895 minipixmap->filename) != ASIT_XMLScript) {
896 ASImage *im = minipixmap->image;
897
898 if (im->imageman != NULL
899 && im->imageman != ASDefaultScr->image_manager) {
900 /* need to engage in trickery : */
901 relocate_asimage (ASDefaultScr->image_manager, im);
902 }
903 /* fprintf( stderr, "minipixmap \"%s\" is not an XML script - skipping\n", minipixmap ); */
904 return;
905 }
906 }
907 safe_asimage_destroy (minipixmap->image);
908 minipixmap->image = NULL;
909 }
910
911 load_menuitem_pmap (mdi, type, False);
912 }
913
reload_menu_pmaps(MenuData * menu,Bool force)914 void reload_menu_pmaps (MenuData * menu, Bool force)
915 {
916 MenuDataItem *curr;
917
918 LOCAL_DEBUG_OUT ("menu = %p, image_manager = %p", menu,
919 ASDefaultScr->image_manager);
920 if (menu && ASDefaultScr->image_manager)
921 for (curr = menu->first; curr != NULL; curr = curr->next) {
922 int i;
923
924 for (i = 0; i < MINIPIXMAP_TypesNum; ++i)
925 reload_menuitem_pmap (curr, i, force);
926 }
927 }
928
929
930 /* this is very often used function so we optimize it as good as we can */
parse_menu_item_name(MenuDataItem * item,char ** name)931 int parse_menu_item_name (MenuDataItem * item, char **name)
932 {
933 register int i;
934 register char *ptr = *name;
935
936 if (ptr == NULL || item == NULL)
937 return -1;
938
939 for (i = 0; ptr[i] && ptr[i] != '\t'; i++) ;
940
941 if (ptr[i] == '\0') {
942 item->item = *name;
943 *name = NULL; /* that will prevent us from memory deallocation */
944 item->item2 = NULL;
945 } else {
946 item->item = mystrndup (*name, i);
947 item->item2 = mystrdup (&(ptr[i + 1]));
948 }
949
950 if ((ptr = item->item) != NULL)
951 for (i = 0; ptr[i]; i++)
952 if (ptr[i] == '_')
953 ptr[i] = ' ';
954
955 if ((ptr = item->item2) != NULL)
956 for (i = 0; ptr[i]; i++)
957 if (ptr[i] == '_')
958 ptr[i] = ' ';
959
960 return 0;
961 }
962
menu_data_item_from_func(MenuData * menu,FunctionData * fdata,Bool do_check_availability)963 MenuDataItem *menu_data_item_from_func (MenuData * menu,
964 FunctionData * fdata,
965 Bool do_check_availability)
966 {
967 MenuDataItem *item = NULL;
968
969 if (fdata != NULL) {
970 MinipixmapTypes mtype = GetMinipixmapType (fdata->func);
971
972 if (mtype < MINIPIXMAP_TypesNum) {
973 if (menu->last)
974 item = menu->last;
975 else {
976 item = new_menu_data_item (menu);
977 item->fdata = fdata;
978 }
979 if (fdata->func == F_SMALL_MINIPIXMAP)
980 set_flags (item->flags, MD_ScaleMinipixmapDown);
981 else if (fdata->func == F_LARGE_MINIPIXMAP)
982 set_flags (item->flags, MD_ScaleMinipixmapUp);
983
984 LOCAL_DEBUG_OUT ("type = %d, filename = \"%s\"", mtype, fdata->name);
985 set_string (&(item->minipixmap[mtype].filename),
986 mystrdup (fdata->name));
987 } else {
988 item = new_menu_data_item (menu);
989 if (parse_menu_item_name (item, &(fdata->name)) >= 0)
990 item->fdata = fdata;
991 if (do_check_availability)
992 check_availability (item);
993 }
994 if (item == NULL || item->fdata != fdata) {
995 free_func_data (fdata); /* insurance measure */
996 free (fdata);
997 }
998 }
999 return item;
1000 }
1001
compare_func_data_name(const void * a,const void * b)1002 int compare_func_data_name (const void *a, const void *b)
1003 {
1004 FunctionData *fda = *(FunctionData **) a;
1005 FunctionData *fdb = *(FunctionData **) b;
1006
1007 return strcmp (fda->name ? fda->name : "", fdb->name ? fdb->name : "");
1008 }
1009
1010
1011
1012 void
print_func_data(const char * file,const char * func,int line,FunctionData * data)1013 print_func_data (const char *file, const char *func, int line,
1014 FunctionData * data)
1015 {
1016 fprintf (stderr, "%s:%s:%s:%d>!!FUNC ", get_application_name (), file,
1017 func, line);
1018 if (data == NULL)
1019 fprintf (stderr, "NULL Function\n");
1020 else {
1021 TermDef *term = func2fterm (data->func, True);
1022
1023 if (term == NULL)
1024 fprintf (stderr, "Invalid Function %ld\n", (long)data->func);
1025 else {
1026 fprintf (stderr, "%s \"%s\" text[%s] ", term->keyword,
1027 data->name ? data->name : "", data->text ? data->text : "");
1028 fprintf (stderr, "val0[%ld%c(%ld)] ", (long)data->func_val[0],
1029 (data->unit[0] == '\0') ? ' ' : data->unit[0],
1030 (long)data->unit_val[0]);
1031 fprintf (stderr, "val1[%ld%c(%ld)] ", (long)data->func_val[1],
1032 (data->unit[1] == '\0') ? ' ' : data->unit[1],
1033 (long)data->unit_val[1]);
1034 fprintf (stderr, "(popup=%p)\n", data->popup);
1035 }
1036 }
1037 }
1038
1039
1040
format_FunctionData(FunctionData * data)1041 char *format_FunctionData (FunctionData * data)
1042 {
1043 char *buffer = NULL;
1044
1045 if (data != NULL) {
1046 int len = 0;
1047 int pos = 0;
1048
1049 if (data->name)
1050 len += 1 + strlen (data->name) + 1;
1051 if (data->text)
1052 len += 1 + strlen (data->text) + 1;
1053 else
1054 len += 64;
1055 buffer = safemalloc (len);
1056
1057 if (data->name) {
1058 int i = 0;
1059
1060 buffer[pos++] = '"';
1061 while (data->name[i])
1062 buffer[pos++] = data->name[i++];
1063 buffer[pos++] = '"';
1064 }
1065 if (data->text) {
1066 int i = 0;
1067
1068 if (pos)
1069 buffer[pos++] = ' ';
1070 while (data->text[i])
1071 buffer[pos++] = data->text[i++];
1072 } else {
1073 #define FORMAT_FUNC_VALUE(val,unit) \
1074 do{ int i = unsigned_int2buffer_end (&buffer[pos], len-pos, ((val) < 0)? -(val) : (val)); \
1075 if (val < 0) buffer[pos++] = '-'; \
1076 while (buffer[i]) buffer[pos++] = buffer[i++]; \
1077 if (unit)buffer[pos++] = unit; }while(0)
1078
1079 if (pos)
1080 buffer[pos++] = ' ';
1081 FORMAT_FUNC_VALUE (data->func_val[0], data->unit[0]);
1082 buffer[pos++] = ' ';
1083 FORMAT_FUNC_VALUE (data->func_val[1], data->unit[1]);
1084
1085 #undef FORMAT_FUNC_VALUE
1086 }
1087 buffer[pos++] = '\0';
1088 }
1089
1090 return buffer;
1091 }
1092