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