This commit was generated by cvs2svn to compensate for changes in r1705,
[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 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 WIN32_NATIVE
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 /* strcasecmp() is not sufficiently portable or standard,
828    and it's easier just to write our own. */
829 static int
830 ascii_strcasecmp (const char *s1, const char *s2)
831 {
832   while (1)
833     {
834       char c1 = *s1++;
835       char c2 = *s2++;
836       if (c1 >= 'A' && c1 <= 'Z') c1 += 'a' - 'A';
837       if (c2 >= 'A' && c2 <= 'Z') c2 += 'a' - 'A';
838       if (c1 != c2) return c1 - c2;
839       if (c1 == '\0') return 0;
840     }
841 }
842
843 static widget_creation_function
844 find_in_table (const char *type, widget_creation_entry *table)
845 {
846   widget_creation_entry *cur;
847   for (cur = table; cur->type; cur++)
848     if (!ascii_strcasecmp (type, cur->type))
849       return cur->function;
850   return NULL;
851 }
852
853 static Boolean
854 dialog_spec_p (const char *name)
855 {
856   /* return True if name matches [EILPQeilpq][1-9][Bb] or
857      [EILPQeilpq][1-9][Bb][Rr][1-9] */
858   if (!name)
859     return False;
860
861   switch (name [0])
862     {
863     case 'E': case 'I': case 'L': case 'P': case 'Q':
864     case 'e': case 'i': case 'l': case 'p': case 'q':
865       if (name [1] >= '0' && name [1] <= '9')
866         {
867           if (name [2] != 'B' && name [2] != 'b')
868             return False;
869           if (!name [3])
870             return True;
871           if ((name [3] == 'T' || name [3] == 't') && !name [4])
872             return True;
873           if ((name [3] == 'R' || name [3] == 'r')
874               && name [4] >= '0' && name [4] <= '9' && !name [5])
875             return True;
876           return False;
877         }
878       else
879         return False;
880
881     default:
882       return False;
883     }
884 }
885
886 static void
887 instantiate_widget_instance (widget_instance *instance)
888 {
889   widget_creation_function function = NULL;
890
891 #ifdef NEED_LUCID
892   if (!function)
893     function = find_in_table (instance->info->type, xlw_creation_table);
894 #endif
895 #ifdef NEED_MOTIF
896   if (!function)
897     function = find_in_table (instance->info->type, xm_creation_table);
898 #endif
899 #ifdef NEED_ATHENA
900   if (!function)
901     function = find_in_table (instance->info->type, xaw_creation_table);
902 #endif
903
904   if (!function)
905     {
906       if (dialog_spec_p (instance->info->type))
907         {
908 #ifdef LWLIB_DIALOGS_MOTIF
909           if (!function)
910             function = xm_create_dialog;
911 #endif
912 #ifdef LWLIB_DIALOGS_ATHENA
913           if (!function)
914             function = xaw_create_dialog;
915 #endif
916 #ifdef LWLIB_DIALOGS_LUCID
917           /* not yet (not ever?) */
918 #endif
919         }
920     }
921
922   if (!function)
923     {
924       fprintf (stderr, "No creation function for widget type %s\n",
925                instance->info->type);
926       abort ();
927     }
928
929   instance->widget = (*function) (instance);
930
931   if (!instance->widget)
932     abort ();
933
934   /*   XtRealizeWidget (instance->widget);*/
935 }
936
937 void
938 lw_register_widget (const char *type, const char *name,
939                     LWLIB_ID id, widget_value *val,
940                     lw_callback pre_activate_cb, lw_callback selection_cb,
941                     lw_callback post_activate_cb)
942 {
943   if (!get_widget_info (id, False))
944     allocate_widget_info (type, name, id, val, pre_activate_cb, selection_cb,
945                           post_activate_cb);
946 }
947
948 Widget
949 lw_get_widget (LWLIB_ID id, Widget parent, Boolean pop_up_p)
950 {
951   widget_instance *instance = find_instance (id, parent, pop_up_p);
952   return instance ? instance->widget : NULL;
953 }
954
955 Widget
956 lw_make_widget (LWLIB_ID id, Widget parent, Boolean pop_up_p)
957 {
958   widget_instance *instance = find_instance (id, parent, pop_up_p);
959
960   if (!instance)
961     {
962       widget_info *info = get_widget_info (id, False);
963       if (!info)
964         return NULL;
965       instance = allocate_widget_instance (info, parent, pop_up_p);
966       initialize_widget_instance (instance);
967     }
968   if (!instance->widget)
969     abort ();
970   return instance->widget;
971 }
972
973 Widget
974 lw_create_widget (const char *type, const char *name,
975                   LWLIB_ID id, widget_value *val,
976                   Widget parent, Boolean pop_up_p, lw_callback pre_activate_cb,
977                   lw_callback selection_cb, lw_callback post_activate_cb)
978 {
979   lw_register_widget (type, name, id, val, pre_activate_cb, selection_cb,
980                       post_activate_cb);
981   return lw_make_widget (id, parent, pop_up_p);
982 }
983
984 \f
985 /* destroying the widgets */
986 static void
987 destroy_one_instance (widget_instance *instance)
988 {
989   /* Remove the destroy callback on the widget; that callback will try to
990      dereference the instance object (to set its widget slot to 0, since the
991      widget is dead.)  Since the instance is now dead, we don't have to worry
992      about the fact that its widget is dead too.
993
994      This happens in the Phase2Destroy of the widget, so this callback would
995      not have been run until arbitrarily long after the instance was freed.
996    */
997   if (instance->widget)
998     XtRemoveCallback (instance->widget, XtNdestroyCallback,
999                       mark_widget_destroyed, (XtPointer)instance);
1000
1001   if (instance->widget)
1002     {
1003       /* The else are pretty tricky here, including the empty statement
1004          at the end because it would be very bad to destroy a widget
1005          twice. */
1006 #ifdef NEED_LUCID
1007       if (lw_lucid_widget_p (instance->widget))
1008         xlw_destroy_instance (instance);
1009       else
1010 #endif
1011 #ifdef NEED_MOTIF
1012       if (lw_motif_widget_p (instance->widget))
1013         xm_destroy_instance (instance);
1014       else
1015 #endif
1016 #ifdef NEED_ATHENA
1017       if (lw_xaw_widget_p (instance->widget))
1018         xaw_destroy_instance (instance);
1019       else
1020 #endif
1021         {
1022           /* do not remove the empty statement */
1023           ;
1024         }
1025     }
1026
1027   free_widget_instance (instance);
1028 }
1029
1030 void
1031 lw_destroy_widget (Widget w)
1032 {
1033   widget_instance *instance = get_widget_instance (w, True);
1034
1035   if (instance)
1036     {
1037       widget_info *info = instance->info;
1038       /* instance has already been removed from the list; free it */
1039       destroy_one_instance (instance);
1040       /* if there are no instances left, free the info too */
1041       if (!info->instances)
1042         lw_destroy_all_widgets (info->id);
1043     }
1044 }
1045
1046 void
1047 lw_destroy_all_widgets (LWLIB_ID id)
1048 {
1049   widget_info *info = get_widget_info (id, True);
1050   widget_instance *instance;
1051   widget_instance *next;
1052
1053   if (info)
1054     {
1055       for (instance = info->instances; instance; )
1056         {
1057           next = instance->next;
1058           destroy_one_instance (instance);
1059           instance = next;
1060         }
1061       free_widget_info (info);
1062     }
1063 }
1064
1065 void
1066 lw_destroy_everything (void)
1067 {
1068   while (all_widget_info)
1069     lw_destroy_all_widgets (all_widget_info->id);
1070 }
1071
1072 void
1073 lw_destroy_all_pop_ups (void)
1074 {
1075   widget_info *info;
1076   widget_info *next;
1077   widget_instance *instance;
1078
1079   for (info = all_widget_info; info; info = next)
1080     {
1081       next = info->next;
1082       instance = info->instances;
1083       if (instance && instance->pop_up_p)
1084         lw_destroy_all_widgets (info->id);
1085     }
1086 }
1087
1088 Widget
1089 lw_raise_all_pop_up_widgets (void)
1090 {
1091   widget_info *info;
1092   widget_instance *instance;
1093   Widget result = NULL;
1094
1095   for (info = all_widget_info; info; info = info->next)
1096     for (instance = info->instances; instance; instance = instance->next)
1097       if (instance->pop_up_p)
1098         {
1099           Widget widget = instance->widget;
1100           if (widget)
1101             {
1102               if (XtIsManaged (widget)
1103 #ifdef NEED_MOTIF
1104                   /* What a complete load of crap!!!!
1105                      When a dialogShell is on the screen, it is not managed!
1106                    */
1107                   || (lw_motif_widget_p (instance->widget) &&
1108                       XtIsManaged (first_child (widget)))
1109 #endif
1110                   )
1111                 {
1112                   if (!result)
1113                     result = widget;
1114                   XMapRaised (XtDisplay (widget), XtWindow (widget));
1115                 }
1116             }
1117         }
1118   return result;
1119 }
1120
1121 static void
1122 lw_pop_all_widgets (LWLIB_ID id, Boolean up)
1123 {
1124   widget_info *info = get_widget_info (id, False);
1125   widget_instance *instance;
1126
1127   if (info)
1128     for (instance = info->instances; instance; instance = instance->next)
1129       if (instance->pop_up_p && instance->widget)
1130         {
1131 #ifdef NEED_LUCID
1132           if (lw_lucid_widget_p (instance->widget))
1133             {
1134               XtRealizeWidget (instance->widget);
1135               xlw_pop_instance (instance, up);
1136             }
1137 #endif
1138 #ifdef NEED_MOTIF
1139           if (lw_motif_widget_p (instance->widget))
1140             {
1141               XtRealizeWidget (instance->widget);
1142               xm_pop_instance (instance, up);
1143             }
1144 #endif
1145 #ifdef NEED_ATHENA
1146           if (lw_xaw_widget_p (instance->widget))
1147             {
1148               XtRealizeWidget (XtParent (instance->widget));
1149               XtRealizeWidget (instance->widget);
1150               xaw_pop_instance (instance, up);
1151             }
1152 #endif
1153         }
1154 }
1155
1156 void
1157 lw_pop_up_all_widgets (LWLIB_ID id)
1158 {
1159   lw_pop_all_widgets (id, True);
1160 }
1161
1162 void
1163 lw_pop_down_all_widgets (LWLIB_ID id)
1164 {
1165   lw_pop_all_widgets (id, False);
1166 }
1167
1168 void
1169 lw_popup_menu (Widget widget, XEvent *event)
1170 {
1171 #ifdef LWLIB_MENUBARS_LUCID
1172   if (lw_lucid_widget_p (widget))
1173     xlw_popup_menu (widget, event);
1174 #endif
1175 #ifdef LWLIB_MENUBARS_MOTIF
1176   if (lw_motif_widget_p (widget))
1177     xm_popup_menu (widget, event);
1178 #endif
1179 #ifdef LWLIB_MENUBARS_ATHENA
1180   if (lw_xaw_widget_p (widget))
1181     xaw_popup_menu (widget, event); /* not implemented */
1182 #endif
1183 }
1184
1185 \f/* get the values back */
1186 static Boolean
1187 get_one_value (widget_instance *instance, widget_value *val)
1188 {
1189   Widget widget = name_to_widget (instance, val->name);
1190
1191   if (widget)
1192     {
1193 #ifdef NEED_LUCID
1194       if (lw_lucid_widget_p (instance->widget))
1195         xlw_update_one_value (instance, widget, val);
1196 #endif
1197 #ifdef NEED_MOTIF
1198       if (lw_motif_widget_p (instance->widget))
1199         xm_update_one_value (instance, widget, val);
1200 #endif
1201 #ifdef NEED_ATHENA
1202       if (lw_xaw_widget_p (instance->widget))
1203         xaw_update_one_value (instance, widget, val);
1204 #endif
1205       return True;
1206     }
1207   else
1208     return False;
1209 }
1210
1211 Boolean
1212 lw_get_some_values (LWLIB_ID id, widget_value *val_out)
1213 {
1214   widget_info *info = get_widget_info (id, False);
1215   widget_instance *instance;
1216   widget_value *val;
1217   Boolean result = False;
1218
1219   if (!info)
1220     return False;
1221
1222   instance = info->instances;
1223   if (!instance)
1224     return False;
1225
1226   for (val = val_out; val; val = val->next)
1227     if (get_one_value (instance, val))
1228       result = True;
1229
1230   return result;
1231 }
1232
1233 widget_value*
1234 lw_get_all_values (LWLIB_ID id)
1235 {
1236   widget_info *info = get_widget_info (id, False);
1237   widget_value *val = info->val;
1238   if (lw_get_some_values (id, val))
1239     return val;
1240   else
1241     return NULL;
1242 }
1243
1244 /* internal function used by the library dependent implementation to get the
1245    widget_value for a given widget in an instance */
1246 widget_value*
1247 lw_get_widget_value_for_widget (widget_instance *instance, Widget w)
1248 {
1249   char *name = XtName (w);
1250   widget_value *cur;
1251   for (cur = instance->info->val; cur; cur = cur->next)
1252     if (!strcmp (cur->name, name))
1253       return cur;
1254   return NULL;
1255 }
1256
1257 \f
1258 /* update other instances value when one thing changed */
1259 /* This function can be used as a an XtCallback for the widgets that get
1260   modified to update other instances of the widgets.  Closure should be the
1261   widget_instance. */
1262 void
1263 lw_internal_update_other_instances (Widget widget, XtPointer closure,
1264                                     XtPointer call_data)
1265 {
1266   /* To forbid recursive calls */
1267   static Boolean updating;
1268
1269   widget_instance *instance = (widget_instance*)closure;
1270   char *name = XtName (widget);
1271   widget_info *info;
1272   widget_instance *cur;
1273   widget_value *val;
1274
1275   /* never recurse as this could cause infinite recursions. */
1276   if (updating)
1277     return;
1278
1279   /* protect against the widget being destroyed */
1280   if (XtWidgetBeingDestroyedP (widget))
1281     return;
1282
1283   /* Return immediately if there are no other instances */
1284   info = instance->info;
1285   if (!info->instances->next)
1286     return;
1287
1288   updating = True;
1289
1290   for (val = info->val; val && strcmp (val->name, name); val = val->next);
1291
1292   if (val && get_one_value (instance, val))
1293     for (cur = info->instances; cur; cur = cur->next)
1294       if (cur != instance)
1295         set_one_value (cur, val, True);
1296
1297   updating = False;
1298 }
1299
1300
1301 \f
1302 /* get the id */
1303
1304 LWLIB_ID
1305 lw_get_widget_id (Widget w)
1306 {
1307   widget_instance *instance = get_widget_instance (w, False);
1308
1309   return instance ? instance->info->id : 0;
1310 }
1311
1312 \f
1313 /* set the keyboard focus */
1314 void
1315 lw_set_keyboard_focus (Widget parent, Widget w)
1316 {
1317 #if defined(NEED_MOTIF) && !defined(LESSTIF_VERSION)
1318   /* This loses with Lesstif v0.75a */
1319   xm_set_keyboard_focus (parent, w);
1320 #else
1321   XtSetKeyboardFocus (parent, w);
1322 #endif
1323 }
1324
1325 \f
1326 /* Show busy */
1327 static void
1328 show_one_widget_busy (Widget w, Boolean flag)
1329 {
1330   Pixel foreground = 0;
1331   Pixel background = 1;
1332   Widget widget_to_invert = XtNameToWidget (w, "*sheet");
1333   Arg al [2];
1334
1335   if (!widget_to_invert)
1336     widget_to_invert = w;
1337
1338   XtSetArg (al [0], XtNforeground, &foreground);
1339   XtSetArg (al [1], XtNbackground, &background);
1340   XtGetValues (widget_to_invert, al, 2);
1341
1342   XtSetArg (al [0], XtNforeground, background);
1343   XtSetArg (al [1], XtNbackground, foreground);
1344   XtSetValues (widget_to_invert, al, 2);
1345 }
1346
1347 void
1348 lw_show_busy (Widget w, Boolean busy)
1349 {
1350   widget_instance *instance = get_widget_instance (w, False);
1351   widget_info *info;
1352   widget_instance *next;
1353
1354   if (instance)
1355     {
1356       info = instance->info;
1357       if (info->busy != busy)
1358         {
1359           for (next = info->instances; next; next = next->next)
1360             if (next->widget)
1361               show_one_widget_busy (next->widget, busy);
1362           info->busy = busy;
1363         }
1364     }
1365 }
1366
1367 void lw_add_value_args_to_args (widget_value* wv, ArgList addto, int* offset)
1368 {
1369   int i;
1370   if (wv->args && wv->args->nargs)
1371     {
1372       for (i = 0; i<wv->args->nargs; i++)
1373         {
1374           addto[i + *offset] = wv->args->args[i];
1375         }
1376       *offset += wv->args->nargs;
1377     }
1378 }
1379
1380 void lw_add_widget_value_arg (widget_value* wv, String name, XtArgVal value)
1381 {
1382   int i = 0;
1383   if (!wv->args)
1384     {
1385       wv->args = (widget_args *) malloc (sizeof (widget_args));
1386       memset (wv->args, '\0', sizeof (widget_args));
1387       wv->args->ref_count = 1;
1388       wv->args->nargs = 0;
1389       wv->args->args = (ArgList) malloc (sizeof (Arg) * 10);
1390       memset (wv->args->args, '\0', sizeof (Arg) * 10);
1391     }
1392   
1393   if (wv->args->nargs > 10)
1394     return;
1395
1396   /* If the arg is already there then we must replace it. */
1397   for (i = 0; i < wv->args->nargs; i++)
1398     {
1399       if (!strcmp (wv->args->args[i].name, name))
1400         {
1401           XtSetArg (wv->args->args [i], name, value);
1402           break;
1403         }
1404     }
1405   if (i >= wv->args->nargs)
1406     {
1407       XtSetArg (wv->args->args [wv->args->nargs], name, value);   wv->args->nargs++;
1408     }
1409 }
1410
1411 static void free_widget_value_args (widget_value* wv)
1412 {
1413   if (wv->args)
1414     {
1415       if (--wv->args->ref_count <= 0)
1416         {
1417 #ifdef LWLIB_WIDGETS_MOTIF
1418           int i;
1419           for (i = 0; i < wv->args->nargs; i++)
1420             {
1421               if (!strcmp (wv->args->args[i].name, XmNfontList))
1422                 XmFontListFree ((XmFontList)wv->args->args[i].value);
1423             }
1424 #endif
1425           free (wv->args->args);
1426           free (wv->args);
1427           wv->args = 0;
1428         }
1429     }
1430 }
1431
1432 void lw_copy_widget_value_args (widget_value* val, widget_value* copy)
1433 {
1434   if (val == copy || val->args == copy->args)
1435     return;
1436
1437   if (copy->args)
1438     {
1439       free_widget_value_args (copy);
1440     }
1441
1442   if (val->args)
1443     {
1444       copy->args = val->args;
1445       copy->args->ref_count++;
1446     }
1447 }
1448
1449 /* Remove %_ and convert %% to %.  We can do this in-place because we
1450    are always shortening, never lengthening, the string. */
1451 void
1452 lw_remove_accelerator_spec (char *val)
1453 {
1454   char *foo = val, *bar = val;
1455
1456   while (*bar)
1457     {
1458       if (*bar == '%' && *(bar+1) == '_')
1459         bar += 2;
1460       else if (*bar == '%' && *(bar+1) == '%')
1461         {
1462           *foo++ = *bar++;
1463           bar++;
1464         }
1465       else
1466         *foo++ = *bar++;
1467     }
1468   *foo = '\0';
1469 }