comparison lwlib/lwlib.c @ 0:376386a54a3c r19-14

Import from CVS: tag r19-14
author cvs
date Mon, 13 Aug 2007 08:45:50 +0200
parents
children ac2d302a0011
comparison
equal deleted inserted replaced
-1:000000000000 0:376386a54a3c
1 /* A general interface to the widgets of different toolkits.
2 Copyright (C) 1992, 1993, 1994 Lucid, Inc.
3 Copyright (C) 1995 Tinker Systems and INS Engineering Corp.
4
5 This file is part of the Lucid Widget Library.
6
7 The Lucid Widget Library is free software; you can redistribute it and/or
8 modify it under the terms of the GNU General Public License as published by
9 the Free Software Foundation; either version 2, or (at your option)
10 any later version.
11
12 The Lucid Widget Library is distributed in the hope that it will be useful,
13 but WITHOUT ANY WARRANTY; without even the implied warranty of
14 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 GNU General Public License for more details.
16
17 You should have received a copy of the GNU General Public License
18 along with GNU Emacs; see the file COPYING. If not, write to
19 the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */
20
21 #ifdef NeXT
22 #undef __STRICT_BSD__ /* ick */
23 #endif
24
25 #include <stdlib.h>
26 #include <unistd.h>
27 #include <sys/types.h>
28 #include <string.h>
29 #include <stdio.h>
30 #include <X11/StringDefs.h>
31 #include "lwlib-internal.h"
32 #include "lwlib-utils.h"
33
34 #if defined(__GNUC__) && !defined(alloca)
35 #define alloca __builtin_alloca
36 #endif
37
38 #if ((!__GNUC__) && !defined(__hpux)) && !defined(_AIX) && !defined (_SCO_DS) && !defined (__USLC__)
39 #include <alloca.h>
40 #endif
41
42 #ifdef __SUNPRO_C
43 void *__builtin_alloca (unsigned int);
44 #endif
45
46 #if defined(_AIX)
47 #pragma alloca
48 #endif
49
50 #ifdef BROKEN_SUNOS_HEADERS
51 extern void * memset (void *, int, int);
52 extern int strcasecmp (char *, char *);
53 extern int fprintf (FILE *, CONST char *, ...);
54 #endif
55
56 #ifdef NEED_LUCID
57 #include "lwlib-Xlw.h"
58 #endif
59 #ifdef NEED_MOTIF
60 #include "lwlib-Xm.h"
61 #endif
62 #ifdef NEED_ATHENA
63 #include "lwlib-Xaw.h"
64 #endif
65
66 /* #### Does a check need to be put back in here to make sure we have
67 sufficient defines to function properly or are the checks in the
68 makefile sufficient? */
69
70 /* List of all widgets managed by the library. Note that each "widget"
71 listed here may actually be a tree of widgets; for example, a
72 single entry here might represent a single menubar or popup menu,
73 each of which might be implemented with a tree of widgets.
74 */
75 static widget_info *all_widget_info = NULL;
76
77
78 /* Forward declarations */
79 static void
80 instantiate_widget_instance (widget_instance *instance);
81
82
83 /* utility functions for widget_instance and widget_info */
84 static char *
85 safe_strdup (CONST char *s)
86 {
87 char *result;
88 if (! s) return 0;
89 result = (char *) malloc (strlen (s) + 1);
90 if (! result)
91 return 0;
92 strcpy (result, s);
93 return result;
94 }
95
96 static void
97 safe_free_str (char *s)
98 {
99 if (s) free (s);
100 }
101
102 static widget_value *widget_value_free_list = 0;
103
104 widget_value *
105 malloc_widget_value (void)
106 {
107 widget_value *wv;
108 if (widget_value_free_list)
109 {
110 wv = widget_value_free_list;
111 widget_value_free_list = wv->free_list;
112 wv->free_list = 0;
113 }
114 else
115 {
116 wv = (widget_value *) malloc (sizeof (widget_value));
117 }
118 if (wv)
119 {
120 memset (wv, 0, sizeof (widget_value));
121 }
122 return wv;
123 }
124
125 /* this is analogous to free(). It frees only what was allocated
126 by malloc_widget_value(), and no substructures.
127 */
128 void
129 free_widget_value (widget_value *wv)
130 {
131 if (wv->free_list)
132 abort ();
133 wv->free_list = widget_value_free_list;
134 widget_value_free_list = wv;
135 }
136
137 static void free_widget_value_tree (widget_value *wv);
138
139 static void
140 free_widget_value_contents (widget_value *wv)
141 {
142 if (wv->name) free (wv->name);
143 if (wv->value) free (wv->value);
144 if (wv->key) free (wv->key);
145
146 /* #### - all of this 0xDEADBEEF stuff should be unnecessary
147 in production code... it should be conditionalized. */
148 wv->name = wv->value = wv->key = (char *) 0xDEADBEEF;
149
150 if (wv->toolkit_data && wv->free_toolkit_data)
151 {
152 free (wv->toolkit_data);
153 wv->toolkit_data = (void *) 0xDEADBEEF;
154 }
155 #ifdef NEED_SCROLLBARS
156 if (wv->scrollbar_data)
157 {
158 free (wv->scrollbar_data);
159 wv->scrollbar_data = NULL;
160 }
161 #endif
162 if (wv->contents && (wv->contents != (widget_value*)1))
163 {
164 free_widget_value_tree (wv->contents);
165 wv->contents = (widget_value *) 0xDEADBEEF;
166 }
167 if (wv->next)
168 {
169 free_widget_value_tree (wv->next);
170 wv->next = (widget_value *) 0xDEADBEEF;
171 }
172 }
173
174 static void
175 free_widget_value_tree (widget_value *wv)
176 {
177 if (!wv)
178 return;
179
180 free_widget_value_contents (wv);
181 free_widget_value (wv);
182 }
183
184 #ifdef NEED_SCROLLBARS
185
186 static void
187 copy_scrollbar_values (widget_value *val, widget_value *copy)
188 {
189 if (!copy->scrollbar_data)
190 copy->scrollbar_data =
191 (scrollbar_values *) malloc (sizeof (scrollbar_values));
192
193 if (val->scrollbar_data)
194 *copy->scrollbar_data = *val->scrollbar_data;
195 else
196 memset (copy->scrollbar_data, 0, sizeof (scrollbar_values));
197 }
198
199 /*
200 * Return true if old->scrollbar_data were not equivalent
201 * to new->scrollbar_data.
202 */
203 static Boolean
204 merge_scrollbar_values (widget_value *old, widget_value *new)
205 {
206 Boolean changed = False;
207
208 if (new->scrollbar_data && !old->scrollbar_data)
209 {
210 copy_scrollbar_values (new, old);
211 changed = True;
212 }
213 else if (!new->scrollbar_data && old->scrollbar_data)
214 {
215 free (old->scrollbar_data);
216 old->scrollbar_data = NULL;
217 }
218 else if (new->scrollbar_data && old->scrollbar_data)
219 {
220 scrollbar_values *old_sb = old->scrollbar_data;
221 scrollbar_values *new_sb = new->scrollbar_data;
222 #define FROB(field) if (old_sb->field != new_sb->field) changed = True
223 FROB (line_increment);
224 FROB (page_increment);
225 FROB (minimum);
226 FROB (maximum);
227 FROB (slider_size);
228 FROB (slider_position);
229 FROB (scrollbar_width);
230 FROB (scrollbar_height);
231 FROB (scrollbar_x);
232 FROB (scrollbar_y);
233 #undef FROB
234 *old_sb = *new_sb;
235 }
236
237 return changed;
238 }
239
240 #endif /* NEED_SCROLLBARS */
241
242 /* Make a complete copy of a widget_value tree. Store CHANGE into
243 the widget_value tree's `change' field. */
244
245 static widget_value *
246 copy_widget_value_tree (widget_value *val, change_type change)
247 {
248 widget_value *copy;
249
250 if (!val)
251 return NULL;
252 if (val == (widget_value *) 1)
253 return val;
254
255 copy = malloc_widget_value ();
256 if (copy)
257 {
258 /* #### - don't seg fault *here* if out of memory. Menus will be
259 truncated inexplicably. */
260 copy->type = val->type;
261 copy->name = safe_strdup (val->name);
262 copy->value = safe_strdup (val->value);
263 copy->key = safe_strdup (val->key);
264 copy->enabled = val->enabled;
265 copy->selected = val->selected;
266 copy->edited = False;
267 copy->change = change;
268 copy->contents = copy_widget_value_tree (val->contents, change);
269 copy->call_data = val->call_data;
270 copy->next = copy_widget_value_tree (val->next, change);
271 copy->toolkit_data = NULL;
272 copy->free_toolkit_data = False;
273 #ifdef NEED_SCROLLBARS
274 copy_scrollbar_values (val, copy);
275 #endif
276 }
277 return copy;
278 }
279
280 /* This function is used to implement incremental menu construction. */
281
282 widget_value *
283 replace_widget_value_tree (widget_value *node, widget_value *newtree)
284 {
285 widget_value *copy;
286
287 if (!node || !newtree)
288 abort ();
289
290 copy = copy_widget_value_tree (newtree, STRUCTURAL_CHANGE);
291
292 free_widget_value_contents (node);
293 *node = *copy;
294 free_widget_value (copy); /* free the node, but not its contents. */
295 return node;
296 }
297
298 static widget_info *
299 allocate_widget_info (CONST char *type, CONST char *name,
300 LWLIB_ID id, widget_value *val,
301 lw_callback pre_activate_cb, lw_callback selection_cb,
302 lw_callback post_activate_cb)
303 {
304 widget_info *info = (widget_info *) malloc (sizeof (widget_info));
305 info->type = safe_strdup (type);
306 info->name = safe_strdup (name);
307 info->id = id;
308 info->val = copy_widget_value_tree (val, STRUCTURAL_CHANGE);
309 info->busy = False;
310 info->pre_activate_cb = pre_activate_cb;
311 info->selection_cb = selection_cb;
312 info->post_activate_cb = post_activate_cb;
313 info->instances = NULL;
314
315 info->next = all_widget_info;
316 all_widget_info = info;
317
318 return info;
319 }
320
321 static void
322 free_widget_info (widget_info *info)
323 {
324 safe_free_str (info->type);
325 safe_free_str (info->name);
326 free_widget_value_tree (info->val);
327 memset ((void*)info, 0xDEADBEEF, sizeof (widget_info));
328 free (info);
329 }
330
331 static void
332 mark_widget_destroyed (Widget widget, XtPointer closure, XtPointer call_data)
333 {
334 widget_instance *instance = (widget_instance*)closure;
335
336 /* be very conservative */
337 if (instance->widget == widget)
338 instance->widget = NULL;
339 }
340
341 static widget_instance *
342 allocate_widget_instance (widget_info *info, Widget parent, Boolean pop_up_p)
343 {
344 widget_instance *instance =
345 (widget_instance *) malloc (sizeof (widget_instance));
346 instance->parent = parent;
347 instance->pop_up_p = pop_up_p;
348 instance->info = info;
349 instance->next = info->instances;
350 info->instances = instance;
351
352 instantiate_widget_instance (instance);
353
354 XtAddCallback (instance->widget, XtNdestroyCallback,
355 mark_widget_destroyed, (XtPointer)instance);
356 return instance;
357 }
358
359 static void
360 free_widget_instance (widget_instance *instance)
361 {
362 memset ((void *) instance, 0xDEADBEEF, sizeof (widget_instance));
363 free (instance);
364 }
365
366 static widget_info *
367 get_widget_info (LWLIB_ID id, Boolean remove_p)
368 {
369 widget_info *info;
370 widget_info *prev;
371 for (prev = NULL, info = all_widget_info;
372 info;
373 prev = info, info = info->next)
374 if (info->id == id)
375 {
376 if (remove_p)
377 {
378 if (prev)
379 prev->next = info->next;
380 else
381 all_widget_info = info->next;
382 }
383 return info;
384 }
385 return NULL;
386 }
387
388 /* Internal function used by the library dependent implementation to get the
389 widget_value for a given widget in an instance */
390 widget_info *
391 lw_get_widget_info (LWLIB_ID id)
392 {
393 return get_widget_info (id, 0);
394 }
395
396 static int
397 map_widget_values (widget_value *value, int (*mapfunc) (widget_value *value,
398 void *closure),
399 void *closure)
400 {
401 int retval = 0;
402
403 if (value->contents)
404 retval = map_widget_values (value->contents, mapfunc, closure);
405 if (retval)
406 return retval;
407
408 if (value->next)
409 retval = map_widget_values (value->next, mapfunc, closure);
410 if (retval)
411 return retval;
412
413 return (mapfunc) (value, closure);
414 }
415
416 int
417 lw_map_widget_values (LWLIB_ID id, int (*mapfunc) (widget_value *value,
418 void *closure),
419 void *closure)
420 {
421 widget_info *info = get_widget_info (id, 0);
422
423 if (!info)
424 abort ();
425
426 if (info->val)
427 return map_widget_values (info->val, mapfunc, closure);
428 return 0;
429 }
430
431 static widget_instance *
432 get_widget_instance (Widget widget, Boolean remove_p)
433 {
434 widget_info *info;
435 widget_instance *instance;
436 widget_instance *prev;
437 for (info = all_widget_info; info; info = info->next)
438 for (prev = NULL, instance = info->instances;
439 instance;
440 prev = instance, instance = instance->next)
441 if (instance->widget == widget)
442 {
443 if (remove_p)
444 {
445 if (prev)
446 prev->next = instance->next;
447 else
448 info->instances = instance->next;
449 }
450 return instance;
451 }
452 return (widget_instance *) 0;
453 }
454
455 static widget_instance*
456 find_instance (LWLIB_ID id, Widget parent, Boolean pop_up_p)
457 {
458 widget_info *info = get_widget_info (id, False);
459 widget_instance *instance;
460
461 if (info)
462 for (instance = info->instances; instance; instance = instance->next)
463 if (instance->parent == parent && instance->pop_up_p == pop_up_p)
464 return instance;
465
466 return NULL;
467 }
468
469
470 /* utility function for widget_value */
471 static Boolean
472 safe_strcmp (CONST char *s1, CONST char *s2)
473 {
474 if (!!s1 ^ !!s2) return True;
475 return (s1 && s2) ? strcmp (s1, s2) : s1 ? False : !!s2;
476 }
477
478 static int
479 max (int i1, int i2)
480 {
481 return i1 > i2 ? i1 : i2;
482 }
483
484
485 #if 0
486 # define EXPLAIN(name, oc, nc, desc, a1, a2) \
487 printf ("Change: \"%s\"\tmax(%s=%d,%s=%d)\t%s %d %d\n", \
488 name, \
489 (oc == NO_CHANGE ? "none" : \
490 (oc == INVISIBLE_CHANGE ? "invisible" : \
491 (oc == VISIBLE_CHANGE ? "visible" : \
492 (oc == STRUCTURAL_CHANGE ? "structural" : "???")))), \
493 oc, \
494 (nc == NO_CHANGE ? "none" : \
495 (nc == INVISIBLE_CHANGE ? "invisible" : \
496 (nc == VISIBLE_CHANGE ? "visible" : \
497 (nc == STRUCTURAL_CHANGE ? "structural" : "???")))), \
498 nc, desc, a1, a2)
499 #else
500 # define EXPLAIN(name, oc, nc, desc, a1, a2)
501 #endif
502
503
504 static widget_value *
505 merge_widget_value (widget_value *val1, widget_value *val2, int level)
506 {
507 change_type change;
508 widget_value *merged_next;
509 widget_value *merged_contents;
510
511 if (!val1)
512 {
513 if (val2)
514 return copy_widget_value_tree (val2, STRUCTURAL_CHANGE);
515 else
516 return NULL;
517 }
518 if (!val2)
519 {
520 free_widget_value_tree (val1);
521 return NULL;
522 }
523
524 change = NO_CHANGE;
525
526 if (val1->type != val2->type)
527 {
528 EXPLAIN (val1->name, change, STRUCTURAL_CHANGE, "type change",
529 val1->type, val2->type);
530 change = max (change, STRUCTURAL_CHANGE);
531 val1->type = val2->type;
532 }
533 if (safe_strcmp (val1->name, val2->name))
534 {
535 EXPLAIN (val1->name, change, STRUCTURAL_CHANGE, "name change",
536 val1->name, val2->name);
537 change = max (change, STRUCTURAL_CHANGE);
538 safe_free_str (val1->name);
539 val1->name = safe_strdup (val2->name);
540 }
541 if (safe_strcmp (val1->value, val2->value))
542 {
543 EXPLAIN (val1->name, change, VISIBLE_CHANGE, "value change",
544 val1->value, val2->value);
545 change = max (change, VISIBLE_CHANGE);
546 safe_free_str (val1->value);
547 val1->value = safe_strdup (val2->value);
548 }
549 if (safe_strcmp (val1->key, val2->key))
550 {
551 EXPLAIN (val1->name, change, VISIBLE_CHANGE, "key change",
552 val1->key, val2->key);
553 change = max (change, VISIBLE_CHANGE);
554 safe_free_str (val1->key);
555 val1->key = safe_strdup (val2->key);
556 }
557 if (val1->enabled != val2->enabled)
558 {
559 EXPLAIN (val1->name, change, VISIBLE_CHANGE, "enablement change",
560 val1->enabled, val2->enabled);
561 change = max (change, VISIBLE_CHANGE);
562 val1->enabled = val2->enabled;
563 }
564 if (val1->selected != val2->selected)
565 {
566 EXPLAIN (val1->name, change, VISIBLE_CHANGE, "selection change",
567 val1->selected, val2->selected);
568 change = max (change, VISIBLE_CHANGE);
569 val1->selected = val2->selected;
570 }
571 if (val1->call_data != val2->call_data)
572 {
573 EXPLAIN (val1->name, change, INVISIBLE_CHANGE, "call-data change",
574 val1->call_data, val2->call_data);
575 change = max (change, INVISIBLE_CHANGE);
576 val1->call_data = val2->call_data;
577 }
578 #ifdef NEED_SCROLLBARS
579 if (merge_scrollbar_values (val1, val2))
580 {
581 EXPLAIN (val1->name, change, VISIBLE_CHANGE, "scrollbar change", 0, 0);
582 change = max (change, VISIBLE_CHANGE);
583 }
584 #endif
585
586 if (level > 0)
587 {
588 merged_contents =
589 merge_widget_value (val1->contents, val2->contents, level - 1);
590
591 if (val1->contents && !merged_contents)
592 {
593 EXPLAIN (val1->name, change, INVISIBLE_CHANGE, "(contents gone)",
594 0, 0);
595 change = max (change, INVISIBLE_CHANGE);
596 }
597 else if (merged_contents && merged_contents->change != NO_CHANGE)
598 {
599 EXPLAIN (val1->name, change, INVISIBLE_CHANGE, "(contents change)",
600 0, 0);
601 change = max (change, INVISIBLE_CHANGE);
602 }
603
604 val1->contents = merged_contents;
605 }
606
607 merged_next = merge_widget_value (val1->next, val2->next, level);
608
609 if (val1->next && !merged_next)
610 {
611 EXPLAIN (val1->name, change, STRUCTURAL_CHANGE, "(following gone)",
612 0, 0);
613 change = max (change, STRUCTURAL_CHANGE);
614 }
615 else if (merged_next)
616 {
617 if (merged_next->change)
618 {
619 EXPLAIN (val1->name, change, merged_next->change, "(following change)",
620 0, 0);
621 }
622 change = max (change, merged_next->change);
623 }
624
625 val1->next = merged_next;
626
627 val1->change = change;
628
629 if (change > NO_CHANGE && val1->toolkit_data)
630 {
631 if (val1->free_toolkit_data)
632 free (val1->toolkit_data);
633 val1->toolkit_data = NULL;
634 }
635
636 return val1;
637 }
638
639
640 /* modifying the widgets */
641 static Widget
642 name_to_widget (widget_instance *instance, CONST char *name)
643 {
644 Widget widget = NULL;
645
646 if (!instance->widget)
647 return NULL;
648
649 if (!strcmp (XtName (instance->widget), name))
650 widget = instance->widget;
651 else
652 {
653 int length = strlen (name) + 2;
654 char *real_name = (char *) alloca (length);
655 real_name [0] = '*';
656 strcpy (real_name + 1, name);
657
658 widget = XtNameToWidget (instance->widget, real_name);
659 }
660 return widget;
661 }
662
663 static void
664 set_one_value (widget_instance *instance, widget_value *val, Boolean deep_p)
665 {
666 Widget widget = name_to_widget (instance, val->name);
667
668 if (widget)
669 {
670 #ifdef NEED_LUCID
671 if (lw_lucid_widget_p (instance->widget))
672 xlw_update_one_widget (instance, widget, val, deep_p);
673 #endif
674 #ifdef NEED_MOTIF
675 if (lw_motif_widget_p (instance->widget))
676 xm_update_one_widget (instance, widget, val, deep_p);
677 #endif
678 #ifdef NEED_ATHENA
679 if (lw_xaw_widget_p (instance->widget))
680 xaw_update_one_widget (instance, widget, val, deep_p);
681 #endif
682 }
683 }
684
685 static void
686 update_one_widget_instance (widget_instance *instance, Boolean deep_p)
687 {
688 widget_value *val;
689
690 if (!instance->widget)
691 /* the widget was destroyed */
692 return;
693
694 for (val = instance->info->val; val; val = val->next)
695 if (val->change != NO_CHANGE)
696 set_one_value (instance, val, deep_p);
697 }
698
699 static void
700 update_all_widget_values (widget_info *info, Boolean deep_p)
701 {
702 widget_instance *instance;
703 widget_value *val;
704
705 for (instance = info->instances; instance; instance = instance->next)
706 update_one_widget_instance (instance, deep_p);
707
708 for (val = info->val; val; val = val->next)
709 val->change = NO_CHANGE;
710 }
711
712 void
713 lw_modify_all_widgets (LWLIB_ID id, widget_value *val, Boolean deep_p)
714 {
715 widget_info *info = get_widget_info (id, False);
716 widget_value *new_val;
717 widget_value *next_new_val;
718 widget_value *cur;
719 widget_value *prev;
720 widget_value *next;
721 int found;
722
723 if (!info)
724 return;
725
726 for (new_val = val; new_val; new_val = new_val->next)
727 {
728 next_new_val = new_val->next;
729 new_val->next = NULL;
730 found = False;
731 for (prev = NULL, cur = info->val; cur; prev = cur, cur = cur->next)
732 if (!strcmp (cur->name, new_val->name))
733 {
734 found = True;
735 next = cur->next;
736 cur->next = NULL;
737 cur = merge_widget_value (cur, new_val, deep_p ? 1000 : 1);
738 if (prev)
739 prev->next = cur ? cur : next;
740 else
741 info->val = cur ? cur : next;
742 if (cur)
743 cur->next = next;
744 break;
745 }
746 if (!found)
747 {
748 /* Could not find it, add it */
749 if (prev)
750 prev->next = copy_widget_value_tree (new_val, STRUCTURAL_CHANGE);
751 else
752 info->val = copy_widget_value_tree (new_val, STRUCTURAL_CHANGE);
753 }
754 new_val->next = next_new_val;
755 }
756
757 update_all_widget_values (info, deep_p);
758 }
759
760
761 /* creating the widgets */
762
763 static void
764 initialize_widget_instance (widget_instance *instance)
765 {
766 widget_value *val;
767
768 for (val = instance->info->val; val; val = val->next)
769 val->change = STRUCTURAL_CHANGE;
770
771 update_one_widget_instance (instance, True);
772
773 for (val = instance->info->val; val; val = val->next)
774 val->change = NO_CHANGE;
775 }
776
777
778 static widget_creation_function
779 find_in_table (CONST char *type, widget_creation_entry *table)
780 {
781 widget_creation_entry *cur;
782 for (cur = table; cur->type; cur++)
783 if (!strcasecmp (type, cur->type))
784 return cur->function;
785 return NULL;
786 }
787
788 static Boolean
789 dialog_spec_p (CONST char *name)
790 {
791 /* return True if name matches [EILPQeilpq][1-9][Bb] or
792 [EILPQeilpq][1-9][Bb][Rr][1-9] */
793 if (!name)
794 return False;
795
796 switch (name [0])
797 {
798 case 'E': case 'I': case 'L': case 'P': case 'Q':
799 case 'e': case 'i': case 'l': case 'p': case 'q':
800 if (name [1] >= '0' && name [1] <= '9')
801 {
802 if (name [2] != 'B' && name [2] != 'b')
803 return False;
804 if (!name [3])
805 return True;
806 if ((name [3] == 'T' || name [3] == 't') && !name [4])
807 return True;
808 if ((name [3] == 'R' || name [3] == 'r')
809 && name [4] >= '0' && name [4] <= '9' && !name [5])
810 return True;
811 return False;
812 }
813 else
814 return False;
815
816 default:
817 return False;
818 }
819 }
820
821 static void
822 instantiate_widget_instance (widget_instance *instance)
823 {
824 widget_creation_function function = NULL;
825
826 #ifdef NEED_LUCID
827 if (!function)
828 function = find_in_table (instance->info->type, xlw_creation_table);
829 #endif
830 #ifdef NEED_MOTIF
831 if (!function)
832 function = find_in_table (instance->info->type, xm_creation_table);
833 #endif
834 #ifdef NEED_ATHENA
835 if (!function)
836 function = find_in_table (instance->info->type, xaw_creation_table);
837 #endif
838
839 if (!function)
840 {
841 if (dialog_spec_p (instance->info->type))
842 {
843 #ifdef DIALOGS_MOTIF
844 if (!function)
845 function = xm_create_dialog;
846 #endif
847 #ifdef DIALOGS_ATHENA
848 if (!function)
849 function = xaw_create_dialog;
850 #endif
851 #ifdef DIALOGS_LUCID
852 /* not yet (not ever?) */
853 #endif
854 }
855 }
856
857 if (!function)
858 {
859 fprintf (stderr, "No creation function for widget type %s\n",
860 instance->info->type);
861 abort ();
862 }
863
864 instance->widget = (*function) (instance);
865
866 if (!instance->widget)
867 abort ();
868
869 /* XtRealizeWidget (instance->widget);*/
870 }
871
872 void
873 lw_register_widget (CONST char *type, CONST char *name,
874 LWLIB_ID id, widget_value *val,
875 lw_callback pre_activate_cb, lw_callback selection_cb,
876 lw_callback post_activate_cb)
877 {
878 if (!get_widget_info (id, False))
879 allocate_widget_info (type, name, id, val, pre_activate_cb, selection_cb,
880 post_activate_cb);
881 }
882
883 Widget
884 lw_get_widget (LWLIB_ID id, Widget parent, Boolean pop_up_p)
885 {
886 widget_instance *instance;
887
888 instance = find_instance (id, parent, pop_up_p);
889 return instance ? instance->widget : NULL;
890 }
891
892 Widget
893 lw_make_widget (LWLIB_ID id, Widget parent, Boolean pop_up_p)
894 {
895 widget_instance *instance;
896 widget_info *info;
897
898 instance = find_instance (id, parent, pop_up_p);
899 if (!instance)
900 {
901 info = get_widget_info (id, False);
902 if (!info)
903 return NULL;
904 instance = allocate_widget_instance (info, parent, pop_up_p);
905 initialize_widget_instance (instance);
906 }
907 if (!instance->widget)
908 abort ();
909 return instance->widget;
910 }
911
912 Widget
913 lw_create_widget (CONST char *type, CONST char *name,
914 LWLIB_ID id, widget_value *val,
915 Widget parent, Boolean pop_up_p, lw_callback pre_activate_cb,
916 lw_callback selection_cb, lw_callback post_activate_cb)
917 {
918 lw_register_widget (type, name, id, val, pre_activate_cb, selection_cb,
919 post_activate_cb);
920 return lw_make_widget (id, parent, pop_up_p);
921 }
922
923
924 /* destroying the widgets */
925 static void
926 destroy_one_instance (widget_instance *instance)
927 {
928 /* Remove the destroy callback on the widget; that callback will try to
929 dereference the instance object (to set its widget slot to 0, since the
930 widget is dead.) Since the instance is now dead, we don't have to worry
931 about the fact that its widget is dead too.
932
933 This happens in the Phase2Destroy of the widget, so this callback would
934 not have been run until arbitrarily long after the instance was freed.
935 */
936 if (instance->widget)
937 XtRemoveCallback (instance->widget, XtNdestroyCallback,
938 mark_widget_destroyed, (XtPointer)instance);
939
940 if (instance->widget)
941 {
942 /* The else are pretty tricky here, including the empty statement
943 at the end because it would be very bad to destroy a widget
944 twice. */
945 #ifdef NEED_LUCID
946 if (lw_lucid_widget_p (instance->widget))
947 xlw_destroy_instance (instance);
948 else
949 #endif
950 #ifdef NEED_MOTIF
951 if (lw_motif_widget_p (instance->widget))
952 xm_destroy_instance (instance);
953 else
954 #endif
955 #ifdef NEED_ATHENA
956 if (lw_xaw_widget_p (instance->widget))
957 xaw_destroy_instance (instance);
958 else
959 #endif
960 {
961 /* do not remove the empty statement */
962 ;
963 }
964 }
965
966 free_widget_instance (instance);
967 }
968
969 void
970 lw_destroy_widget (Widget w)
971 {
972 widget_instance *instance = get_widget_instance (w, True);
973
974 if (instance)
975 {
976 widget_info *info = instance->info;
977 /* instance has already been removed from the list; free it */
978 destroy_one_instance (instance);
979 /* if there are no instances left, free the info too */
980 if (!info->instances)
981 lw_destroy_all_widgets (info->id);
982 }
983 }
984
985 void
986 lw_destroy_all_widgets (LWLIB_ID id)
987 {
988 widget_info *info = get_widget_info (id, True);
989 widget_instance *instance;
990 widget_instance *next;
991
992 if (info)
993 {
994 for (instance = info->instances; instance; )
995 {
996 next = instance->next;
997 destroy_one_instance (instance);
998 instance = next;
999 }
1000 free_widget_info (info);
1001 }
1002 }
1003
1004 void
1005 lw_destroy_everything ()
1006 {
1007 while (all_widget_info)
1008 lw_destroy_all_widgets (all_widget_info->id);
1009 }
1010
1011 void
1012 lw_destroy_all_pop_ups ()
1013 {
1014 widget_info *info;
1015 widget_info *next;
1016 widget_instance *instance;
1017
1018 for (info = all_widget_info; info; info = next)
1019 {
1020 next = info->next;
1021 instance = info->instances;
1022 if (instance && instance->pop_up_p)
1023 lw_destroy_all_widgets (info->id);
1024 }
1025 }
1026
1027 Widget
1028 lw_raise_all_pop_up_widgets (void)
1029 {
1030 widget_info *info;
1031 widget_instance *instance;
1032 Widget result = NULL;
1033
1034 for (info = all_widget_info; info; info = info->next)
1035 for (instance = info->instances; instance; instance = instance->next)
1036 if (instance->pop_up_p)
1037 {
1038 Widget widget = instance->widget;
1039 if (widget)
1040 {
1041 if (XtIsManaged (widget)
1042 #ifdef NEED_MOTIF
1043 /* What a complete load of crap!!!!
1044 When a dialogShell is on the screen, it is not managed!
1045 */
1046 || (lw_motif_widget_p (instance->widget) &&
1047 XtIsManaged (first_child (widget)))
1048 #endif
1049 )
1050 {
1051 if (!result)
1052 result = widget;
1053 XMapRaised (XtDisplay (widget), XtWindow (widget));
1054 }
1055 }
1056 }
1057 return result;
1058 }
1059
1060 static void
1061 lw_pop_all_widgets (LWLIB_ID id, Boolean up)
1062 {
1063 widget_info *info = get_widget_info (id, False);
1064 widget_instance *instance;
1065
1066 if (info)
1067 for (instance = info->instances; instance; instance = instance->next)
1068 if (instance->pop_up_p && instance->widget)
1069 {
1070 #ifdef NEED_LUCID
1071 if (lw_lucid_widget_p (instance->widget))
1072 {
1073 XtRealizeWidget (instance->widget);
1074 xlw_pop_instance (instance, up);
1075 }
1076 #endif
1077 #ifdef NEED_MOTIF
1078 if (lw_motif_widget_p (instance->widget))
1079 {
1080 XtRealizeWidget (instance->widget);
1081 xm_pop_instance (instance, up);
1082 }
1083 #endif
1084 #ifdef NEED_ATHENA
1085 if (lw_xaw_widget_p (instance->widget))
1086 {
1087 XtRealizeWidget (XtParent (instance->widget));
1088 XtRealizeWidget (instance->widget);
1089 xaw_pop_instance (instance, up);
1090 }
1091 #endif
1092 }
1093 }
1094
1095 void
1096 lw_pop_up_all_widgets (LWLIB_ID id)
1097 {
1098 lw_pop_all_widgets (id, True);
1099 }
1100
1101 void
1102 lw_pop_down_all_widgets (LWLIB_ID id)
1103 {
1104 lw_pop_all_widgets (id, False);
1105 }
1106
1107 void
1108 lw_popup_menu (Widget widget, XEvent *event)
1109 {
1110 #ifdef MENUBARS_LUCID
1111 if (lw_lucid_widget_p (widget))
1112 xlw_popup_menu (widget, event);
1113 #endif
1114 #ifdef MENUBARS_MOTIF
1115 if (lw_motif_widget_p (widget))
1116 xm_popup_menu (widget, event);
1117 #endif
1118 #ifdef MENUBARS_ATHENA
1119 if (lw_xaw_widget_p (widget))
1120 xaw_popup_menu (widget, event); /* not implemented */
1121 #endif
1122 }
1123
1124 /* get the values back */
1125 static Boolean
1126 get_one_value (widget_instance *instance, widget_value *val)
1127 {
1128 Widget widget = name_to_widget (instance, val->name);
1129
1130 if (widget)
1131 {
1132 #ifdef NEED_LUCID
1133 if (lw_lucid_widget_p (instance->widget))
1134 xlw_update_one_value (instance, widget, val);
1135 #endif
1136 #ifdef NEED_MOTIF
1137 if (lw_motif_widget_p (instance->widget))
1138 xm_update_one_value (instance, widget, val);
1139 #endif
1140 #ifdef NEED_ATHENA
1141 if (lw_xaw_widget_p (instance->widget))
1142 xaw_update_one_value (instance, widget, val);
1143 #endif
1144 return True;
1145 }
1146 else
1147 return False;
1148 }
1149
1150 Boolean
1151 lw_get_some_values (LWLIB_ID id, widget_value *val_out)
1152 {
1153 widget_info *info = get_widget_info (id, False);
1154 widget_instance *instance;
1155 widget_value *val;
1156 Boolean result = False;
1157
1158 if (!info)
1159 return False;
1160
1161 instance = info->instances;
1162 if (!instance)
1163 return False;
1164
1165 for (val = val_out; val; val = val->next)
1166 if (get_one_value (instance, val))
1167 result = True;
1168
1169 return result;
1170 }
1171
1172 widget_value*
1173 lw_get_all_values (LWLIB_ID id)
1174 {
1175 widget_info *info = get_widget_info (id, False);
1176 widget_value *val = info->val;
1177 if (lw_get_some_values (id, val))
1178 return val;
1179 else
1180 return NULL;
1181 }
1182
1183 /* internal function used by the library dependent implementation to get the
1184 widget_value for a given widget in an instance */
1185 widget_value*
1186 lw_get_widget_value_for_widget (widget_instance *instance, Widget w)
1187 {
1188 char *name = XtName (w);
1189 widget_value *cur;
1190 for (cur = instance->info->val; cur; cur = cur->next)
1191 if (!strcmp (cur->name, name))
1192 return cur;
1193 return NULL;
1194 }
1195
1196
1197 /* update other instances value when one thing changed */
1198 /* This function can be used as a an XtCallback for the widgets that get
1199 modified to update other instances of the widgets. Closure should be the
1200 widget_instance. */
1201 void
1202 lw_internal_update_other_instances (Widget widget, XtPointer closure,
1203 XtPointer call_data)
1204 {
1205 /* To forbid recursive calls */
1206 static Boolean updating;
1207
1208 widget_instance *instance = (widget_instance*)closure;
1209 char *name = XtName (widget);
1210 widget_info *info;
1211 widget_instance *cur;
1212 widget_value *val;
1213
1214 /* never recurse as this could cause infinite recursions. */
1215 if (updating)
1216 return;
1217
1218 /* protect against the widget being destroyed */
1219 if (XtWidgetBeingDestroyedP (widget))
1220 return;
1221
1222 /* Return immediately if there are no other instances */
1223 info = instance->info;
1224 if (!info->instances->next)
1225 return;
1226
1227 updating = True;
1228
1229 for (val = info->val; val && strcmp (val->name, name); val = val->next);
1230
1231 if (val && get_one_value (instance, val))
1232 for (cur = info->instances; cur; cur = cur->next)
1233 if (cur != instance)
1234 set_one_value (cur, val, True);
1235
1236 updating = False;
1237 }
1238
1239
1240
1241 /* get the id */
1242
1243 LWLIB_ID
1244 lw_get_widget_id (Widget w)
1245 {
1246 widget_instance *instance = get_widget_instance (w, False);
1247
1248 return instance ? instance->info->id : 0;
1249 }
1250
1251
1252 /* set the keyboard focus */
1253 void
1254 lw_set_keyboard_focus (Widget parent, Widget w)
1255 {
1256 #ifdef NEED_MOTIF
1257 xm_set_keyboard_focus (parent, w);
1258 #else
1259 XtSetKeyboardFocus (parent, w);
1260 #endif
1261 }
1262
1263
1264 /* Show busy */
1265 static void
1266 show_one_widget_busy (Widget w, Boolean flag)
1267 {
1268 Pixel foreground = 0;
1269 Pixel background = 1;
1270 Widget widget_to_invert = XtNameToWidget (w, "*sheet");
1271 if (!widget_to_invert)
1272 widget_to_invert = w;
1273
1274 XtVaGetValues (widget_to_invert,
1275 XtNforeground, &foreground,
1276 XtNbackground, &background,
1277 0);
1278 XtVaSetValues (widget_to_invert,
1279 XtNforeground, background,
1280 XtNbackground, foreground,
1281 0);
1282 }
1283
1284 void
1285 lw_show_busy (Widget w, Boolean busy)
1286 {
1287 widget_instance *instance = get_widget_instance (w, False);
1288 widget_info *info;
1289 widget_instance *next;
1290
1291 if (instance)
1292 {
1293 info = instance->info;
1294 if (info->busy != busy)
1295 {
1296 for (next = info->instances; next; next = next->next)
1297 if (next->widget)
1298 show_one_widget_busy (next->widget, busy);
1299 info->busy = busy;
1300 }
1301 }
1302 }