(_widget_value): Add help string.
[bpt/emacs.git] / lwlib / lwlib.c
1 /* A general interface to the widgets of different toolkits.
2 Copyright (C) 1992, 1993 Lucid, Inc.
3
4 This file is part of the Lucid Widget Library.
5
6 The Lucid Widget Library is free software; you can redistribute it and/or
7 modify it under the terms of the GNU General Public License as published by
8 the Free Software Foundation; either version 2, or (at your option)
9 any later version.
10
11 The Lucid Widget Library is distributed in the hope that it will be useful,
12 but WITHOUT ANY WARRANTY; without even the implied warranty of
13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 GNU General Public License for more details.
15
16 You should have received a copy of the GNU General Public License
17 along with GNU Emacs; see the file COPYING. If not, write to
18 the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
19 Boston, MA 02111-1307, USA. */
20
21 #ifdef NeXT
22 #undef __STRICT_BSD__ /* ick */
23 #endif
24
25 #ifdef HAVE_CONFIG_H
26 #include <config.h>
27 #endif
28
29 #include <sys/types.h>
30 #include <stdio.h>
31 #include <ctype.h>
32 #include "lwlib-int.h"
33 #include "lwlib-utils.h"
34 #include <X11/StringDefs.h>
35
36 extern long *xmalloc();
37
38 #if defined (USE_LUCID)
39 #include "lwlib-Xlw.h"
40 #endif
41 #if defined (USE_MOTIF)
42 #include "lwlib-Xm.h"
43 #else /* not USE_MOTIF */
44 #if defined (USE_LUCID)
45 #define USE_XAW
46 #endif /* not USE_MOTIF && USE_LUCID */
47 #endif
48 #if defined (USE_OLIT)
49 #include "lwlib-Xol.h"
50 #endif
51 #if defined (USE_XAW)
52 #include <X11/Xaw/Paned.h>
53 #include "lwlib-Xaw.h"
54 #endif
55
56 #if !defined (USE_LUCID) && !defined (USE_MOTIF) && !defined (USE_OLIT)
57 ERROR! At least one of USE_LUCID, USE_MOTIF or USE_OLIT must be defined.
58 #endif
59
60 #if defined (USE_MOTIF) && defined (USE_OLIT)
61 ERROR! no more than one of USE_MOTIF and USE_OLIT may be defined.
62 #endif
63
64 #ifndef max
65 #define max(x, y) ((x) > (y) ? (x) : (y))
66 #endif
67
68 /* List of all widgets managed by the library. */
69 static widget_info*
70 all_widget_info = NULL;
71
72 #ifdef USE_MOTIF
73 char *lwlib_toolkit_type = "motif";
74 #else
75 char *lwlib_toolkit_type = "lucid";
76 #endif
77 \f/* Forward declarations */
78 static void
79 instantiate_widget_instance (/* widget_instance* instance */);
80
81 void
82 lwlib_memset (address, value, length)
83 char *address;
84 int value;
85 int length;
86 {
87 int i;
88
89 for (i = 0; i < length; i++)
90 address[i] = value;
91 }
92
93 void
94 lwlib_bcopy (from, to, length)
95 char *from;
96 char *to;
97 int length;
98 {
99 int i;
100
101 for (i = 0; i < length; i++)
102 to[i] = from[i];
103 }
104 \f/* utility functions for widget_instance and widget_info */
105 char *
106 safe_strdup (s)
107 char *s;
108 {
109 char *result;
110 if (! s) return 0;
111 result = (char *) malloc (strlen (s) + 1);
112 if (! result)
113 return 0;
114 strcpy (result, s);
115 return result;
116 }
117
118 /* Like strcmp but ignore differences in case. */
119
120 static int
121 my_strcasecmp (s1, s2)
122 char *s1, *s2;
123 {
124 while (1)
125 {
126 int c1 = *s1++;
127 int c2 = *s2++;
128 if (isupper (c1))
129 c1 = tolower (c1);
130 if (isupper (c2))
131 c2 = tolower (c2);
132 if (c1 != c2)
133 return (c1 > c2 ? 1 : -1);
134 if (c1 == 0)
135 return 0;
136 }
137 }
138
139 static void
140 safe_free_str (s)
141 char *s;
142 {
143 if (s) free (s);
144 }
145
146 static widget_value *widget_value_free_list = 0;
147 static int malloc_cpt = 0;
148
149 widget_value *
150 malloc_widget_value ()
151 {
152 widget_value *wv;
153 if (widget_value_free_list)
154 {
155 wv = widget_value_free_list;
156 widget_value_free_list = wv->free_list;
157 wv->free_list = 0;
158 }
159 else
160 {
161 wv = (widget_value *) malloc (sizeof (widget_value));
162 malloc_cpt++;
163 }
164 lwlib_memset (wv, 0, sizeof (widget_value));
165 return wv;
166 }
167
168 /* this is analogous to free(). It frees only what was allocated
169 by malloc_widget_value(), and no substructures.
170 */
171 void
172 free_widget_value (wv)
173 widget_value *wv;
174 {
175 if (wv->free_list)
176 abort ();
177
178 if (malloc_cpt > 25)
179 {
180 /* When the number of already allocated cells is too big,
181 We free it. */
182 free (wv);
183 malloc_cpt--;
184 }
185 else
186 {
187 wv->free_list = widget_value_free_list;
188 widget_value_free_list = wv;
189 }
190 }
191
192 static void
193 free_widget_value_tree (wv)
194 widget_value *wv;
195 {
196 if (!wv)
197 return;
198
199 if (wv->name) free (wv->name);
200 if (wv->value) free (wv->value);
201 if (wv->key) free (wv->key);
202 if (wv->help) free (wv->help);
203
204 wv->name = wv->value = wv->key = wv->help = (char *) 0xDEADBEEF;
205
206 if (wv->toolkit_data && wv->free_toolkit_data)
207 {
208 XtFree (wv->toolkit_data);
209 wv->toolkit_data = (void *) 0xDEADBEEF;
210 }
211
212 if (wv->contents && (wv->contents != (widget_value*)1))
213 {
214 free_widget_value_tree (wv->contents);
215 wv->contents = (widget_value *) 0xDEADBEEF;
216 }
217 if (wv->next)
218 {
219 free_widget_value_tree (wv->next);
220 wv->next = (widget_value *) 0xDEADBEEF;
221 }
222 free_widget_value (wv);
223 }
224
225 static widget_value *
226 copy_widget_value_tree (val, change)
227 widget_value* val;
228 change_type change;
229 {
230 widget_value* copy;
231
232 if (!val)
233 return NULL;
234 if (val == (widget_value *) 1)
235 return val;
236
237 copy = malloc_widget_value ();
238 copy->name = safe_strdup (val->name);
239 copy->value = safe_strdup (val->value);
240 copy->key = safe_strdup (val->key);
241 copy->help = safe_strdup (val->help);
242 copy->enabled = val->enabled;
243 copy->button_type = val->button_type;
244 copy->selected = val->selected;
245 copy->edited = False;
246 copy->change = change;
247 copy->this_one_change = change;
248 copy->contents = copy_widget_value_tree (val->contents, change);
249 copy->call_data = val->call_data;
250 copy->next = copy_widget_value_tree (val->next, change);
251 copy->toolkit_data = NULL;
252 copy->free_toolkit_data = False;
253 return copy;
254 }
255
256 static widget_info *
257 allocate_widget_info (type, name, id, val, pre_activate_cb,
258 selection_cb, post_activate_cb, highlight_cb)
259 char* type;
260 char* name;
261 LWLIB_ID id;
262 widget_value* val;
263 lw_callback pre_activate_cb;
264 lw_callback selection_cb;
265 lw_callback post_activate_cb;
266 lw_callback highlight_cb;
267 {
268 widget_info* info = (widget_info*)malloc (sizeof (widget_info));
269 info->type = safe_strdup (type);
270 info->name = safe_strdup (name);
271 info->id = id;
272 info->val = copy_widget_value_tree (val, STRUCTURAL_CHANGE);
273 info->busy = False;
274 info->pre_activate_cb = pre_activate_cb;
275 info->selection_cb = selection_cb;
276 info->post_activate_cb = post_activate_cb;
277 info->highlight_cb = highlight_cb;
278 info->instances = NULL;
279
280 info->next = all_widget_info;
281 all_widget_info = info;
282
283 return info;
284 }
285
286 static void
287 free_widget_info (info)
288 widget_info* info;
289 {
290 safe_free_str (info->type);
291 safe_free_str (info->name);
292 free_widget_value_tree (info->val);
293 lwlib_memset ((void*)info, 0xDEADBEEF, sizeof (widget_info));
294 free (info);
295 }
296
297 static void
298 mark_widget_destroyed (widget, closure, call_data)
299 Widget widget;
300 XtPointer closure;
301 XtPointer call_data;
302 {
303 widget_instance* instance = (widget_instance*)closure;
304
305 /* be very conservative */
306 if (instance->widget == widget)
307 instance->widget = NULL;
308 }
309
310 static widget_instance *
311 allocate_widget_instance (info, parent, pop_up_p)
312 widget_info* info;
313 Widget parent;
314 Boolean pop_up_p;
315 {
316 widget_instance* instance =
317 (widget_instance*)malloc (sizeof (widget_instance));
318 bzero (instance, sizeof *instance);
319 instance->parent = parent;
320 instance->pop_up_p = pop_up_p;
321 instance->info = info;
322 instance->next = info->instances;
323 info->instances = instance;
324
325 instantiate_widget_instance (instance);
326
327 XtAddCallback (instance->widget, XtNdestroyCallback,
328 mark_widget_destroyed, (XtPointer)instance);
329 return instance;
330 }
331
332 static void
333 free_widget_instance (instance)
334 widget_instance* instance;
335 {
336 lwlib_memset ((void*)instance, 0xDEADBEEF, sizeof (widget_instance));
337 free (instance);
338 }
339
340 static widget_info *
341 get_widget_info (id, remove_p)
342 LWLIB_ID id;
343 Boolean remove_p;
344 {
345 widget_info* info;
346 widget_info* prev;
347 for (prev = NULL, info = all_widget_info;
348 info;
349 prev = info, info = info->next)
350 if (info->id == id)
351 {
352 if (remove_p)
353 {
354 if (prev)
355 prev->next = info->next;
356 else
357 all_widget_info = info->next;
358 }
359 return info;
360 }
361 return NULL;
362 }
363
364 /* Internal function used by the library dependent implementation to get the
365 widget_value for a given widget in an instance */
366 widget_info *
367 lw_get_widget_info (id)
368 LWLIB_ID id;
369 {
370 return get_widget_info (id, 0);
371 }
372
373 static widget_instance *
374 get_widget_instance (widget, remove_p)
375 Widget widget;
376 Boolean remove_p;
377 {
378 widget_info* info;
379 widget_instance* instance;
380 widget_instance* prev;
381 for (info = all_widget_info; info; info = info->next)
382 for (prev = NULL, instance = info->instances;
383 instance;
384 prev = instance, instance = instance->next)
385 if (instance->widget == widget)
386 {
387 if (remove_p)
388 {
389 if (prev)
390 prev->next = instance->next;
391 else
392 info->instances = instance->next;
393 }
394 return instance;
395 }
396 return (widget_instance *) 0;
397 }
398
399 /* Value is a pointer to the widget_instance corresponding to
400 WIDGET, or null if WIDGET is not a lwlib widget. */
401
402 widget_instance *
403 lw_get_widget_instance (widget)
404 Widget widget;
405 {
406 return get_widget_instance (widget, False);
407 }
408
409 static widget_instance*
410 find_instance (id, parent, pop_up_p)
411 LWLIB_ID id;
412 Widget parent;
413 Boolean pop_up_p;
414 {
415 widget_info* info = get_widget_info (id, False);
416 widget_instance* instance;
417
418 if (info)
419 for (instance = info->instances; instance; instance = instance->next)
420 if (instance->parent == parent && instance->pop_up_p == pop_up_p)
421 return instance;
422
423 return NULL;
424 }
425
426 \f
427 /* utility function for widget_value */
428 static Boolean
429 safe_strcmp (s1, s2)
430 char* s1;
431 char* s2;
432 {
433 if (!!s1 ^ !!s2) return True;
434 return (s1 && s2) ? strcmp (s1, s2) : s1 ? False : !!s2;
435 }
436
437
438 #if 0
439 # define EXPLAIN(name, oc, nc, desc, a1, a2) \
440 printf ("Change: \"%s\"\tmax(%s=%d,%s=%d)\t%s %d %d\n", \
441 name, \
442 (oc == NO_CHANGE ? "none" : \
443 (oc == INVISIBLE_CHANGE ? "invisible" : \
444 (oc == VISIBLE_CHANGE ? "visible" : \
445 (oc == STRUCTURAL_CHANGE ? "structural" : "???")))), \
446 oc, \
447 (nc == NO_CHANGE ? "none" : \
448 (nc == INVISIBLE_CHANGE ? "invisible" : \
449 (nc == VISIBLE_CHANGE ? "visible" : \
450 (nc == STRUCTURAL_CHANGE ? "structural" : "???")))), \
451 nc, desc, a1, a2)
452 #else
453 # define EXPLAIN(name, oc, nc, desc, a1, a2)
454 #endif
455
456
457 static widget_value *
458 merge_widget_value (val1, val2, level)
459 widget_value* val1;
460 widget_value* val2;
461 int level;
462 {
463 change_type change, this_one_change;
464 widget_value* merged_next;
465 widget_value* merged_contents;
466
467 if (!val1)
468 {
469 if (val2)
470 return copy_widget_value_tree (val2, STRUCTURAL_CHANGE);
471 else
472 return NULL;
473 }
474 if (!val2)
475 {
476 free_widget_value_tree (val1);
477 return NULL;
478 }
479
480 change = NO_CHANGE;
481
482 if (safe_strcmp (val1->name, val2->name))
483 {
484 EXPLAIN (val1->name, change, STRUCTURAL_CHANGE, "name change",
485 val1->name, val2->name);
486 change = max (change, STRUCTURAL_CHANGE);
487 safe_free_str (val1->name);
488 val1->name = safe_strdup (val2->name);
489 }
490 if (safe_strcmp (val1->value, val2->value))
491 {
492 EXPLAIN (val1->name, change, VISIBLE_CHANGE, "value change",
493 val1->value, val2->value);
494 change = max (change, VISIBLE_CHANGE);
495 safe_free_str (val1->value);
496 val1->value = safe_strdup (val2->value);
497 }
498 if (safe_strcmp (val1->key, val2->key))
499 {
500 EXPLAIN (val1->name, change, VISIBLE_CHANGE, "key change",
501 val1->key, val2->key);
502 change = max (change, VISIBLE_CHANGE);
503 safe_free_str (val1->key);
504 val1->key = safe_strdup (val2->key);
505 }
506 if (safe_strcmp (val1->help, val2->help))
507 {
508 EXPLAIN (val1->name, change, VISIBLE_CHANGE, "help change",
509 val1->help, val2->help);
510 change = max (change, VISIBLE_CHANGE);
511 safe_free_str (val1->help);
512 val1->key = safe_strdup (val2->help);
513 }
514 if (val1->enabled != val2->enabled)
515 {
516 EXPLAIN (val1->name, change, VISIBLE_CHANGE, "enablement change",
517 val1->enabled, val2->enabled);
518 change = max (change, VISIBLE_CHANGE);
519 val1->enabled = val2->enabled;
520 }
521 if (val1->button_type != val2->button_type)
522 {
523 EXPLAIN (val1->name, change, VISIBLE_CHANGE, "button type change",
524 val1->button_type, val2->button_type);
525 change = max (change, VISIBLE_CHANGE);
526 val1->button_type = val2->button_type;
527 }
528 if (val1->selected != val2->selected)
529 {
530 EXPLAIN (val1->name, change, VISIBLE_CHANGE, "selection change",
531 val1->selected, val2->selected);
532 change = max (change, VISIBLE_CHANGE);
533 val1->selected = val2->selected;
534 }
535 if (val1->call_data != val2->call_data)
536 {
537 EXPLAIN (val1->name, change, INVISIBLE_CHANGE, "call-data change",
538 val1->call_data, val2->call_data);
539 change = max (change, INVISIBLE_CHANGE);
540 val1->call_data = val2->call_data;
541 }
542
543 if (level > 0)
544 {
545 merged_contents =
546 merge_widget_value (val1->contents, val2->contents, level - 1);
547
548 if (val1->contents && !merged_contents)
549 {
550 /* This used to say INVISIBLE_CHANGE,
551 but it is visible and vitally important when
552 the contents of the menu bar itself are entirely deleted.
553
554 But maybe it doesn't matter. This fails to fix the bug. */
555 EXPLAIN (val1->name, change, STRUCTURAL_CHANGE, "(contents gone)",
556 0, 0);
557 change = max (change, STRUCTURAL_CHANGE);
558 }
559 else if (merged_contents && merged_contents->change != NO_CHANGE)
560 {
561 EXPLAIN (val1->name, change, INVISIBLE_CHANGE, "(contents change)",
562 0, 0);
563 change = max (change, INVISIBLE_CHANGE);
564 #if 0 /* This was replaced by the August 9 1996 change in lwlib-Xm.c. */
565 #ifdef USE_MOTIF
566 change = max (merged_contents->change, change);
567 #endif
568 #endif
569 }
570
571 val1->contents = merged_contents;
572 }
573
574 this_one_change = change;
575
576 merged_next = merge_widget_value (val1->next, val2->next, level);
577
578 if (val1->next && !merged_next)
579 {
580 EXPLAIN (val1->name, change, STRUCTURAL_CHANGE, "(following gone)",
581 0, 0);
582 change = max (change, STRUCTURAL_CHANGE);
583 }
584 else if (merged_next)
585 {
586 if (merged_next->change)
587 EXPLAIN (val1->name, change, merged_next->change, "(following change)",
588 0, 0);
589 change = max (change, merged_next->change);
590 }
591
592 val1->next = merged_next;
593
594 val1->this_one_change = this_one_change;
595 val1->change = change;
596
597 if (change > NO_CHANGE && val1->toolkit_data)
598 {
599 if (val1->free_toolkit_data)
600 XtFree (val1->toolkit_data);
601 val1->toolkit_data = NULL;
602 }
603
604 return val1;
605 }
606
607 \f
608 /* modifying the widgets */
609 static Widget
610 name_to_widget (instance, name)
611 widget_instance* instance;
612 char* name;
613 {
614 Widget widget = NULL;
615
616 if (!instance->widget)
617 return NULL;
618
619 if (!strcmp (XtName (instance->widget), name))
620 widget = instance->widget;
621 else
622 {
623 int length = strlen (name) + 2;
624 char* real_name = (char *) xmalloc (length);
625 real_name [0] = '*';
626 strcpy (real_name + 1, name);
627
628 widget = XtNameToWidget (instance->widget, real_name);
629
630 free (real_name);
631 }
632 return widget;
633 }
634
635 static void
636 set_one_value (instance, val, deep_p)
637 widget_instance* instance;
638 widget_value* val;
639 Boolean deep_p;
640 {
641 Widget widget = name_to_widget (instance, val->name);
642
643 if (widget)
644 {
645 #if defined (USE_LUCID)
646 if (lw_lucid_widget_p (instance->widget))
647 xlw_update_one_widget (instance, widget, val, deep_p);
648 #endif
649 #if defined (USE_MOTIF)
650 if (lw_motif_widget_p (instance->widget))
651 xm_update_one_widget (instance, widget, val, deep_p);
652 #endif
653 #if defined (USE_OLIT)
654 if (lw_olit_widget_p (instance->widget))
655 xol_update_one_widget (instance, widget, val, deep_p);
656 #endif
657 #if defined (USE_XAW)
658 if (lw_xaw_widget_p (instance->widget))
659 xaw_update_one_widget (instance, widget, val, deep_p);
660 #endif
661 }
662 }
663
664 static void
665 update_one_widget_instance (instance, deep_p)
666 widget_instance* instance;
667 Boolean deep_p;
668 {
669 widget_value *val;
670
671 if (!instance->widget)
672 /* the widget was destroyed */
673 return;
674
675 for (val = instance->info->val; val; val = val->next)
676 if (val->change != NO_CHANGE)
677 set_one_value (instance, val, deep_p);
678 }
679
680 static void
681 update_all_widget_values (info, deep_p)
682 widget_info* info;
683 Boolean deep_p;
684 {
685 widget_instance* instance;
686 widget_value* val;
687
688 for (instance = info->instances; instance; instance = instance->next)
689 update_one_widget_instance (instance, deep_p);
690
691 for (val = info->val; val; val = val->next)
692 val->change = NO_CHANGE;
693 }
694
695 void
696 lw_modify_all_widgets (id, val, deep_p)
697 LWLIB_ID id;
698 widget_value* val;
699 Boolean deep_p;
700 {
701 widget_info* info = get_widget_info (id, False);
702 widget_value* new_val;
703 widget_value* next_new_val;
704 widget_value* cur;
705 widget_value* prev;
706 widget_value* next;
707 int found;
708
709 if (!info)
710 return;
711
712 for (new_val = val; new_val; new_val = new_val->next)
713 {
714 next_new_val = new_val->next;
715 new_val->next = NULL;
716 found = False;
717 for (prev = NULL, cur = info->val; cur; prev = cur, cur = cur->next)
718 if (!strcmp (cur->name, new_val->name))
719 {
720 found = True;
721 next = cur->next;
722 cur->next = NULL;
723 cur = merge_widget_value (cur, new_val, deep_p ? 1000 : 1);
724 if (prev)
725 prev->next = cur ? cur : next;
726 else
727 info->val = cur ? cur : next;
728 if (cur)
729 cur->next = next;
730 break;
731 }
732 if (!found)
733 {
734 /* Could not find it, add it */
735 if (prev)
736 prev->next = copy_widget_value_tree (new_val, STRUCTURAL_CHANGE);
737 else
738 info->val = copy_widget_value_tree (new_val, STRUCTURAL_CHANGE);
739 }
740 new_val->next = next_new_val;
741 }
742
743 update_all_widget_values (info, deep_p);
744 }
745
746 \f
747 /* creating the widgets */
748
749 static void
750 initialize_widget_instance (instance)
751 widget_instance* instance;
752 {
753 widget_value* val;
754
755 for (val = instance->info->val; val; val = val->next)
756 val->change = STRUCTURAL_CHANGE;
757
758 update_one_widget_instance (instance, True);
759
760 for (val = instance->info->val; val; val = val->next)
761 val->change = NO_CHANGE;
762 }
763
764
765 static widget_creation_function
766 find_in_table (type, table)
767 char* type;
768 widget_creation_entry* table;
769 {
770 widget_creation_entry* cur;
771 for (cur = table; cur->type; cur++)
772 if (!my_strcasecmp (type, cur->type))
773 return cur->function;
774 return NULL;
775 }
776
777 static Boolean
778 dialog_spec_p (name)
779 char* name;
780 {
781 /* return True if name matches [EILPQeilpq][1-9][Bb] or
782 [EILPQeilpq][1-9][Bb][Rr][1-9] */
783 if (!name)
784 return False;
785
786 switch (name [0])
787 {
788 case 'E': case 'I': case 'L': case 'P': case 'Q':
789 case 'e': case 'i': case 'l': case 'p': case 'q':
790 if (name [1] >= '0' && name [1] <= '9')
791 {
792 if (name [2] != 'B' && name [2] != 'b')
793 return False;
794 if (!name [3])
795 return True;
796 if ((name [3] == 'T' || name [3] == 't') && !name [4])
797 return True;
798 if ((name [3] == 'R' || name [3] == 'r')
799 && name [4] >= '0' && name [4] <= '9' && !name [5])
800 return True;
801 return False;
802 }
803 else
804 return False;
805
806 default:
807 return False;
808 }
809 }
810
811 static void
812 instantiate_widget_instance (instance)
813 widget_instance* instance;
814 {
815 widget_creation_function function = NULL;
816
817 #if defined (USE_LUCID)
818 if (!function)
819 function = find_in_table (instance->info->type, xlw_creation_table);
820 #endif
821 #if defined(USE_MOTIF)
822 if (!function)
823 function = find_in_table (instance->info->type, xm_creation_table);
824 #endif
825 #if defined (USE_OLIT)
826 if (!function)
827 function = find_in_table (instance->info->type, xol_creation_table);
828 #endif
829 #if defined (USE_XAW)
830 if (!function)
831 function = find_in_table (instance->info->type, xaw_creation_table);
832 #endif
833
834 if (!function)
835 {
836 if (dialog_spec_p (instance->info->type))
837 {
838 #if defined (USE_LUCID)
839 /* not yet */
840 #endif
841 #if defined(USE_MOTIF)
842 if (!function)
843 function = xm_create_dialog;
844 #endif
845 #if defined (USE_XAW)
846 if (!function)
847 function = xaw_create_dialog;
848 #endif
849 #if defined (USE_OLIT)
850 /* not yet */
851 #endif
852 }
853 }
854
855 if (!function)
856 {
857 printf ("No creation function for widget type %s\n",
858 instance->info->type);
859 abort ();
860 }
861
862 instance->widget = (*function) (instance);
863
864 if (!instance->widget)
865 abort ();
866
867 /* XtRealizeWidget (instance->widget);*/
868 }
869
870 void
871 lw_register_widget (type, name, id, val, pre_activate_cb,
872 selection_cb, post_activate_cb, highlight_cb)
873 char* type;
874 char* name;
875 LWLIB_ID id;
876 widget_value* val;
877 lw_callback pre_activate_cb;
878 lw_callback selection_cb;
879 lw_callback post_activate_cb;
880 lw_callback highlight_cb;
881 {
882 if (!get_widget_info (id, False))
883 allocate_widget_info (type, name, id, val, pre_activate_cb, selection_cb,
884 post_activate_cb, highlight_cb);
885 }
886
887 Widget
888 lw_get_widget (id, parent, pop_up_p)
889 LWLIB_ID id;
890 Widget parent;
891 Boolean pop_up_p;
892 {
893 widget_instance* instance;
894
895 instance = find_instance (id, parent, pop_up_p);
896 return instance ? instance->widget : NULL;
897 }
898
899 Widget
900 lw_make_widget (id, parent, pop_up_p)
901 LWLIB_ID id;
902 Widget parent;
903 Boolean pop_up_p;
904 {
905 widget_instance* instance;
906 widget_info* info;
907
908 instance = find_instance (id, parent, pop_up_p);
909 if (!instance)
910 {
911 info = get_widget_info (id, False);
912 if (!info)
913 return NULL;
914 instance = allocate_widget_instance (info, parent, pop_up_p);
915 initialize_widget_instance (instance);
916 }
917 if (!instance->widget)
918 abort ();
919 return instance->widget;
920 }
921
922 Widget
923 lw_create_widget (type, name, id, val, parent, pop_up_p, pre_activate_cb,
924 selection_cb, post_activate_cb, highlight_cb)
925 char* type;
926 char* name;
927 LWLIB_ID id;
928 widget_value* val;
929 Widget parent;
930 Boolean pop_up_p;
931 lw_callback pre_activate_cb;
932 lw_callback selection_cb;
933 lw_callback post_activate_cb;
934 lw_callback highlight_cb;
935 {
936 lw_register_widget (type, name, id, val, pre_activate_cb, selection_cb,
937 post_activate_cb, highlight_cb);
938 return lw_make_widget (id, parent, pop_up_p);
939 }
940
941 \f
942 /* destroying the widgets */
943 static void
944 destroy_one_instance (instance)
945 widget_instance* instance;
946 {
947 /* Remove the destroy callback on the widget; that callback will try to
948 dereference the instance object (to set its widget slot to 0, since the
949 widget is dead.) Since the instance is now dead, we don't have to worry
950 about the fact that its widget is dead too.
951
952 This happens in the Phase2Destroy of the widget, so this callback would
953 not have been run until arbitrarily long after the instance was freed.
954 */
955 if (instance->widget)
956 XtRemoveCallback (instance->widget, XtNdestroyCallback,
957 mark_widget_destroyed, (XtPointer)instance);
958
959 if (instance->widget)
960 {
961 /* The else are pretty tricky here, including the empty statement
962 at the end because it would be very bad to destroy a widget
963 twice. */
964 #if defined (USE_LUCID)
965 if (lw_lucid_widget_p (instance->widget))
966 xlw_destroy_instance (instance);
967 else
968 #endif
969 #if defined (USE_MOTIF)
970 if (lw_motif_widget_p (instance->widget))
971 xm_destroy_instance (instance);
972 else
973 #endif
974 #if defined (USE_OLIT)
975 if (lw_olit_widget_p (instance->widget))
976 xol_destroy_instance (instance);
977 else
978 #endif
979 #if defined (USE_XAW)
980 if (lw_xaw_widget_p (instance->widget))
981 xaw_destroy_instance (instance);
982 else
983 #endif
984 /* do not remove the empty statement */
985 ;
986 }
987
988 free_widget_instance (instance);
989 }
990
991 void
992 lw_destroy_widget (w)
993 Widget w;
994 {
995 widget_instance* instance = get_widget_instance (w, True);
996
997 if (instance)
998 {
999 widget_info *info = instance->info;
1000 /* instance has already been removed from the list; free it */
1001 destroy_one_instance (instance);
1002 /* if there are no instances left, free the info too */
1003 if (!info->instances)
1004 lw_destroy_all_widgets (info->id);
1005 }
1006 }
1007
1008 void
1009 lw_destroy_all_widgets (id)
1010 LWLIB_ID id;
1011 {
1012 widget_info* info = get_widget_info (id, True);
1013 widget_instance* instance;
1014 widget_instance* next;
1015
1016 if (info)
1017 {
1018 for (instance = info->instances; instance; )
1019 {
1020 next = instance->next;
1021 destroy_one_instance (instance);
1022 instance = next;
1023 }
1024 free_widget_info (info);
1025 }
1026 }
1027
1028 void
1029 lw_destroy_everything ()
1030 {
1031 while (all_widget_info)
1032 lw_destroy_all_widgets (all_widget_info->id);
1033 }
1034
1035 void
1036 lw_destroy_all_pop_ups ()
1037 {
1038 widget_info* info;
1039 widget_info* next;
1040 widget_instance* instance;
1041
1042 for (info = all_widget_info; info; info = next)
1043 {
1044 next = info->next;
1045 instance = info->instances;
1046 if (instance && instance->pop_up_p)
1047 lw_destroy_all_widgets (info->id);
1048 }
1049 }
1050
1051 #ifdef USE_MOTIF
1052 extern Widget first_child (/* Widget */); /* garbage */
1053 #endif
1054
1055 Widget
1056 lw_raise_all_pop_up_widgets ()
1057 {
1058 widget_info* info;
1059 widget_instance* instance;
1060 Widget result = NULL;
1061
1062 for (info = all_widget_info; info; info = info->next)
1063 for (instance = info->instances; instance; instance = instance->next)
1064 if (instance->pop_up_p)
1065 {
1066 Widget widget = instance->widget;
1067 if (widget)
1068 {
1069 if (XtIsManaged (widget)
1070 #ifdef USE_MOTIF
1071 /* What a complete load of crap!!!!
1072 When a dialogShell is on the screen, it is not managed!
1073 */
1074 || (lw_motif_widget_p (instance->widget) &&
1075 XtIsManaged (first_child (widget)))
1076 #endif
1077 )
1078 {
1079 if (!result)
1080 result = widget;
1081 XMapRaised (XtDisplay (widget), XtWindow (widget));
1082 }
1083 }
1084 }
1085 return result;
1086 }
1087
1088 static void
1089 lw_pop_all_widgets (id, up)
1090 LWLIB_ID id;
1091 Boolean up;
1092 {
1093 widget_info* info = get_widget_info (id, False);
1094 widget_instance* instance;
1095
1096 if (info)
1097 for (instance = info->instances; instance; instance = instance->next)
1098 if (instance->pop_up_p && instance->widget)
1099 {
1100 #if defined (USE_LUCID)
1101 if (lw_lucid_widget_p (instance->widget))
1102 {
1103 XtRealizeWidget (instance->widget);
1104 xlw_pop_instance (instance, up);
1105 }
1106 #endif
1107 #if defined (USE_MOTIF)
1108 if (lw_motif_widget_p (instance->widget))
1109 {
1110 XtRealizeWidget (instance->widget);
1111 xm_pop_instance (instance, up);
1112 }
1113 #endif
1114 #if defined (USE_OLIT)
1115 if (lw_olit_widget_p (instance->widget))
1116 {
1117 XtRealizeWidget (instance->widget);
1118 xol_pop_instance (instance, up);
1119 }
1120 #endif
1121 #if defined (USE_XAW)
1122 if (lw_xaw_widget_p (instance->widget))
1123 {
1124 XtRealizeWidget (XtParent (instance->widget));
1125 XtRealizeWidget (instance->widget);
1126 xaw_pop_instance (instance, up);
1127 }
1128 #endif
1129 }
1130 }
1131
1132 void
1133 lw_pop_up_all_widgets (id)
1134 LWLIB_ID id;
1135 {
1136 lw_pop_all_widgets (id, True);
1137 }
1138
1139 void
1140 lw_pop_down_all_widgets (id)
1141 LWLIB_ID id;
1142 {
1143 lw_pop_all_widgets (id, False);
1144 }
1145
1146 void
1147 lw_popup_menu (widget, event)
1148 Widget widget;
1149 XEvent *event;
1150 {
1151 #if defined (USE_LUCID)
1152 if (lw_lucid_widget_p (widget))
1153 xlw_popup_menu (widget, event);
1154 #endif
1155 #if defined (USE_MOTIF)
1156 if (lw_motif_widget_p (widget))
1157 xm_popup_menu (widget, event);
1158 #endif
1159 #if defined (USE_OLIT)
1160 if (lw_olit_widget_p (widget))
1161 xol_popup_menu (widget, event);
1162 #endif
1163 #if defined (USE_XAW)
1164 if (lw_xaw_widget_p (widget))
1165 xaw_popup_menu (widget, event);
1166 #endif
1167 }
1168
1169 \f/* get the values back */
1170 static Boolean
1171 get_one_value (instance, val)
1172 widget_instance* instance;
1173 widget_value* val;
1174 {
1175 Widget widget = name_to_widget (instance, val->name);
1176
1177 if (widget)
1178 {
1179 #if defined (USE_LUCID)
1180 if (lw_lucid_widget_p (instance->widget))
1181 xlw_update_one_value (instance, widget, val);
1182 #endif
1183 #if defined (USE_MOTIF)
1184 if (lw_motif_widget_p (instance->widget))
1185 xm_update_one_value (instance, widget, val);
1186 #endif
1187 #if defined (USE_OLIT)
1188 if (lw_olit_widget_p (instance->widget))
1189 xol_update_one_value (instance, widget, val);
1190 #endif
1191 #if defined (USE_XAW)
1192 if (lw_xaw_widget_p (instance->widget))
1193 xaw_update_one_value (instance, widget, val);
1194 #endif
1195 return True;
1196 }
1197 else
1198 return False;
1199 }
1200
1201 Boolean
1202 lw_get_some_values (id, val_out)
1203 LWLIB_ID id;
1204 widget_value* val_out;
1205 {
1206 widget_info* info = get_widget_info (id, False);
1207 widget_instance* instance;
1208 widget_value* val;
1209 Boolean result = False;
1210
1211 if (!info)
1212 return False;
1213
1214 instance = info->instances;
1215 if (!instance)
1216 return False;
1217
1218 for (val = val_out; val; val = val->next)
1219 if (get_one_value (instance, val))
1220 result = True;
1221
1222 return result;
1223 }
1224
1225 widget_value*
1226 lw_get_all_values (id)
1227 LWLIB_ID id;
1228 {
1229 widget_info* info = get_widget_info (id, False);
1230 widget_value* val = info->val;
1231 if (lw_get_some_values (id, val))
1232 return val;
1233 else
1234 return NULL;
1235 }
1236
1237 /* internal function used by the library dependent implementation to get the
1238 widget_value for a given widget in an instance */
1239 widget_value*
1240 lw_get_widget_value_for_widget (instance, w)
1241 widget_instance* instance;
1242 Widget w;
1243 {
1244 char* name = XtName (w);
1245 widget_value* cur;
1246 for (cur = instance->info->val; cur; cur = cur->next)
1247 if (!strcmp (cur->name, name))
1248 return cur;
1249 return NULL;
1250 }
1251
1252 \f/* update other instances value when one thing changed */
1253
1254 /* To forbid recursive calls */
1255 static Boolean lwlib_updating;
1256
1257 /* This function can be used as a an XtCallback for the widgets that get
1258 modified to update other instances of the widgets. Closure should be the
1259 widget_instance. */
1260 void
1261 lw_internal_update_other_instances (widget, closure, call_data)
1262 Widget widget;
1263 XtPointer closure;
1264 XtPointer call_data;
1265 {
1266 widget_instance* instance = (widget_instance*)closure;
1267 char* name = XtName (widget);
1268 widget_info* info;
1269 widget_instance* cur;
1270 widget_value* val;
1271
1272 /* Avoid possibly infinite recursion. */
1273 if (lwlib_updating)
1274 return;
1275
1276 /* protect against the widget being destroyed */
1277 if (XtWidgetBeingDestroyedP (widget))
1278 return;
1279
1280 /* Return immediately if there are no other instances */
1281 info = instance->info;
1282 if (!info->instances->next)
1283 return;
1284
1285 lwlib_updating = True;
1286
1287 for (val = info->val; val && strcmp (val->name, name); val = val->next);
1288
1289 if (val && get_one_value (instance, val))
1290 for (cur = info->instances; cur; cur = cur->next)
1291 if (cur != instance)
1292 set_one_value (cur, val, True);
1293
1294 lwlib_updating = False;
1295 }
1296
1297
1298 \f/* get the id */
1299
1300 LWLIB_ID
1301 lw_get_widget_id (w)
1302 Widget w;
1303 {
1304 widget_instance* instance = get_widget_instance (w, False);
1305
1306 return instance ? instance->info->id : 0;
1307 }
1308
1309 \f/* set the keyboard focus */
1310 void
1311 lw_set_keyboard_focus (parent, w)
1312 Widget parent;
1313 Widget w;
1314 {
1315 #if defined (USE_MOTIF)
1316 xm_set_keyboard_focus (parent, w);
1317 #else
1318 XtSetKeyboardFocus (parent, w);
1319 #endif
1320 }
1321
1322 \f/* Show busy */
1323 static void
1324 show_one_widget_busy (w, flag)
1325 Widget w;
1326 Boolean flag;
1327 {
1328 Pixel foreground = 0;
1329 Pixel background = 1;
1330 Widget widget_to_invert = XtNameToWidget (w, "*sheet");
1331 if (!widget_to_invert)
1332 widget_to_invert = w;
1333
1334 XtVaGetValues (widget_to_invert,
1335 XtNforeground, &foreground,
1336 XtNbackground, &background,
1337 0);
1338 XtVaSetValues (widget_to_invert,
1339 XtNforeground, background,
1340 XtNbackground, foreground,
1341 0);
1342 }
1343
1344 void
1345 lw_show_busy (w, busy)
1346 Widget w;
1347 Boolean busy;
1348 {
1349 widget_instance* instance = get_widget_instance (w, False);
1350 widget_info* info;
1351 widget_instance* next;
1352
1353 if (instance)
1354 {
1355 info = instance->info;
1356 if (info->busy != busy)
1357 {
1358 for (next = info->instances; next; next = next->next)
1359 if (next->widget)
1360 show_one_widget_busy (next->widget, busy);
1361 info->busy = busy;
1362 }
1363 }
1364 }
1365
1366 /* This hack exists because Lucid/Athena need to execute the strange
1367 function below to support geometry management. */
1368 void
1369 lw_refigure_widget (w, doit)
1370 Widget w;
1371 Boolean doit;
1372 {
1373 #if defined (USE_XAW)
1374 XawPanedSetRefigureMode (w, doit);
1375 #endif
1376 #if defined (USE_MOTIF)
1377 if (doit)
1378 XtManageChild (w);
1379 else
1380 XtUnmanageChild (w);
1381 #endif
1382 }
1383
1384 /* Toolkit independent way of determining if an event window is in the
1385 menubar. */
1386 Boolean
1387 lw_window_is_in_menubar (win, menubar_widget)
1388 Window win;
1389 Widget menubar_widget;
1390 {
1391 return menubar_widget
1392 #if defined (USE_LUCID)
1393 && XtWindow (menubar_widget) == win;
1394 #endif
1395 #if defined (USE_MOTIF)
1396 && ((XtWindow (menubar_widget) == win)
1397 || (XtWindowToWidget (XtDisplay (menubar_widget), win)
1398 && (XtParent (XtWindowToWidget (XtDisplay (menubar_widget), win))
1399 == menubar_widget)));
1400 #endif
1401 }
1402
1403 /* Motif hack to set the main window areas. */
1404 void
1405 lw_set_main_areas (parent, menubar, work_area)
1406 Widget parent;
1407 Widget menubar;
1408 Widget work_area;
1409 {
1410 #if defined (USE_MOTIF)
1411 xm_set_main_areas (parent, menubar, work_area);
1412 #endif
1413 }
1414
1415 /* Manage resizing for Motif. This disables resizing when the menubar
1416 is about to be modified. */
1417 void
1418 lw_allow_resizing (w, flag)
1419 Widget w;
1420 Boolean flag;
1421 {
1422 #if defined (USE_MOTIF)
1423 xm_manage_resizing (w, flag);
1424 #endif
1425 }
1426
1427
1428 /* Value is non-zero if LABEL is a menu separator. If it is, *TYPE is
1429 set to an appropriate enumerator of type enum menu_separator.
1430 MOTIF_P non-zero means map separator types not supported by Motif
1431 to similar ones that are supported. */
1432
1433 int
1434 lw_separator_p (label, type, motif_p)
1435 char *label;
1436 enum menu_separator *type;
1437 int motif_p;
1438 {
1439 int separator_p;
1440
1441 if (strlen (label) >= 3
1442 && bcmp (label, "--:", 3) == 0)
1443 {
1444 static struct separator_table
1445 {
1446 char *name;
1447 enum menu_separator type;
1448 }
1449 separator_names[] =
1450 {
1451 "space", SEPARATOR_NO_LINE,
1452 "noLine", SEPARATOR_NO_LINE,
1453 "singleLine", SEPARATOR_SINGLE_LINE,
1454 "doubleLine", SEPARATOR_DOUBLE_LINE,
1455 "singleDashedLine", SEPARATOR_SINGLE_DASHED_LINE,
1456 "doubleDashedLine", SEPARATOR_DOUBLE_DASHED_LINE,
1457 "shadowEtchedIn", SEPARATOR_SHADOW_ETCHED_IN,
1458 "shadowEtchedOut", SEPARATOR_SHADOW_ETCHED_OUT,
1459 "shadowEtchedInDash", SEPARATOR_SHADOW_ETCHED_IN_DASH,
1460 "shadowEtchedOutDash", SEPARATOR_SHADOW_ETCHED_OUT_DASH,
1461 "shadowDoubleEtchedIn", SEPARATOR_SHADOW_DOUBLE_ETCHED_IN,
1462 "shadowDoubleEtchedOut", SEPARATOR_SHADOW_DOUBLE_ETCHED_OUT,
1463 "shadowDoubleEtchedInDash", SEPARATOR_SHADOW_DOUBLE_ETCHED_IN_DASH,
1464 "shadowDoubleEtchedOutDash", SEPARATOR_SHADOW_DOUBLE_ETCHED_OUT_DASH,
1465 0
1466 };
1467
1468 int i;
1469
1470 label += 3;
1471 for (i = 0; separator_names[i].name; ++i)
1472 if (strcmp (label, separator_names[i].name) == 0)
1473 {
1474 separator_p = 1;
1475 *type = separator_names[i].type;
1476
1477 /* If separator type is not supported under Motif,
1478 use a similar one. */
1479 if (motif_p && *type >= SEPARATOR_SHADOW_DOUBLE_ETCHED_IN)
1480 *type -= 4;
1481 break;
1482 }
1483 }
1484 else if (strlen (label) > 3
1485 && bcmp (label, "--", 2) == 0
1486 && label[2] != '-')
1487 {
1488 /* Alternative, more Emacs-style names. */
1489 static struct separator_table
1490 {
1491 char *name;
1492 enum menu_separator type;
1493 }
1494 separator_names[] =
1495 {
1496 "space", SEPARATOR_NO_LINE,
1497 "no-line", SEPARATOR_NO_LINE,
1498 "single-line", SEPARATOR_SINGLE_LINE,
1499 "double-line", SEPARATOR_DOUBLE_LINE,
1500 "single-dashed-line", SEPARATOR_SINGLE_DASHED_LINE,
1501 "double-dashed-line", SEPARATOR_DOUBLE_DASHED_LINE,
1502 "shadow-etched-in", SEPARATOR_SHADOW_ETCHED_IN,
1503 "shadow-etched-out", SEPARATOR_SHADOW_ETCHED_OUT,
1504 "shadow-etched-in-dash", SEPARATOR_SHADOW_ETCHED_IN_DASH,
1505 "shadow-etched-out-dash", SEPARATOR_SHADOW_ETCHED_OUT_DASH,
1506 "shadow-double-etched-in", SEPARATOR_SHADOW_DOUBLE_ETCHED_IN,
1507 "shadow-double-etched-out", SEPARATOR_SHADOW_DOUBLE_ETCHED_OUT,
1508 "shadow-double-etched-in-dash", SEPARATOR_SHADOW_DOUBLE_ETCHED_IN_DASH,
1509 "shadow-double-etched-out-dash",SEPARATOR_SHADOW_DOUBLE_ETCHED_OUT_DASH,
1510 0
1511 };
1512
1513 int i;
1514
1515 label += 2;
1516 for (i = 0; separator_names[i].name; ++i)
1517 if (strcmp (label, separator_names[i].name) == 0)
1518 {
1519 separator_p = 1;
1520 *type = separator_names[i].type;
1521
1522 /* If separator type is not supported under Motif,
1523 use a similar one. */
1524 if (motif_p && *type >= SEPARATOR_SHADOW_DOUBLE_ETCHED_IN)
1525 *type -= 4;
1526 break;
1527 }
1528 }
1529 else
1530 {
1531 /* Old-style separator, maybe. It's a separator if it contains
1532 only dashes. */
1533 while (*label == '-')
1534 ++label;
1535 separator_p = *label == 0;
1536 *type = SEPARATOR_SHADOW_ETCHED_IN;
1537 }
1538
1539 return separator_p;
1540 }
1541