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