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