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