Convert function definitions in lwlib files to standard C.
[bpt/emacs.git] / lwlib / lwlib.c
1 /* A general interface to the widgets of different toolkits.
2 Copyright (C) 1992, 1993 Lucid, Inc.
3 Copyright (C) 1994, 1995, 1996, 1999, 2000, 2001, 2002, 2003, 2004,
4 2005, 2006, 2007, 2008, 2009, 2010 Free Software Foundation, Inc.
5
6 This file is part of the Lucid Widget Library.
7
8 The Lucid Widget Library is free software; you can redistribute it and/or
9 modify it under the terms of the GNU General Public License as published by
10 the Free Software Foundation; either version 2, or (at your option)
11 any later version.
12
13 The Lucid Widget Library is distributed in the hope that it will be useful,
14 but WITHOUT ANY WARRANTY; without even the implied warranty of
15 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 GNU General Public License for more details.
17
18 You should have received a copy of the GNU General Public License
19 along with GNU Emacs; see the file COPYING. If not, write to
20 the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
21 Boston, MA 02110-1301, USA. */
22
23 #ifdef HAVE_CONFIG_H
24 #include <config.h>
25 #endif
26
27 #include <setjmp.h>
28 #include "../src/lisp.h"
29
30 #include <sys/types.h>
31 #include <stdio.h>
32 #include <ctype.h>
33 #include "lwlib-int.h"
34 #include "lwlib-utils.h"
35 #include <X11/StringDefs.h>
36
37 #if defined (USE_LUCID)
38 #include "lwlib-Xlw.h"
39 #endif
40 #if defined (USE_MOTIF)
41 #include "lwlib-Xm.h"
42 #else /* not USE_MOTIF */
43 #if defined (USE_LUCID)
44 #define USE_XAW
45 #endif /* not USE_MOTIF && USE_LUCID */
46 #endif
47 #if defined (USE_XAW)
48 #ifdef HAVE_XAW3D
49 #include <X11/Xaw3d/Paned.h>
50 #else /* !HAVE_XAW3D */
51 #include <X11/Xaw/Paned.h>
52 #endif /* HAVE_XAW3D */
53 #include "lwlib-Xaw.h"
54 #endif
55
56 #if !defined (USE_LUCID) && !defined (USE_MOTIF)
57 #error At least one of USE_LUCID or USE_MOTIF must be defined.
58 #endif
59
60 #ifndef max
61 #define max(x, y) ((x) > (y) ? (x) : (y))
62 #endif
63
64 /* List of all widgets managed by the library. */
65 static widget_info*
66 all_widget_info = NULL;
67
68 #ifdef USE_MOTIF
69 char *lwlib_toolkit_type = "motif";
70 #else
71 char *lwlib_toolkit_type = "lucid";
72 #endif
73
74 static widget_value *merge_widget_value (widget_value *,
75 widget_value *,
76 int, int *);
77 static void instantiate_widget_instance (widget_instance *);
78 static int my_strcasecmp (char *, char *);
79 static void safe_free_str (char *);
80 static void free_widget_value_tree (widget_value *);
81 static widget_value *copy_widget_value_tree (widget_value *,
82 change_type);
83 static widget_info *allocate_widget_info (char *, char *, LWLIB_ID,
84 widget_value *,
85 lw_callback, lw_callback,
86 lw_callback, lw_callback);
87 static void free_widget_info (widget_info *);
88 static void mark_widget_destroyed (Widget, XtPointer, XtPointer);
89 static widget_instance *allocate_widget_instance (widget_info *,
90 Widget, Boolean);
91 static void free_widget_instance (widget_instance *);
92 static widget_info *get_widget_info (LWLIB_ID, Boolean);
93 static widget_instance *get_widget_instance (Widget, Boolean);
94 static widget_instance *find_instance (LWLIB_ID, Widget, Boolean);
95 static Boolean safe_strcmp (char *, char *);
96 static Widget name_to_widget (widget_instance *, char *);
97 static void set_one_value (widget_instance *, widget_value *, Boolean);
98 static void update_one_widget_instance (widget_instance *, Boolean);
99 static void update_all_widget_values (widget_info *, Boolean);
100 static void initialize_widget_instance (widget_instance *);
101 static widget_creation_function find_in_table (char *, widget_creation_entry *);
102 static Boolean dialog_spec_p (char *);
103 static void destroy_one_instance (widget_instance *);
104 static void lw_pop_all_widgets (LWLIB_ID, Boolean);
105 static Boolean get_one_value (widget_instance *, widget_value *);
106 static void show_one_widget_busy (Widget, Boolean);
107
108 void
109 lwlib_memset (char *address, int value, size_t length)
110 {
111 int i;
112
113 for (i = 0; i < length; i++)
114 address[i] = value;
115 }
116
117 void
118 lwlib_bcopy (char *from, char *to, int length)
119 {
120 int i;
121
122 for (i = 0; i < length; i++)
123 to[i] = from[i];
124 }
125 \f/* utility functions for widget_instance and widget_info */
126 char *
127 safe_strdup (const char *s)
128 {
129 char *result;
130 if (! s) return 0;
131 result = (char *) malloc (strlen (s) + 1);
132 if (! result)
133 return 0;
134 strcpy (result, s);
135 return result;
136 }
137
138 /* Like strcmp but ignore differences in case. */
139
140 static int
141 my_strcasecmp (char *s1, char *s2)
142 {
143 while (1)
144 {
145 int c1 = *s1++;
146 int c2 = *s2++;
147 if (isupper (c1))
148 c1 = tolower (c1);
149 if (isupper (c2))
150 c2 = tolower (c2);
151 if (c1 != c2)
152 return (c1 > c2 ? 1 : -1);
153 if (c1 == 0)
154 return 0;
155 }
156 }
157
158 static void
159 safe_free_str (char *s)
160 {
161 free (s);
162 }
163
164 static widget_value *widget_value_free_list = 0;
165 static int malloc_cpt = 0;
166
167 widget_value *
168 malloc_widget_value (void)
169 {
170 widget_value *wv;
171 if (widget_value_free_list)
172 {
173 wv = widget_value_free_list;
174 widget_value_free_list = wv->free_list;
175 wv->free_list = 0;
176 }
177 else
178 {
179 wv = (widget_value *) malloc (sizeof (widget_value));
180 malloc_cpt++;
181 }
182 lwlib_memset ((void*) wv, 0, sizeof (widget_value));
183 return wv;
184 }
185
186 /* this is analogous to free(). It frees only what was allocated
187 by malloc_widget_value(), and no substructures.
188 */
189 void
190 free_widget_value (widget_value *wv)
191 {
192 if (wv->free_list)
193 abort ();
194
195 if (malloc_cpt > 25)
196 {
197 /* When the number of already allocated cells is too big,
198 We free it. */
199 free (wv);
200 malloc_cpt--;
201 }
202 else
203 {
204 wv->free_list = widget_value_free_list;
205 widget_value_free_list = wv;
206 }
207 }
208
209 static void
210 free_widget_value_tree (widget_value *wv)
211 {
212 if (!wv)
213 return;
214
215 free (wv->name);
216 free (wv->value);
217 free (wv->key);
218
219 wv->name = wv->value = wv->key = (char *) 0xDEADBEEF;
220
221 if (wv->toolkit_data && wv->free_toolkit_data)
222 {
223 XtFree (wv->toolkit_data);
224 wv->toolkit_data = (void *) 0xDEADBEEF;
225 }
226
227 if (wv->contents && (wv->contents != (widget_value*)1))
228 {
229 free_widget_value_tree (wv->contents);
230 wv->contents = (widget_value *) 0xDEADBEEF;
231 }
232 if (wv->next)
233 {
234 free_widget_value_tree (wv->next);
235 wv->next = (widget_value *) 0xDEADBEEF;
236 }
237 free_widget_value (wv);
238 }
239
240 static widget_value *
241 copy_widget_value_tree (widget_value *val, change_type change)
242 {
243 widget_value* copy;
244
245 if (!val)
246 return NULL;
247 if (val == (widget_value *) 1)
248 return val;
249
250 copy = malloc_widget_value ();
251 copy->name = safe_strdup (val->name);
252 copy->value = safe_strdup (val->value);
253 copy->key = safe_strdup (val->key);
254 copy->help = val->help;
255 copy->enabled = val->enabled;
256 copy->button_type = val->button_type;
257 copy->selected = val->selected;
258 copy->edited = False;
259 copy->change = change;
260 copy->this_one_change = change;
261 copy->contents = copy_widget_value_tree (val->contents, change);
262 copy->call_data = val->call_data;
263 copy->next = copy_widget_value_tree (val->next, change);
264 copy->toolkit_data = NULL;
265 copy->free_toolkit_data = False;
266 return copy;
267 }
268
269 static widget_info *
270 allocate_widget_info (type, name, id, val, pre_activate_cb,
271 selection_cb, post_activate_cb, highlight_cb)
272 char* type;
273 char* name;
274 LWLIB_ID id;
275 widget_value* val;
276 lw_callback pre_activate_cb;
277 lw_callback selection_cb;
278 lw_callback post_activate_cb;
279 lw_callback highlight_cb;
280 {
281 widget_info* info = (widget_info*)malloc (sizeof (widget_info));
282 info->type = safe_strdup (type);
283 info->name = safe_strdup (name);
284 info->id = id;
285 info->val = copy_widget_value_tree (val, STRUCTURAL_CHANGE);
286 info->busy = False;
287 info->pre_activate_cb = pre_activate_cb;
288 info->selection_cb = selection_cb;
289 info->post_activate_cb = post_activate_cb;
290 info->highlight_cb = highlight_cb;
291 info->instances = NULL;
292
293 info->next = all_widget_info;
294 all_widget_info = info;
295
296 return info;
297 }
298
299 static void
300 free_widget_info (widget_info *info)
301 {
302 safe_free_str (info->type);
303 safe_free_str (info->name);
304 free_widget_value_tree (info->val);
305 lwlib_memset ((void*)info, 0xDEADBEEF, sizeof (widget_info));
306 free (info);
307 }
308
309 static void
310 mark_widget_destroyed (Widget widget, XtPointer closure, XtPointer call_data)
311 {
312 widget_instance* instance = (widget_instance*)closure;
313
314 /* be very conservative */
315 if (instance->widget == widget)
316 instance->widget = NULL;
317 }
318
319 /* The messy #ifdef PROTOTYPES here and elsewhere are prompted by a
320 flood of warnings about argument promotion from proprietary ISO C
321 compilers. (etags still only makes one entry for each function.) */
322 static widget_instance *
323 #ifdef PROTOTYPES
324 allocate_widget_instance (widget_info* info, Widget parent, Boolean pop_up_p)
325 #else
326 allocate_widget_instance (info, parent, pop_up_p)
327 widget_info* info;
328 Widget parent;
329 Boolean pop_up_p;
330 #endif
331 {
332 widget_instance* instance =
333 (widget_instance*)malloc (sizeof (widget_instance));
334 bzero (instance, sizeof *instance);
335 instance->parent = parent;
336 instance->pop_up_p = pop_up_p;
337 instance->info = info;
338 instance->next = info->instances;
339 info->instances = instance;
340
341 instantiate_widget_instance (instance);
342
343 XtAddCallback (instance->widget, XtNdestroyCallback,
344 mark_widget_destroyed, (XtPointer)instance);
345 return instance;
346 }
347
348 static void
349 free_widget_instance (widget_instance *instance)
350 {
351 lwlib_memset ((void*)instance, 0xDEADBEEF, sizeof (widget_instance));
352 free (instance);
353 }
354
355 static widget_info *
356 #ifdef PROTOTYPES
357 get_widget_info (LWLIB_ID id, Boolean remove_p)
358 #else
359 get_widget_info (id, remove_p)
360 LWLIB_ID id;
361 Boolean remove_p;
362 #endif
363 {
364 widget_info* info;
365 widget_info* prev;
366 for (prev = NULL, info = all_widget_info;
367 info;
368 prev = info, info = info->next)
369 if (info->id == id)
370 {
371 if (remove_p)
372 {
373 if (prev)
374 prev->next = info->next;
375 else
376 all_widget_info = info->next;
377 }
378 return info;
379 }
380 return NULL;
381 }
382
383 /* Internal function used by the library dependent implementation to get the
384 widget_value for a given widget in an instance */
385 widget_info *
386 lw_get_widget_info (LWLIB_ID id)
387 {
388 return get_widget_info (id, 0);
389 }
390
391 static widget_instance *
392 #ifdef PROTOTYPES
393 get_widget_instance (Widget widget, Boolean remove_p)
394 #else
395 get_widget_instance (widget, remove_p)
396 Widget widget;
397 Boolean remove_p;
398 #endif
399 {
400 widget_info* info;
401 widget_instance* instance;
402 widget_instance* prev;
403 for (info = all_widget_info; info; info = info->next)
404 for (prev = NULL, instance = info->instances;
405 instance;
406 prev = instance, instance = instance->next)
407 if (instance->widget == widget)
408 {
409 if (remove_p)
410 {
411 if (prev)
412 prev->next = instance->next;
413 else
414 info->instances = instance->next;
415 }
416 return instance;
417 }
418 return (widget_instance *) 0;
419 }
420
421 /* Value is a pointer to the widget_instance corresponding to
422 WIDGET, or null if WIDGET is not a lwlib widget. */
423
424 widget_instance *
425 lw_get_widget_instance (Widget widget)
426 {
427 return get_widget_instance (widget, False);
428 }
429
430 static widget_instance*
431 #ifdef PROTOTYPES
432 find_instance (LWLIB_ID id, Widget parent, Boolean pop_up_p)
433 #else
434 find_instance (id, parent, pop_up_p)
435 LWLIB_ID id;
436 Widget parent;
437 Boolean pop_up_p;
438 #endif
439 {
440 widget_info* info = get_widget_info (id, False);
441 widget_instance* instance;
442
443 if (info)
444 for (instance = info->instances; instance; instance = instance->next)
445 if (instance->parent == parent && instance->pop_up_p == pop_up_p)
446 return instance;
447
448 return NULL;
449 }
450
451 \f
452 /* utility function for widget_value */
453 static Boolean
454 safe_strcmp (char *s1, char *s2)
455 {
456 if (!!s1 ^ !!s2) return True;
457 return (s1 && s2) ? strcmp (s1, s2) : s1 ? False : !!s2;
458 }
459
460
461 #if 0
462 # define EXPLAIN(name, oc, nc, desc, a1, a2) \
463 printf ("Change: \"%s\"\tmax(%s=%d,%s=%d)\t%s %d %d\n", \
464 name, \
465 (oc == NO_CHANGE ? "none" : \
466 (oc == INVISIBLE_CHANGE ? "invisible" : \
467 (oc == VISIBLE_CHANGE ? "visible" : \
468 (oc == STRUCTURAL_CHANGE ? "structural" : "???")))), \
469 oc, \
470 (nc == NO_CHANGE ? "none" : \
471 (nc == INVISIBLE_CHANGE ? "invisible" : \
472 (nc == VISIBLE_CHANGE ? "visible" : \
473 (nc == STRUCTURAL_CHANGE ? "structural" : "???")))), \
474 nc, desc, a1, a2)
475 #else
476 # define EXPLAIN(name, oc, nc, desc, a1, a2)
477 #endif
478
479
480 static widget_value *
481 merge_widget_value (widget_value *val1, widget_value *val2, int level, int *change_p)
482 {
483 change_type change, this_one_change;
484 widget_value* merged_next;
485 widget_value* merged_contents;
486
487 if (!val1)
488 {
489 if (val2)
490 {
491 *change_p = 1;
492 return copy_widget_value_tree (val2, STRUCTURAL_CHANGE);
493 }
494 else
495 return NULL;
496 }
497 if (!val2)
498 {
499 *change_p = 1;
500 free_widget_value_tree (val1);
501 return NULL;
502 }
503
504 change = NO_CHANGE;
505
506 if (safe_strcmp (val1->name, val2->name))
507 {
508 EXPLAIN (val1->name, change, STRUCTURAL_CHANGE, "name change",
509 val1->name, val2->name);
510 change = max (change, STRUCTURAL_CHANGE);
511 safe_free_str (val1->name);
512 val1->name = safe_strdup (val2->name);
513 }
514 if (safe_strcmp (val1->value, val2->value))
515 {
516 EXPLAIN (val1->name, change, VISIBLE_CHANGE, "value change",
517 val1->value, val2->value);
518 change = max (change, VISIBLE_CHANGE);
519 safe_free_str (val1->value);
520 val1->value = safe_strdup (val2->value);
521 }
522 if (safe_strcmp (val1->key, val2->key))
523 {
524 EXPLAIN (val1->name, change, VISIBLE_CHANGE, "key change",
525 val1->key, val2->key);
526 change = max (change, VISIBLE_CHANGE);
527 safe_free_str (val1->key);
528 val1->key = safe_strdup (val2->key);
529 }
530 if (! EQ (val1->help, val2->help))
531 {
532 EXPLAIN (val1->name, change, VISIBLE_CHANGE, "help change",
533 val1->help, val2->help);
534 change = max (change, VISIBLE_CHANGE);
535 val1->help = val2->help;
536 }
537 if (val1->enabled != val2->enabled)
538 {
539 EXPLAIN (val1->name, change, VISIBLE_CHANGE, "enablement change",
540 val1->enabled, val2->enabled);
541 change = max (change, VISIBLE_CHANGE);
542 val1->enabled = val2->enabled;
543 }
544 if (val1->button_type != val2->button_type)
545 {
546 EXPLAIN (val1->name, change, VISIBLE_CHANGE, "button type change",
547 val1->button_type, val2->button_type);
548 change = max (change, VISIBLE_CHANGE);
549 val1->button_type = val2->button_type;
550 }
551 if (val1->selected != val2->selected)
552 {
553 EXPLAIN (val1->name, change, VISIBLE_CHANGE, "selection change",
554 val1->selected, val2->selected);
555 change = max (change, VISIBLE_CHANGE);
556 val1->selected = val2->selected;
557 }
558 if (val1->call_data != val2->call_data)
559 {
560 EXPLAIN (val1->name, change, INVISIBLE_CHANGE, "call-data change",
561 val1->call_data, val2->call_data);
562 change = max (change, INVISIBLE_CHANGE);
563 val1->call_data = val2->call_data;
564 }
565
566 if (level > 0)
567 {
568 merged_contents =
569 merge_widget_value (val1->contents, val2->contents, level - 1,
570 change_p);
571
572 if (val1->contents && !merged_contents)
573 {
574 /* This used to say INVISIBLE_CHANGE,
575 but it is visible and vitally important when
576 the contents of the menu bar itself are entirely deleted.
577
578 But maybe it doesn't matter. This fails to fix the bug. */
579 EXPLAIN (val1->name, change, STRUCTURAL_CHANGE, "(contents gone)",
580 0, 0);
581 change = max (change, STRUCTURAL_CHANGE);
582 }
583 else if (merged_contents && merged_contents->change != NO_CHANGE)
584 {
585 EXPLAIN (val1->name, change, INVISIBLE_CHANGE, "(contents change)",
586 0, 0);
587 change = max (change, INVISIBLE_CHANGE);
588 #if 0 /* This was replaced by the August 9 1996 change in lwlib-Xm.c. */
589 #ifdef USE_MOTIF
590 change = max (merged_contents->change, change);
591 #endif
592 #endif
593 }
594
595 val1->contents = merged_contents;
596 }
597
598 this_one_change = change;
599
600 merged_next = merge_widget_value (val1->next, val2->next, level, change_p);
601
602 if (val1->next && !merged_next)
603 {
604 EXPLAIN (val1->name, change, STRUCTURAL_CHANGE, "(following gone)",
605 0, 0);
606 change = max (change, STRUCTURAL_CHANGE);
607 }
608 else if (merged_next)
609 {
610 if (merged_next->change)
611 EXPLAIN (val1->name, change, merged_next->change, "(following change)",
612 0, 0);
613 change = max (change, merged_next->change);
614 }
615
616 val1->next = merged_next;
617
618 val1->this_one_change = this_one_change;
619 val1->change = change;
620
621 if (change > NO_CHANGE && val1->toolkit_data)
622 {
623 *change_p = 1;
624 if (val1->free_toolkit_data)
625 XtFree (val1->toolkit_data);
626 val1->toolkit_data = NULL;
627 }
628
629 return val1;
630 }
631
632 \f
633 /* modifying the widgets */
634 static Widget
635 name_to_widget (widget_instance *instance, char *name)
636 {
637 Widget widget = NULL;
638
639 if (!instance->widget)
640 return NULL;
641
642 if (!strcmp (XtName (instance->widget), name))
643 widget = instance->widget;
644 else
645 {
646 int length = strlen (name) + 2;
647 char* real_name = (char *) xmalloc (length);
648 real_name [0] = '*';
649 strcpy (real_name + 1, name);
650
651 widget = XtNameToWidget (instance->widget, real_name);
652
653 free (real_name);
654 }
655 return widget;
656 }
657
658 static void
659 #ifdef PROTOTYPES
660 set_one_value (widget_instance* instance, widget_value* val, Boolean deep_p)
661 #else
662 set_one_value (instance, val, deep_p)
663 widget_instance* instance;
664 widget_value* val;
665 Boolean deep_p;
666 #endif
667 {
668 Widget widget = name_to_widget (instance, val->name);
669
670 if (widget)
671 {
672 #if defined (USE_LUCID)
673 if (lw_lucid_widget_p (instance->widget))
674 xlw_update_one_widget (instance, widget, val, deep_p);
675 #endif
676 #if defined (USE_MOTIF)
677 if (lw_motif_widget_p (instance->widget))
678 xm_update_one_widget (instance, widget, val, deep_p);
679 #endif
680 #if defined (USE_XAW)
681 if (lw_xaw_widget_p (instance->widget))
682 xaw_update_one_widget (instance, widget, val, deep_p);
683 #endif
684 }
685 }
686
687 static void
688 #ifdef PROTOTYPES
689 update_one_widget_instance (widget_instance* instance, Boolean deep_p)
690 #else
691 update_one_widget_instance (instance, deep_p)
692 widget_instance* instance;
693 Boolean deep_p;
694 #endif
695 {
696 widget_value *val;
697
698 if (!instance->widget)
699 /* the widget was destroyed */
700 return;
701
702 for (val = instance->info->val; val; val = val->next)
703 if (val->change != NO_CHANGE)
704 set_one_value (instance, val, deep_p);
705 }
706
707 static void
708 #ifdef PROTOTYPES
709 update_all_widget_values (widget_info* info, Boolean deep_p)
710 #else
711 update_all_widget_values (info, deep_p)
712 widget_info* info;
713 Boolean deep_p;
714 #endif
715 {
716 widget_instance* instance;
717 widget_value* val;
718
719 for (instance = info->instances; instance; instance = instance->next)
720 update_one_widget_instance (instance, deep_p);
721
722 for (val = info->val; val; val = val->next)
723 val->change = NO_CHANGE;
724 }
725
726 int
727 #ifdef PROTOTYPES
728 lw_modify_all_widgets (LWLIB_ID id, widget_value* val, Boolean deep_p)
729 #else
730 lw_modify_all_widgets (id, val, deep_p)
731 LWLIB_ID id;
732 widget_value* val;
733 Boolean deep_p;
734 #endif
735 {
736 widget_info* info = get_widget_info (id, False);
737 widget_value* new_val;
738 widget_value* next_new_val;
739 widget_value* cur;
740 widget_value* prev;
741 widget_value* next;
742 int found;
743 int change_p = 0;
744
745 if (!info)
746 return 0;
747
748 for (new_val = val; new_val; new_val = new_val->next)
749 {
750 next_new_val = new_val->next;
751 new_val->next = NULL;
752 found = False;
753 for (prev = NULL, cur = info->val; cur; prev = cur, cur = cur->next)
754 if (!strcmp (cur->name, new_val->name))
755 {
756 found = True;
757 next = cur->next;
758 cur->next = NULL;
759 cur = merge_widget_value (cur, new_val, deep_p ? 1000 : 1,
760 &change_p);
761 if (prev)
762 prev->next = cur ? cur : next;
763 else
764 info->val = cur ? cur : next;
765 if (cur)
766 cur->next = next;
767 break;
768 }
769 if (!found)
770 {
771 /* Could not find it, add it */
772 if (prev)
773 prev->next = copy_widget_value_tree (new_val, STRUCTURAL_CHANGE);
774 else
775 info->val = copy_widget_value_tree (new_val, STRUCTURAL_CHANGE);
776 change_p = 1;
777 }
778 new_val->next = next_new_val;
779 }
780
781 update_all_widget_values (info, deep_p);
782 return change_p;
783 }
784
785 \f
786 /* creating the widgets */
787
788 static void
789 initialize_widget_instance (widget_instance *instance)
790 {
791 widget_value* val;
792
793 for (val = instance->info->val; val; val = val->next)
794 val->change = STRUCTURAL_CHANGE;
795
796 update_one_widget_instance (instance, True);
797
798 for (val = instance->info->val; val; val = val->next)
799 val->change = NO_CHANGE;
800 }
801
802
803 static widget_creation_function
804 find_in_table (char *type, widget_creation_entry *table)
805 {
806 widget_creation_entry* cur;
807 for (cur = table; cur->type; cur++)
808 if (!my_strcasecmp (type, cur->type))
809 return cur->function;
810 return NULL;
811 }
812
813 static Boolean
814 dialog_spec_p (char *name)
815 {
816 /* return True if name matches [EILPQeilpq][1-9][Bb] or
817 [EILPQeilpq][1-9][Bb][Rr][1-9] */
818 if (!name)
819 return False;
820
821 switch (name [0])
822 {
823 case 'E': case 'I': case 'L': case 'P': case 'Q':
824 case 'e': case 'i': case 'l': case 'p': case 'q':
825 if (name [1] >= '0' && name [1] <= '9')
826 {
827 if (name [2] != 'B' && name [2] != 'b')
828 return False;
829 if (!name [3])
830 return True;
831 if ((name [3] == 'T' || name [3] == 't') && !name [4])
832 return True;
833 if ((name [3] == 'R' || name [3] == 'r')
834 && name [4] >= '0' && name [4] <= '9' && !name [5])
835 return True;
836 return False;
837 }
838 else
839 return False;
840
841 default:
842 return False;
843 }
844 }
845
846 static void
847 instantiate_widget_instance (widget_instance *instance)
848 {
849 widget_creation_function function = NULL;
850
851 #if defined (USE_LUCID)
852 if (!function)
853 function = find_in_table (instance->info->type, xlw_creation_table);
854 #endif
855 #if defined(USE_MOTIF)
856 if (!function)
857 function = find_in_table (instance->info->type, xm_creation_table);
858 #endif
859 #if defined (USE_XAW)
860 if (!function)
861 function = find_in_table (instance->info->type, xaw_creation_table);
862 #endif
863
864 if (!function)
865 {
866 if (dialog_spec_p (instance->info->type))
867 {
868 #if defined (USE_LUCID)
869 /* not yet */
870 #endif
871 #if defined(USE_MOTIF)
872 if (!function)
873 function = xm_create_dialog;
874 #endif
875 #if defined (USE_XAW)
876 if (!function)
877 function = xaw_create_dialog;
878 #endif
879 }
880 }
881
882 if (!function)
883 {
884 printf ("No creation function for widget type %s\n",
885 instance->info->type);
886 abort ();
887 }
888
889 instance->widget = (*function) (instance);
890
891 if (!instance->widget)
892 abort ();
893
894 /* XtRealizeWidget (instance->widget);*/
895 }
896
897 void
898 lw_register_widget (type, name, id, val, pre_activate_cb,
899 selection_cb, post_activate_cb, highlight_cb)
900 char* type;
901 char* name;
902 LWLIB_ID id;
903 widget_value* val;
904 lw_callback pre_activate_cb;
905 lw_callback selection_cb;
906 lw_callback post_activate_cb;
907 lw_callback highlight_cb;
908 {
909 if (!get_widget_info (id, False))
910 allocate_widget_info (type, name, id, val, pre_activate_cb, selection_cb,
911 post_activate_cb, highlight_cb);
912 }
913
914 Widget
915 #ifdef PROTOTYPES
916 lw_get_widget (LWLIB_ID id, Widget parent, Boolean pop_up_p)
917 #else
918 lw_get_widget (id, parent, pop_up_p)
919 LWLIB_ID id;
920 Widget parent;
921 Boolean pop_up_p;
922 #endif
923 {
924 widget_instance* instance;
925
926 instance = find_instance (id, parent, pop_up_p);
927 return instance ? instance->widget : NULL;
928 }
929
930 Widget
931 #ifdef PROTOTYPES
932 lw_make_widget (LWLIB_ID id, Widget parent, Boolean pop_up_p)
933 #else
934 lw_make_widget (id, parent, pop_up_p)
935 LWLIB_ID id;
936 Widget parent;
937 Boolean pop_up_p;
938 #endif
939 {
940 widget_instance* instance;
941 widget_info* info;
942
943 instance = find_instance (id, parent, pop_up_p);
944 if (!instance)
945 {
946 info = get_widget_info (id, False);
947 if (!info)
948 return NULL;
949 instance = allocate_widget_instance (info, parent, pop_up_p);
950 initialize_widget_instance (instance);
951 }
952 if (!instance->widget)
953 abort ();
954 return instance->widget;
955 }
956
957 Widget
958 #ifdef PROTOTYPES
959 lw_create_widget (char* type, char* name, LWLIB_ID id, widget_value* val,
960 Widget parent, Boolean pop_up_p,
961 lw_callback pre_activate_cb, lw_callback selection_cb,
962 lw_callback post_activate_cb, lw_callback highlight_cb)
963 #else
964 lw_create_widget (type, name, id, val, parent, pop_up_p, pre_activate_cb,
965 selection_cb, post_activate_cb, highlight_cb)
966 char* type;
967 char* name;
968 LWLIB_ID id;
969 widget_value* val;
970 Widget parent;
971 Boolean pop_up_p;
972 lw_callback pre_activate_cb;
973 lw_callback selection_cb;
974 lw_callback post_activate_cb;
975 lw_callback highlight_cb;
976 #endif
977 {
978 lw_register_widget (type, name, id, val, pre_activate_cb, selection_cb,
979 post_activate_cb, highlight_cb);
980 return lw_make_widget (id, parent, pop_up_p);
981 }
982
983 \f
984 /* destroying the widgets */
985 static void
986 destroy_one_instance (widget_instance *instance)
987 {
988 /* Remove the destroy callback on the widget; that callback will try to
989 dereference the instance object (to set its widget slot to 0, since the
990 widget is dead.) Since the instance is now dead, we don't have to worry
991 about the fact that its widget is dead too.
992
993 This happens in the Phase2Destroy of the widget, so this callback would
994 not have been run until arbitrarily long after the instance was freed.
995 */
996 if (instance->widget)
997 XtRemoveCallback (instance->widget, XtNdestroyCallback,
998 mark_widget_destroyed, (XtPointer)instance);
999
1000 if (instance->widget)
1001 {
1002 /* The else are pretty tricky here, including the empty statement
1003 at the end because it would be very bad to destroy a widget
1004 twice. */
1005 #if defined (USE_LUCID)
1006 if (lw_lucid_widget_p (instance->widget))
1007 xlw_destroy_instance (instance);
1008 else
1009 #endif
1010 #if defined (USE_MOTIF)
1011 if (lw_motif_widget_p (instance->widget))
1012 xm_destroy_instance (instance);
1013 else
1014 #endif
1015 #if defined (USE_XAW)
1016 if (lw_xaw_widget_p (instance->widget))
1017 xaw_destroy_instance (instance);
1018 else
1019 #endif
1020 /* do not remove the empty statement */
1021 ;
1022 }
1023
1024 free_widget_instance (instance);
1025 }
1026
1027 void
1028 lw_destroy_widget (Widget w)
1029 {
1030 widget_instance* instance = get_widget_instance (w, True);
1031
1032 if (instance)
1033 {
1034 widget_info *info = instance->info;
1035 /* instance has already been removed from the list; free it */
1036 destroy_one_instance (instance);
1037 /* if there are no instances left, free the info too */
1038 if (!info->instances)
1039 lw_destroy_all_widgets (info->id);
1040 }
1041 }
1042
1043 void
1044 lw_destroy_all_widgets (LWLIB_ID id)
1045 {
1046 widget_info* info = get_widget_info (id, True);
1047 widget_instance* instance;
1048 widget_instance* next;
1049
1050 if (info)
1051 {
1052 for (instance = info->instances; instance; )
1053 {
1054 next = instance->next;
1055 destroy_one_instance (instance);
1056 instance = next;
1057 }
1058 free_widget_info (info);
1059 }
1060 }
1061
1062 void
1063 lw_destroy_everything (void)
1064 {
1065 while (all_widget_info)
1066 lw_destroy_all_widgets (all_widget_info->id);
1067 }
1068
1069 void
1070 lw_destroy_all_pop_ups (void)
1071 {
1072 widget_info* info;
1073 widget_info* next;
1074 widget_instance* instance;
1075
1076 for (info = all_widget_info; info; info = next)
1077 {
1078 next = info->next;
1079 instance = info->instances;
1080 if (instance && instance->pop_up_p)
1081 lw_destroy_all_widgets (info->id);
1082 }
1083 }
1084
1085 #ifdef USE_MOTIF
1086 extern Widget first_child (/* Widget */); /* garbage */
1087 #endif
1088
1089 Widget
1090 lw_raise_all_pop_up_widgets (void)
1091 {
1092 widget_info* info;
1093 widget_instance* instance;
1094 Widget result = NULL;
1095
1096 for (info = all_widget_info; info; info = info->next)
1097 for (instance = info->instances; instance; instance = instance->next)
1098 if (instance->pop_up_p)
1099 {
1100 Widget widget = instance->widget;
1101 if (widget)
1102 {
1103 if (XtIsManaged (widget)
1104 #ifdef USE_MOTIF
1105 /* What a complete load of crap!!!!
1106 When a dialogShell is on the screen, it is not managed!
1107 */
1108 || (lw_motif_widget_p (instance->widget) &&
1109 XtIsManaged (first_child (widget)))
1110 #endif
1111 )
1112 {
1113 if (!result)
1114 result = widget;
1115 XMapRaised (XtDisplay (widget), XtWindow (widget));
1116 }
1117 }
1118 }
1119 return result;
1120 }
1121
1122 static void
1123 #ifdef PROTOTYPES
1124 lw_pop_all_widgets (LWLIB_ID id, Boolean up)
1125 #else
1126 lw_pop_all_widgets (id, up)
1127 LWLIB_ID id;
1128 Boolean up;
1129 #endif
1130 {
1131 widget_info* info = get_widget_info (id, False);
1132 widget_instance* instance;
1133
1134 if (info)
1135 for (instance = info->instances; instance; instance = instance->next)
1136 if (instance->pop_up_p && instance->widget)
1137 {
1138 #if defined (USE_LUCID)
1139 if (lw_lucid_widget_p (instance->widget))
1140 {
1141 XtRealizeWidget (instance->widget);
1142 xlw_pop_instance (instance, up);
1143 }
1144 #endif
1145 #if defined (USE_MOTIF)
1146 if (lw_motif_widget_p (instance->widget))
1147 {
1148 XtRealizeWidget (instance->widget);
1149 xm_pop_instance (instance, up);
1150 }
1151 #endif
1152 #if defined (USE_XAW)
1153 if (lw_xaw_widget_p (instance->widget))
1154 {
1155 XtRealizeWidget (XtParent (instance->widget));
1156 XtRealizeWidget (instance->widget);
1157 xaw_pop_instance (instance, up);
1158 }
1159 #endif
1160 }
1161 }
1162
1163 void
1164 lw_pop_up_all_widgets (LWLIB_ID id)
1165 {
1166 lw_pop_all_widgets (id, True);
1167 }
1168
1169 void
1170 lw_pop_down_all_widgets (LWLIB_ID id)
1171 {
1172 lw_pop_all_widgets (id, False);
1173 }
1174
1175 void
1176 lw_popup_menu (Widget widget, XEvent *event)
1177 {
1178 #if defined (USE_LUCID)
1179 if (lw_lucid_widget_p (widget))
1180 xlw_popup_menu (widget, event);
1181 #endif
1182 #if defined (USE_MOTIF)
1183 if (lw_motif_widget_p (widget))
1184 xm_popup_menu (widget, event);
1185 #endif
1186 #if defined (USE_XAW)
1187 if (lw_xaw_widget_p (widget))
1188 xaw_popup_menu (widget, event);
1189 #endif
1190 }
1191
1192 \f/* get the values back */
1193 static Boolean
1194 get_one_value (widget_instance *instance, widget_value *val)
1195 {
1196 Widget widget = name_to_widget (instance, val->name);
1197
1198 if (widget)
1199 {
1200 #if defined (USE_LUCID)
1201 if (lw_lucid_widget_p (instance->widget))
1202 xlw_update_one_value (instance, widget, val);
1203 #endif
1204 #if defined (USE_MOTIF)
1205 if (lw_motif_widget_p (instance->widget))
1206 xm_update_one_value (instance, widget, val);
1207 #endif
1208 #if defined (USE_XAW)
1209 if (lw_xaw_widget_p (instance->widget))
1210 xaw_update_one_value (instance, widget, val);
1211 #endif
1212 return True;
1213 }
1214 else
1215 return False;
1216 }
1217
1218 Boolean
1219 lw_get_some_values (LWLIB_ID id, widget_value *val_out)
1220 {
1221 widget_info* info = get_widget_info (id, False);
1222 widget_instance* instance;
1223 widget_value* val;
1224 Boolean result = False;
1225
1226 if (!info)
1227 return False;
1228
1229 instance = info->instances;
1230 if (!instance)
1231 return False;
1232
1233 for (val = val_out; val; val = val->next)
1234 if (get_one_value (instance, val))
1235 result = True;
1236
1237 return result;
1238 }
1239
1240 widget_value*
1241 lw_get_all_values (LWLIB_ID id)
1242 {
1243 widget_info* info = get_widget_info (id, False);
1244 widget_value* val = info->val;
1245 if (lw_get_some_values (id, val))
1246 return val;
1247 else
1248 return NULL;
1249 }
1250
1251 /* internal function used by the library dependent implementation to get the
1252 widget_value for a given widget in an instance */
1253 widget_value*
1254 lw_get_widget_value_for_widget (widget_instance *instance, Widget w)
1255 {
1256 char* name = XtName (w);
1257 widget_value* cur;
1258 for (cur = instance->info->val; cur; cur = cur->next)
1259 if (!strcmp (cur->name, name))
1260 return cur;
1261 return NULL;
1262 }
1263
1264 \f/* update other instances value when one thing changed */
1265
1266 /* To forbid recursive calls */
1267 static Boolean lwlib_updating;
1268
1269 /* This function can be used as a an XtCallback for the widgets that get
1270 modified to update other instances of the widgets. Closure should be the
1271 widget_instance. */
1272 void
1273 lw_internal_update_other_instances (Widget widget, XtPointer closure, XtPointer call_data)
1274 {
1275 widget_instance* instance = (widget_instance*)closure;
1276 char* name = XtName (widget);
1277 widget_info* info;
1278 widget_instance* cur;
1279 widget_value* val;
1280
1281 /* Avoid possibly infinite recursion. */
1282 if (lwlib_updating)
1283 return;
1284
1285 /* protect against the widget being destroyed */
1286 if (XtWidgetBeingDestroyedP (widget))
1287 return;
1288
1289 /* Return immediately if there are no other instances */
1290 info = instance->info;
1291 if (!info->instances->next)
1292 return;
1293
1294 lwlib_updating = True;
1295
1296 for (val = info->val; val && strcmp (val->name, name); val = val->next);
1297
1298 if (val && get_one_value (instance, val))
1299 for (cur = info->instances; cur; cur = cur->next)
1300 if (cur != instance)
1301 set_one_value (cur, val, True);
1302
1303 lwlib_updating = False;
1304 }
1305
1306
1307 \f/* get the id */
1308
1309 LWLIB_ID
1310 lw_get_widget_id (Widget w)
1311 {
1312 widget_instance* instance = get_widget_instance (w, False);
1313
1314 return instance ? instance->info->id : 0;
1315 }
1316
1317 \f/* set the keyboard focus */
1318 void
1319 lw_set_keyboard_focus (Widget parent, Widget w)
1320 {
1321 #if defined (USE_MOTIF)
1322 xm_set_keyboard_focus (parent, w);
1323 #else
1324 XtSetKeyboardFocus (parent, w);
1325 #endif
1326 }
1327
1328 \f/* Show busy */
1329 static void
1330 #ifdef PROTOTYPES
1331 show_one_widget_busy (Widget w, Boolean flag)
1332 #else
1333 show_one_widget_busy (w, flag)
1334 Widget w;
1335 Boolean flag;
1336 #endif
1337 {
1338 Pixel foreground = 0;
1339 Pixel background = 1;
1340 Widget widget_to_invert = XtNameToWidget (w, "*sheet");
1341 if (!widget_to_invert)
1342 widget_to_invert = w;
1343
1344 XtVaGetValues (widget_to_invert,
1345 XtNforeground, &foreground,
1346 XtNbackground, &background,
1347 NULL);
1348 XtVaSetValues (widget_to_invert,
1349 XtNforeground, background,
1350 XtNbackground, foreground,
1351 NULL);
1352 }
1353
1354 void
1355 #ifdef PROTOTYPES
1356 lw_show_busy (Widget w, Boolean busy)
1357 #else
1358 lw_show_busy (w, busy)
1359 Widget w;
1360 Boolean busy;
1361 #endif
1362 {
1363 widget_instance* instance = get_widget_instance (w, False);
1364 widget_info* info;
1365 widget_instance* next;
1366
1367 if (instance)
1368 {
1369 info = instance->info;
1370 if (info->busy != busy)
1371 {
1372 for (next = info->instances; next; next = next->next)
1373 if (next->widget)
1374 show_one_widget_busy (next->widget, busy);
1375 info->busy = busy;
1376 }
1377 }
1378 }
1379
1380 /* This hack exists because Lucid/Athena need to execute the strange
1381 function below to support geometry management. */
1382 void
1383 #ifdef PROTOTYPES
1384 lw_refigure_widget (Widget w, Boolean doit)
1385 #else
1386 lw_refigure_widget (w, doit)
1387 Widget w;
1388 Boolean doit;
1389 #endif
1390 {
1391 #if defined (USE_XAW)
1392 XawPanedSetRefigureMode (w, doit);
1393 #endif
1394 #if defined (USE_MOTIF)
1395 if (doit)
1396 XtManageChild (w);
1397 else
1398 XtUnmanageChild (w);
1399 #endif
1400 }
1401
1402 /* Toolkit independent way of determining if an event window is in the
1403 menubar. */
1404 Boolean
1405 lw_window_is_in_menubar (Window win, Widget menubar_widget)
1406 {
1407 return menubar_widget
1408 #if defined (USE_LUCID)
1409 && XtWindow (menubar_widget) == win;
1410 #endif
1411 #if defined (USE_MOTIF)
1412 && ((XtWindow (menubar_widget) == win)
1413 || (XtWindowToWidget (XtDisplay (menubar_widget), win)
1414 && (XtParent (XtWindowToWidget (XtDisplay (menubar_widget), win))
1415 == menubar_widget)));
1416 #endif
1417 }
1418
1419 /* Motif hack to set the main window areas. */
1420 void
1421 lw_set_main_areas (Widget parent, Widget menubar, Widget work_area)
1422 {
1423 #if defined (USE_MOTIF)
1424 xm_set_main_areas (parent, menubar, work_area);
1425 #endif
1426 }
1427
1428 /* Manage resizing for Motif. This disables resizing when the menubar
1429 is about to be modified. */
1430 void
1431 #ifdef PROTOTYPES
1432 lw_allow_resizing (Widget w, Boolean flag)
1433 #else
1434 lw_allow_resizing (w, flag)
1435 Widget w;
1436 Boolean flag;
1437 #endif
1438 {
1439 #if defined (USE_MOTIF)
1440 xm_manage_resizing (w, flag);
1441 #endif
1442 }
1443
1444
1445 /* Value is non-zero if LABEL is a menu separator. If it is, *TYPE is
1446 set to an appropriate enumerator of type enum menu_separator.
1447 MOTIF_P non-zero means map separator types not supported by Motif
1448 to similar ones that are supported. */
1449
1450 int
1451 lw_separator_p (char *label, enum menu_separator *type, int motif_p)
1452 {
1453 int separator_p = 0;
1454
1455 if (strlen (label) >= 3
1456 && bcmp (label, "--:", 3) == 0)
1457 {
1458 static struct separator_table
1459 {
1460 char *name;
1461 enum menu_separator type;
1462 }
1463 separator_names[] =
1464 {
1465 {"space", SEPARATOR_NO_LINE},
1466 {"noLine", SEPARATOR_NO_LINE},
1467 {"singleLine", SEPARATOR_SINGLE_LINE},
1468 {"doubleLine", SEPARATOR_DOUBLE_LINE},
1469 {"singleDashedLine", SEPARATOR_SINGLE_DASHED_LINE},
1470 {"doubleDashedLine", SEPARATOR_DOUBLE_DASHED_LINE},
1471 {"shadowEtchedIn", SEPARATOR_SHADOW_ETCHED_IN},
1472 {"shadowEtchedOut", SEPARATOR_SHADOW_ETCHED_OUT},
1473 {"shadowEtchedInDash", SEPARATOR_SHADOW_ETCHED_IN_DASH},
1474 {"shadowEtchedOutDash", SEPARATOR_SHADOW_ETCHED_OUT_DASH},
1475 {"shadowDoubleEtchedIn", SEPARATOR_SHADOW_DOUBLE_ETCHED_IN},
1476 {"shadowDoubleEtchedOut", SEPARATOR_SHADOW_DOUBLE_ETCHED_OUT},
1477 {"shadowDoubleEtchedInDash", SEPARATOR_SHADOW_DOUBLE_ETCHED_IN_DASH},
1478 {"shadowDoubleEtchedOutDash", SEPARATOR_SHADOW_DOUBLE_ETCHED_OUT_DASH},
1479 {0,0}
1480 };
1481
1482 int i;
1483
1484 label += 3;
1485 for (i = 0; separator_names[i].name; ++i)
1486 if (strcmp (label, separator_names[i].name) == 0)
1487 {
1488 separator_p = 1;
1489 *type = separator_names[i].type;
1490
1491 /* If separator type is not supported under Motif,
1492 use a similar one. */
1493 if (motif_p && *type >= SEPARATOR_SHADOW_DOUBLE_ETCHED_IN)
1494 *type -= 4;
1495 break;
1496 }
1497 }
1498 else if (strlen (label) > 3
1499 && bcmp (label, "--", 2) == 0
1500 && label[2] != '-')
1501 {
1502 /* Alternative, more Emacs-style names. */
1503 static struct separator_table
1504 {
1505 char *name;
1506 enum menu_separator type;
1507 }
1508 separator_names[] =
1509 {
1510 {"space", SEPARATOR_NO_LINE},
1511 {"no-line", SEPARATOR_NO_LINE},
1512 {"single-line", SEPARATOR_SINGLE_LINE},
1513 {"double-line", SEPARATOR_DOUBLE_LINE},
1514 {"single-dashed-line", SEPARATOR_SINGLE_DASHED_LINE},
1515 {"double-dashed-line", SEPARATOR_DOUBLE_DASHED_LINE},
1516 {"shadow-etched-in", SEPARATOR_SHADOW_ETCHED_IN},
1517 {"shadow-etched-out", SEPARATOR_SHADOW_ETCHED_OUT},
1518 {"shadow-etched-in-dash", SEPARATOR_SHADOW_ETCHED_IN_DASH},
1519 {"shadow-etched-out-dash", SEPARATOR_SHADOW_ETCHED_OUT_DASH},
1520 {"shadow-double-etched-in", SEPARATOR_SHADOW_DOUBLE_ETCHED_IN},
1521 {"shadow-double-etched-out", SEPARATOR_SHADOW_DOUBLE_ETCHED_OUT},
1522 {"shadow-double-etched-in-dash", SEPARATOR_SHADOW_DOUBLE_ETCHED_IN_DASH},
1523 {"shadow-double-etched-out-dash",SEPARATOR_SHADOW_DOUBLE_ETCHED_OUT_DASH},
1524 {0,0}
1525 };
1526
1527 int i;
1528
1529 label += 2;
1530 for (i = 0; separator_names[i].name; ++i)
1531 if (strcmp (label, separator_names[i].name) == 0)
1532 {
1533 separator_p = 1;
1534 *type = separator_names[i].type;
1535
1536 /* If separator type is not supported under Motif,
1537 use a similar one. */
1538 if (motif_p && *type >= SEPARATOR_SHADOW_DOUBLE_ETCHED_IN)
1539 *type -= 4;
1540 break;
1541 }
1542 }
1543 else
1544 {
1545 /* Old-style separator, maybe. It's a separator if it contains
1546 only dashes. */
1547 while (*label == '-')
1548 ++label;
1549 separator_p = *label == 0;
1550 *type = SEPARATOR_SHADOW_ETCHED_IN;
1551 }
1552
1553 return separator_p;
1554 }
1555
1556 /* arch-tag: 3d730f36-a441-4a71-9971-48ef3b5a4d9f
1557 (do not change this comment) */