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