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