(hs-hide-block): Fix message spelling.
[bpt/emacs.git] / lwlib / lwlib.c
CommitLineData
07bf635f
RS
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
07bf635f 24#include <sys/types.h>
07bf635f 25#include <stdio.h>
5f61736f 26#include <ctype.h>
e7818b5a 27#include "lwlib-int.h"
07bf635f 28#include "lwlib-utils.h"
01492d1b 29#include <X11/StringDefs.h>
07bf635f 30
c7d71315
RS
31#ifdef __osf__
32#include <string.h>
33#include <stdlib.h>
34extern long *xmalloc();
35#endif
36
07bf635f
RS
37#if defined (USE_LUCID)
38#include "lwlib-Xlw.h"
39#endif
40#if defined (USE_MOTIF)
41#include "lwlib-Xm.h"
ce5a08a1
FP
42#else /* not USE_MOTIF */
43#if defined (USE_LUCID)
44#define USE_XAW
45#endif /* not USE_MOTIF && USE_LUCID */
07bf635f
RS
46#endif
47#if defined (USE_OLIT)
48#include "lwlib-Xol.h"
49#endif
9331cca8
FP
50#if defined (USE_XAW)
51#include "lwlib-Xaw.h"
52#endif
07bf635f
RS
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
2af91681
PR
62#ifndef max
63#define max(x, y) ((x) > (y) ? (x) : (y))
64#endif
65
07bf635f
RS
66/* List of all widgets managed by the library. */
67static widget_info*
68all_widget_info = NULL;
69
99dcca2f
KH
70#ifdef USE_MOTIF
71char *lwlib_toolkit_type = "motif";
72#else
73char *lwlib_toolkit_type = "lucid";
74#endif
07bf635f
RS
75\f/* Forward declarations */
76static void
5f61736f 77instanciate_widget_instance (/* widget_instance* instance */);
07bf635f 78
f60044f5
RS
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}
07bf635f 100\f/* utility functions for widget_instance and widget_info */
bb2ee72b 101char *
5f61736f
RS
102safe_strdup (s)
103 char *s;
07bf635f
RS
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
5f61736f
RS
114/* Like strcmp but ignore differences in case. */
115
116static int
ed9c1473 117my_strcasecmp (s1, s2)
5f61736f
RS
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
07bf635f 135static void
5f61736f
RS
136safe_free_str (s)
137 char *s;
07bf635f
RS
138{
139 if (s) free (s);
140}
141
142static widget_value *widget_value_free_list = 0;
0b96f00b 143static int malloc_cpt = 0;
07bf635f
RS
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));
0b96f00b 158 malloc_cpt++;
07bf635f 159 }
f60044f5 160 lwlib_memset (wv, 0, sizeof (widget_value));
07bf635f
RS
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 ();
0b96f00b 173
d2a5919f 174 if (malloc_cpt > 25)
0b96f00b
FP
175 {
176 /* When the number of already allocated cells is too big,
177 We free it. */
0b96f00b 178 free (wv);
d2a5919f 179 malloc_cpt--;
0b96f00b
FP
180 }
181 else
182 {
183 wv->free_list = widget_value_free_list;
184 widget_value_free_list = wv;
185 }
07bf635f
RS
186}
187
188static void
5f61736f
RS
189free_widget_value_tree (wv)
190 widget_value *wv;
07bf635f
RS
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 *
5f61736f
RS
221copy_widget_value_tree (val, change)
222 widget_value* val;
223 change_type change;
07bf635f
RS
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 *
5f61736f
RS
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;
07bf635f
RS
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
5f61736f
RS
276free_widget_info (info)
277 widget_info* info;
07bf635f
RS
278{
279 safe_free_str (info->type);
280 safe_free_str (info->name);
281 free_widget_value_tree (info->val);
f60044f5 282 lwlib_memset ((void*)info, 0xDEADBEEF, sizeof (widget_info));
07bf635f
RS
283 free (info);
284}
285
286static void
5f61736f
RS
287mark_widget_destroyed (widget, closure, call_data)
288 Widget widget;
289 XtPointer closure;
290 XtPointer call_data;
07bf635f
RS
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 *
5f61736f
RS
300allocate_widget_instance (info, parent, pop_up_p)
301 widget_info* info;
302 Widget parent;
303 Boolean pop_up_p;
07bf635f
RS
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
5f61736f
RS
321free_widget_instance (instance)
322 widget_instance* instance;
07bf635f 323{
f60044f5 324 lwlib_memset ((void*)instance, 0xDEADBEEF, sizeof (widget_instance));
07bf635f
RS
325 free (instance);
326}
327
328static widget_info *
5f61736f
RS
329get_widget_info (id, remove_p)
330 LWLIB_ID id;
331 Boolean remove_p;
07bf635f
RS
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
9331cca8
FP
352/* Internal function used by the library dependent implementation to get the
353 widget_value for a given widget in an instance */
354widget_info *
e14e13a4
FP
355lw_get_widget_info (id)
356 LWLIB_ID id;
9331cca8
FP
357{
358 return get_widget_info (id, 0);
359}
360
07bf635f 361static widget_instance *
5f61736f
RS
362get_widget_instance (widget, remove_p)
363 Widget widget;
364 Boolean remove_p;
07bf635f
RS
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*
5f61736f
RS
388find_instance (id, parent, pop_up_p)
389 LWLIB_ID id;
390 Widget parent;
391 Boolean pop_up_p;
07bf635f
RS
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
5f61736f
RS
407safe_strcmp (s1, s2)
408 char* s1;
409 char* s2;
07bf635f
RS
410{
411 if (!!s1 ^ !!s2) return True;
412 return (s1 && s2) ? strcmp (s1, s2) : s1 ? False : !!s2;
413}
414
07bf635f
RS
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 *
5f61736f
RS
436merge_widget_value (val1, val2, level)
437 widget_value* val1;
438 widget_value* val2;
439 int level;
07bf635f
RS
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
5f61736f
RS
560name_to_widget (instance, name)
561 widget_instance* instance;
562 char* name;
07bf635f
RS
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;
f60044f5 574 char* real_name = (char *) xmalloc (length);
07bf635f
RS
575 real_name [0] = '*';
576 strcpy (real_name + 1, name);
577
578 widget = XtNameToWidget (instance->widget, real_name);
f60044f5
RS
579
580 free (real_name);
07bf635f
RS
581 }
582 return widget;
583}
584
585static void
5f61736f
RS
586set_one_value (instance, val, deep_p)
587 widget_instance* instance;
588 widget_value* val;
589 Boolean deep_p;
07bf635f
RS
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);
9331cca8
FP
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);
07bf635f
RS
610#endif
611 }
612}
613
614static void
5f61736f
RS
615update_one_widget_instance (instance, deep_p)
616 widget_instance* instance;
617 Boolean deep_p;
07bf635f
RS
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
5f61736f
RS
631update_all_widget_values (info, deep_p)
632 widget_info* info;
633 Boolean deep_p;
07bf635f
RS
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
5f61736f
RS
646lw_modify_all_widgets (id, val, deep_p)
647 LWLIB_ID id;
648 widget_value* val;
649 Boolean deep_p;
07bf635f
RS
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
5f61736f
RS
700initialize_widget_instance (instance)
701 widget_instance* instance;
07bf635f
RS
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
5f61736f
RS
716find_in_table (type, table)
717 char* type;
718 widget_creation_entry* table;
07bf635f
RS
719{
720 widget_creation_entry* cur;
721 for (cur = table; cur->type; cur++)
ed9c1473 722 if (!my_strcasecmp (type, cur->type))
07bf635f
RS
723 return cur->function;
724 return NULL;
725}
726
727static Boolean
5f61736f
RS
728dialog_spec_p (name)
729 char* name;
07bf635f
RS
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
5f61736f
RS
762instanciate_widget_instance (instance)
763 widget_instance* instance;
07bf635f
RS
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
9331cca8
FP
779#if defined (USE_XAW)
780 if (!function)
781 function = find_in_table (instance->info->type, xaw_creation_table);
782#endif
07bf635f
RS
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
9331cca8
FP
795#if defined (USE_XAW)
796 if (!function)
797 function = xaw_create_dialog;
798#endif
07bf635f
RS
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
5f61736f
RS
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;
07bf635f
RS
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
5f61736f
RS
836lw_get_widget (id, parent, pop_up_p)
837 LWLIB_ID id;
838 Widget parent;
839 Boolean pop_up_p;
07bf635f
RS
840{
841 widget_instance* instance;
842
843 instance = find_instance (id, parent, pop_up_p);
844 return instance ? instance->widget : NULL;
845}
846
847Widget
5f61736f
RS
848lw_make_widget (id, parent, pop_up_p)
849 LWLIB_ID id;
850 Widget parent;
851 Boolean pop_up_p;
07bf635f
RS
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
5f61736f
RS
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;
07bf635f
RS
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
5f61736f
RS
890destroy_one_instance (instance)
891 widget_instance* instance;
07bf635f
RS
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
9331cca8
FP
924#endif
925#if defined (USE_XAW)
926 if (lw_xaw_widget_p (instance->widget))
927 xaw_destroy_instance (instance);
928 else
07bf635f
RS
929#endif
930 /* do not remove the empty statement */
931 ;
932 }
933
934 free_widget_instance (instance);
935}
936
937void
5f61736f
RS
938lw_destroy_widget (w)
939 Widget w;
07bf635f
RS
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
5f61736f
RS
955lw_destroy_all_widgets (id)
956 LWLIB_ID id;
07bf635f
RS
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
9e3fe459 998extern Widget first_child (/* Widget */); /* garbage */
07bf635f
RS
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
5f61736f
RS
1035lw_pop_all_widgets (id, up)
1036 LWLIB_ID id;
1037 Boolean up;
07bf635f
RS
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 {
07bf635f
RS
1046#if defined (USE_LUCID)
1047 if (lw_lucid_widget_p (instance->widget))
9331cca8
FP
1048 {
1049 XtRealizeWidget (instance->widget);
1050 xlw_pop_instance (instance, up);
1051 }
07bf635f
RS
1052#endif
1053#if defined (USE_MOTIF)
1054 if (lw_motif_widget_p (instance->widget))
9331cca8
FP
1055 {
1056 XtRealizeWidget (instance->widget);
1057 xm_pop_instance (instance, up);
1058 }
07bf635f
RS
1059#endif
1060#if defined (USE_OLIT)
1061 if (lw_olit_widget_p (instance->widget))
9331cca8
FP
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 }
07bf635f
RS
1074#endif
1075 }
1076}
1077
1078void
5f61736f
RS
1079lw_pop_up_all_widgets (id)
1080 LWLIB_ID id;
07bf635f
RS
1081{
1082 lw_pop_all_widgets (id, True);
1083}
1084
1085void
5f61736f
RS
1086lw_pop_down_all_widgets (id)
1087 LWLIB_ID id;
07bf635f
RS
1088{
1089 lw_pop_all_widgets (id, False);
1090}
1091
1092void
5b3b31d6 1093lw_popup_menu (widget, event)
5f61736f 1094 Widget widget;
5b3b31d6 1095 XEvent *event;
07bf635f
RS
1096{
1097#if defined (USE_LUCID)
1098 if (lw_lucid_widget_p (widget))
5b3b31d6 1099 xlw_popup_menu (widget, event);
07bf635f
RS
1100#endif
1101#if defined (USE_MOTIF)
1102 if (lw_motif_widget_p (widget))
5b3b31d6 1103 xm_popup_menu (widget, event);
07bf635f
RS
1104#endif
1105#if defined (USE_OLIT)
1106 if (lw_olit_widget_p (widget))
5b3b31d6 1107 xol_popup_menu (widget, event);
07bf635f 1108#endif
9331cca8
FP
1109#if defined (USE_XAW)
1110 if (lw_xaw_widget_p (widget))
5b3b31d6 1111 xaw_popup_menu (widget, event);
9331cca8 1112#endif
07bf635f
RS
1113}
1114
1115\f/* get the values back */
1116static Boolean
5f61736f
RS
1117get_one_value (instance, val)
1118 widget_instance* instance;
1119 widget_value* val;
07bf635f
RS
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);
9331cca8
FP
1136#endif
1137#if defined (USE_XAW)
1138 if (lw_xaw_widget_p (instance->widget))
1139 xaw_update_one_value (instance, widget, val);
07bf635f
RS
1140#endif
1141 return True;
1142 }
1143 else
1144 return False;
1145}
1146
1147Boolean
5f61736f
RS
1148lw_get_some_values (id, val_out)
1149 LWLIB_ID id;
1150 widget_value* val_out;
07bf635f
RS
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*
5f61736f
RS
1172lw_get_all_values (id)
1173 LWLIB_ID id;
07bf635f
RS
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*
5f61736f
RS
1186lw_get_widget_value_for_widget (instance, w)
1187 widget_instance* instance;
1188 Widget w;
07bf635f
RS
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
5f61736f
RS
1203lw_internal_update_other_instances (widget, closure, call_data)
1204 Widget widget;
1205 XtPointer closure;
1206 XtPointer call_data;
07bf635f
RS
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
5f61736f
RS
1246lw_get_widget_id (w)
1247 Widget w;
07bf635f
RS
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
5f61736f
RS
1256lw_set_keyboard_focus (parent, w)
1257 Widget parent;
1258 Widget w;
07bf635f
RS
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
5f61736f
RS
1269show_one_widget_busy (w, flag)
1270 Widget w;
1271 Boolean flag;
07bf635f
RS
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
5f61736f
RS
1290lw_show_busy (w, busy)
1291 Widget w;
1292 Boolean busy;
07bf635f
RS
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}
2af91681
PR
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{
e1241f09 1318#if defined (USE_XAW)
2af91681
PR
1319 XawPanedSetRefigureMode (w, doit);
1320#endif
1321#if defined (USE_MOTIF)
1322 if (doit)
2af91681 1323 XtManageChild (w);
a61155bc
RS
1324 else
1325 XtUnmanageChild (w);
2af91681
PR
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)
6618806e 1355 xm_set_main_areas (parent, menubar, work_area);
2af91681
PR
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)
f78c5177 1367 xm_manage_resizing (w, flag);
2af91681
PR
1368#endif
1369}