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