comparison lwlib/lwlib.c @ 428:3ecd8885ac67 r21-2-22

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