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