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