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