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