Reposition some code so defined before used.
[emacs.git] / lwlib / lwlib.c
blob624c75890845e8b1d8bb81d57fac48c744fa0c62
1 /* A general interface to the widgets of different toolkits.
2 Copyright (C) 1992, 1993 Lucid, Inc.
4 This file is part of the Lucid Widget Library.
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.
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.
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. */
21 #ifdef NeXT
22 #undef __STRICT_BSD__ /* ick */
23 #endif
25 #ifdef HAVE_CONFIG_H
26 #include <config.h>
27 #endif
29 #include "../src/lisp.h"
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>
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_XAW)
49 #include <X11/Xaw/Paned.h>
50 #include "lwlib-Xaw.h"
51 #endif
53 #if !defined (USE_LUCID) && !defined (USE_MOTIF)
54 #error At least one of USE_LUCID or USE_MOTIF must be defined.
55 #endif
57 #ifndef max
58 #define max(x, y) ((x) > (y) ? (x) : (y))
59 #endif
61 /* List of all widgets managed by the library. */
62 static widget_info*
63 all_widget_info = NULL;
65 #ifdef USE_MOTIF
66 char *lwlib_toolkit_type = "motif";
67 #else
68 char *lwlib_toolkit_type = "lucid";
69 #endif
71 static widget_value *merge_widget_value P_ ((widget_value *,
72 widget_value *,
73 int, int *));
74 static void instantiate_widget_instance P_ ((widget_instance *));
75 static int my_strcasecmp P_ ((char *, char *));
76 static void safe_free_str P_ ((char *));
77 static void free_widget_value_tree P_ ((widget_value *));
78 static widget_value *copy_widget_value_tree P_ ((widget_value *,
79 change_type));
80 static widget_info *allocate_widget_info P_ ((char *, char *, LWLIB_ID,
81 widget_value *,
82 lw_callback, lw_callback,
83 lw_callback, lw_callback));
84 static void free_widget_info P_ ((widget_info *));
85 static void mark_widget_destroyed P_ ((Widget, XtPointer, XtPointer));
86 static widget_instance *allocate_widget_instance P_ ((widget_info *,
87 Widget, Boolean));
88 static void free_widget_instance P_ ((widget_instance *));
89 static widget_info *get_widget_info P_ ((LWLIB_ID, Boolean));
90 static widget_instance *get_widget_instance P_ ((Widget, Boolean));
91 static widget_instance *find_instance P_ ((LWLIB_ID, Widget, Boolean));
92 static Boolean safe_strcmp P_ ((char *, char *));
93 static Widget name_to_widget P_ ((widget_instance *, char *));
94 static void set_one_value P_ ((widget_instance *, widget_value *, Boolean));
95 static void update_one_widget_instance P_ ((widget_instance *, Boolean));
96 static void update_all_widget_values P_ ((widget_info *, Boolean));
97 static void initialize_widget_instance P_ ((widget_instance *));
98 static widget_creation_function find_in_table P_ ((char *, widget_creation_entry *));
99 static Boolean dialog_spec_p P_ ((char *));
100 static void destroy_one_instance P_ ((widget_instance *));
101 static void lw_pop_all_widgets P_ ((LWLIB_ID, Boolean));
102 static Boolean get_one_value P_ ((widget_instance *, widget_value *));
103 static void show_one_widget_busy P_ ((Widget, Boolean));
105 void
106 lwlib_memset (address, value, length)
107 char *address;
108 int value;
109 size_t length;
111 int i;
113 for (i = 0; i < length; i++)
114 address[i] = value;
117 void
118 lwlib_bcopy (from, to, length)
119 char *from;
120 char *to;
121 int length;
123 int i;
125 for (i = 0; i < length; i++)
126 to[i] = from[i];
128 \f/* utility functions for widget_instance and widget_info */
129 char *
130 safe_strdup (s)
131 const char *s;
133 char *result;
134 if (! s) return 0;
135 result = (char *) malloc (strlen (s) + 1);
136 if (! result)
137 return 0;
138 strcpy (result, s);
139 return result;
142 /* Like strcmp but ignore differences in case. */
144 static int
145 my_strcasecmp (s1, s2)
146 char *s1, *s2;
148 while (1)
150 int c1 = *s1++;
151 int c2 = *s2++;
152 if (isupper (c1))
153 c1 = tolower (c1);
154 if (isupper (c2))
155 c2 = tolower (c2);
156 if (c1 != c2)
157 return (c1 > c2 ? 1 : -1);
158 if (c1 == 0)
159 return 0;
163 static void
164 safe_free_str (s)
165 char *s;
167 if (s) free (s);
170 static widget_value *widget_value_free_list = 0;
171 static int malloc_cpt = 0;
173 widget_value *
174 malloc_widget_value ()
176 widget_value *wv;
177 if (widget_value_free_list)
179 wv = widget_value_free_list;
180 widget_value_free_list = wv->free_list;
181 wv->free_list = 0;
183 else
185 wv = (widget_value *) malloc (sizeof (widget_value));
186 malloc_cpt++;
188 lwlib_memset ((void*) wv, 0, sizeof (widget_value));
189 return wv;
192 /* this is analogous to free(). It frees only what was allocated
193 by malloc_widget_value(), and no substructures.
195 void
196 free_widget_value (wv)
197 widget_value *wv;
199 if (wv->free_list)
200 abort ();
202 if (malloc_cpt > 25)
204 /* When the number of already allocated cells is too big,
205 We free it. */
206 free (wv);
207 malloc_cpt--;
209 else
211 wv->free_list = widget_value_free_list;
212 widget_value_free_list = wv;
216 static void
217 free_widget_value_tree (wv)
218 widget_value *wv;
220 if (!wv)
221 return;
223 if (wv->name) free (wv->name);
224 if (wv->value) free (wv->value);
225 if (wv->key) free (wv->key);
227 wv->name = wv->value = wv->key = (char *) 0xDEADBEEF;
229 if (wv->toolkit_data && wv->free_toolkit_data)
231 XtFree (wv->toolkit_data);
232 wv->toolkit_data = (void *) 0xDEADBEEF;
235 if (wv->contents && (wv->contents != (widget_value*)1))
237 free_widget_value_tree (wv->contents);
238 wv->contents = (widget_value *) 0xDEADBEEF;
240 if (wv->next)
242 free_widget_value_tree (wv->next);
243 wv->next = (widget_value *) 0xDEADBEEF;
245 free_widget_value (wv);
248 static widget_value *
249 copy_widget_value_tree (val, change)
250 widget_value* val;
251 change_type change;
253 widget_value* copy;
255 if (!val)
256 return NULL;
257 if (val == (widget_value *) 1)
258 return val;
260 copy = malloc_widget_value ();
261 copy->name = safe_strdup (val->name);
262 copy->value = safe_strdup (val->value);
263 copy->key = safe_strdup (val->key);
264 copy->help = val->help;
265 copy->enabled = val->enabled;
266 copy->button_type = val->button_type;
267 copy->selected = val->selected;
268 copy->edited = False;
269 copy->change = change;
270 copy->this_one_change = change;
271 copy->contents = copy_widget_value_tree (val->contents, change);
272 copy->call_data = val->call_data;
273 copy->next = copy_widget_value_tree (val->next, change);
274 copy->toolkit_data = NULL;
275 copy->free_toolkit_data = False;
276 return copy;
279 static widget_info *
280 allocate_widget_info (type, name, id, val, pre_activate_cb,
281 selection_cb, post_activate_cb, highlight_cb)
282 char* type;
283 char* name;
284 LWLIB_ID id;
285 widget_value* val;
286 lw_callback pre_activate_cb;
287 lw_callback selection_cb;
288 lw_callback post_activate_cb;
289 lw_callback highlight_cb;
291 widget_info* info = (widget_info*)malloc (sizeof (widget_info));
292 info->type = safe_strdup (type);
293 info->name = safe_strdup (name);
294 info->id = id;
295 info->val = copy_widget_value_tree (val, STRUCTURAL_CHANGE);
296 info->busy = False;
297 info->pre_activate_cb = pre_activate_cb;
298 info->selection_cb = selection_cb;
299 info->post_activate_cb = post_activate_cb;
300 info->highlight_cb = highlight_cb;
301 info->instances = NULL;
303 info->next = all_widget_info;
304 all_widget_info = info;
306 return info;
309 static void
310 free_widget_info (info)
311 widget_info* info;
313 safe_free_str (info->type);
314 safe_free_str (info->name);
315 free_widget_value_tree (info->val);
316 lwlib_memset ((void*)info, 0xDEADBEEF, sizeof (widget_info));
317 free (info);
320 static void
321 mark_widget_destroyed (widget, closure, call_data)
322 Widget widget;
323 XtPointer closure;
324 XtPointer call_data;
326 widget_instance* instance = (widget_instance*)closure;
328 /* be very conservative */
329 if (instance->widget == widget)
330 instance->widget = NULL;
333 /* The messy #ifdef PROTOTYPES here and elsewhere are prompted by a
334 flood of warnings about argument promotion from proprietary ISO C
335 compilers. (etags still only makes one entry for each function.) */
336 static widget_instance *
337 #ifdef PROTOTYPES
338 allocate_widget_instance (widget_info* info, Widget parent, Boolean pop_up_p)
339 #else
340 allocate_widget_instance (info, parent, pop_up_p)
341 widget_info* info;
342 Widget parent;
343 Boolean pop_up_p;
344 #endif
346 widget_instance* instance =
347 (widget_instance*)malloc (sizeof (widget_instance));
348 bzero (instance, sizeof *instance);
349 instance->parent = parent;
350 instance->pop_up_p = pop_up_p;
351 instance->info = info;
352 instance->next = info->instances;
353 info->instances = instance;
355 instantiate_widget_instance (instance);
357 XtAddCallback (instance->widget, XtNdestroyCallback,
358 mark_widget_destroyed, (XtPointer)instance);
359 return instance;
362 static void
363 free_widget_instance (instance)
364 widget_instance* instance;
366 lwlib_memset ((void*)instance, 0xDEADBEEF, sizeof (widget_instance));
367 free (instance);
370 static widget_info *
371 #ifdef PROTOTYPES
372 get_widget_info (LWLIB_ID id, Boolean remove_p)
373 #else
374 get_widget_info (id, remove_p)
375 LWLIB_ID id;
376 Boolean remove_p;
377 #endif
379 widget_info* info;
380 widget_info* prev;
381 for (prev = NULL, info = all_widget_info;
382 info;
383 prev = info, info = info->next)
384 if (info->id == id)
386 if (remove_p)
388 if (prev)
389 prev->next = info->next;
390 else
391 all_widget_info = info->next;
393 return info;
395 return NULL;
398 /* Internal function used by the library dependent implementation to get the
399 widget_value for a given widget in an instance */
400 widget_info *
401 lw_get_widget_info (id)
402 LWLIB_ID id;
404 return get_widget_info (id, 0);
407 static widget_instance *
408 #ifdef PROTOTYPES
409 get_widget_instance (Widget widget, Boolean remove_p)
410 #else
411 get_widget_instance (widget, remove_p)
412 Widget widget;
413 Boolean remove_p;
414 #endif
416 widget_info* info;
417 widget_instance* instance;
418 widget_instance* prev;
419 for (info = all_widget_info; info; info = info->next)
420 for (prev = NULL, instance = info->instances;
421 instance;
422 prev = instance, instance = instance->next)
423 if (instance->widget == widget)
425 if (remove_p)
427 if (prev)
428 prev->next = instance->next;
429 else
430 info->instances = instance->next;
432 return instance;
434 return (widget_instance *) 0;
437 /* Value is a pointer to the widget_instance corresponding to
438 WIDGET, or null if WIDGET is not a lwlib widget. */
440 widget_instance *
441 lw_get_widget_instance (widget)
442 Widget widget;
444 return get_widget_instance (widget, False);
447 static widget_instance*
448 #ifdef PROTOTYPES
449 find_instance (LWLIB_ID id, Widget parent, Boolean pop_up_p)
450 #else
451 find_instance (id, parent, pop_up_p)
452 LWLIB_ID id;
453 Widget parent;
454 Boolean pop_up_p;
455 #endif
457 widget_info* info = get_widget_info (id, False);
458 widget_instance* instance;
460 if (info)
461 for (instance = info->instances; instance; instance = instance->next)
462 if (instance->parent == parent && instance->pop_up_p == pop_up_p)
463 return instance;
465 return NULL;
469 /* utility function for widget_value */
470 static Boolean
471 safe_strcmp (s1, s2)
472 char* s1;
473 char* s2;
475 if (!!s1 ^ !!s2) return True;
476 return (s1 && s2) ? strcmp (s1, s2) : s1 ? False : !!s2;
480 #if 0
481 # define EXPLAIN(name, oc, nc, desc, a1, a2) \
482 printf ("Change: \"%s\"\tmax(%s=%d,%s=%d)\t%s %d %d\n", \
483 name, \
484 (oc == NO_CHANGE ? "none" : \
485 (oc == INVISIBLE_CHANGE ? "invisible" : \
486 (oc == VISIBLE_CHANGE ? "visible" : \
487 (oc == STRUCTURAL_CHANGE ? "structural" : "???")))), \
488 oc, \
489 (nc == NO_CHANGE ? "none" : \
490 (nc == INVISIBLE_CHANGE ? "invisible" : \
491 (nc == VISIBLE_CHANGE ? "visible" : \
492 (nc == STRUCTURAL_CHANGE ? "structural" : "???")))), \
493 nc, desc, a1, a2)
494 #else
495 # define EXPLAIN(name, oc, nc, desc, a1, a2)
496 #endif
499 static widget_value *
500 merge_widget_value (val1, val2, level, change_p)
501 widget_value* val1;
502 widget_value* val2;
503 int level;
504 int *change_p;
506 change_type change, this_one_change;
507 widget_value* merged_next;
508 widget_value* merged_contents;
510 if (!val1)
512 if (val2)
514 *change_p = 1;
515 return copy_widget_value_tree (val2, STRUCTURAL_CHANGE);
517 else
518 return NULL;
520 if (!val2)
522 *change_p = 1;
523 free_widget_value_tree (val1);
524 return NULL;
527 change = NO_CHANGE;
529 if (safe_strcmp (val1->name, val2->name))
531 EXPLAIN (val1->name, change, STRUCTURAL_CHANGE, "name change",
532 val1->name, val2->name);
533 change = max (change, STRUCTURAL_CHANGE);
534 safe_free_str (val1->name);
535 val1->name = safe_strdup (val2->name);
537 if (safe_strcmp (val1->value, val2->value))
539 EXPLAIN (val1->name, change, VISIBLE_CHANGE, "value change",
540 val1->value, val2->value);
541 change = max (change, VISIBLE_CHANGE);
542 safe_free_str (val1->value);
543 val1->value = safe_strdup (val2->value);
545 if (safe_strcmp (val1->key, val2->key))
547 EXPLAIN (val1->name, change, VISIBLE_CHANGE, "key change",
548 val1->key, val2->key);
549 change = max (change, VISIBLE_CHANGE);
550 safe_free_str (val1->key);
551 val1->key = safe_strdup (val2->key);
553 if (! EQ (val1->help, val2->help))
555 EXPLAIN (val1->name, change, VISIBLE_CHANGE, "help change",
556 val1->help, val2->help);
557 change = max (change, VISIBLE_CHANGE);
558 val1->help = val2->help;
560 if (val1->enabled != val2->enabled)
562 EXPLAIN (val1->name, change, VISIBLE_CHANGE, "enablement change",
563 val1->enabled, val2->enabled);
564 change = max (change, VISIBLE_CHANGE);
565 val1->enabled = val2->enabled;
567 if (val1->button_type != val2->button_type)
569 EXPLAIN (val1->name, change, VISIBLE_CHANGE, "button type change",
570 val1->button_type, val2->button_type);
571 change = max (change, VISIBLE_CHANGE);
572 val1->button_type = val2->button_type;
574 if (val1->selected != val2->selected)
576 EXPLAIN (val1->name, change, VISIBLE_CHANGE, "selection change",
577 val1->selected, val2->selected);
578 change = max (change, VISIBLE_CHANGE);
579 val1->selected = val2->selected;
581 if (val1->call_data != val2->call_data)
583 EXPLAIN (val1->name, change, INVISIBLE_CHANGE, "call-data change",
584 val1->call_data, val2->call_data);
585 change = max (change, INVISIBLE_CHANGE);
586 val1->call_data = val2->call_data;
589 if (level > 0)
591 merged_contents =
592 merge_widget_value (val1->contents, val2->contents, level - 1,
593 change_p);
595 if (val1->contents && !merged_contents)
597 /* This used to say INVISIBLE_CHANGE,
598 but it is visible and vitally important when
599 the contents of the menu bar itself are entirely deleted.
601 But maybe it doesn't matter. This fails to fix the bug. */
602 EXPLAIN (val1->name, change, STRUCTURAL_CHANGE, "(contents gone)",
603 0, 0);
604 change = max (change, STRUCTURAL_CHANGE);
606 else if (merged_contents && merged_contents->change != NO_CHANGE)
608 EXPLAIN (val1->name, change, INVISIBLE_CHANGE, "(contents change)",
609 0, 0);
610 change = max (change, INVISIBLE_CHANGE);
611 #if 0 /* This was replaced by the August 9 1996 change in lwlib-Xm.c. */
612 #ifdef USE_MOTIF
613 change = max (merged_contents->change, change);
614 #endif
615 #endif
618 val1->contents = merged_contents;
621 this_one_change = change;
623 merged_next = merge_widget_value (val1->next, val2->next, level, change_p);
625 if (val1->next && !merged_next)
627 EXPLAIN (val1->name, change, STRUCTURAL_CHANGE, "(following gone)",
628 0, 0);
629 change = max (change, STRUCTURAL_CHANGE);
631 else if (merged_next)
633 if (merged_next->change)
634 EXPLAIN (val1->name, change, merged_next->change, "(following change)",
635 0, 0);
636 change = max (change, merged_next->change);
639 val1->next = merged_next;
641 val1->this_one_change = this_one_change;
642 val1->change = change;
644 if (change > NO_CHANGE && val1->toolkit_data)
646 *change_p = 1;
647 if (val1->free_toolkit_data)
648 XtFree (val1->toolkit_data);
649 val1->toolkit_data = NULL;
652 return val1;
656 /* modifying the widgets */
657 static Widget
658 name_to_widget (instance, name)
659 widget_instance* instance;
660 char* name;
662 Widget widget = NULL;
664 if (!instance->widget)
665 return NULL;
667 if (!strcmp (XtName (instance->widget), name))
668 widget = instance->widget;
669 else
671 int length = strlen (name) + 2;
672 char* real_name = (char *) xmalloc (length);
673 real_name [0] = '*';
674 strcpy (real_name + 1, name);
676 widget = XtNameToWidget (instance->widget, real_name);
678 free (real_name);
680 return widget;
683 static void
684 #ifdef PROTOTYPES
685 set_one_value (widget_instance* instance, widget_value* val, Boolean deep_p)
686 #else
687 set_one_value (instance, val, deep_p)
688 widget_instance* instance;
689 widget_value* val;
690 Boolean deep_p;
691 #endif
693 Widget widget = name_to_widget (instance, val->name);
695 if (widget)
697 #if defined (USE_LUCID)
698 if (lw_lucid_widget_p (instance->widget))
699 xlw_update_one_widget (instance, widget, val, deep_p);
700 #endif
701 #if defined (USE_MOTIF)
702 if (lw_motif_widget_p (instance->widget))
703 xm_update_one_widget (instance, widget, val, deep_p);
704 #endif
705 #if defined (USE_XAW)
706 if (lw_xaw_widget_p (instance->widget))
707 xaw_update_one_widget (instance, widget, val, deep_p);
708 #endif
712 static void
713 #ifdef PROTOTYPES
714 update_one_widget_instance (widget_instance* instance, Boolean deep_p)
715 #else
716 update_one_widget_instance (instance, deep_p)
717 widget_instance* instance;
718 Boolean deep_p;
719 #endif
721 widget_value *val;
723 if (!instance->widget)
724 /* the widget was destroyed */
725 return;
727 for (val = instance->info->val; val; val = val->next)
728 if (val->change != NO_CHANGE)
729 set_one_value (instance, val, deep_p);
732 static void
733 #ifdef PROTOTYPES
734 update_all_widget_values (widget_info* info, Boolean deep_p)
735 #else
736 update_all_widget_values (info, deep_p)
737 widget_info* info;
738 Boolean deep_p;
739 #endif
741 widget_instance* instance;
742 widget_value* val;
744 for (instance = info->instances; instance; instance = instance->next)
745 update_one_widget_instance (instance, deep_p);
747 for (val = info->val; val; val = val->next)
748 val->change = NO_CHANGE;
752 #ifdef PROTOTYPES
753 lw_modify_all_widgets (LWLIB_ID id, widget_value* val, Boolean deep_p)
754 #else
755 lw_modify_all_widgets (id, val, deep_p)
756 LWLIB_ID id;
757 widget_value* val;
758 Boolean deep_p;
759 #endif
761 widget_info* info = get_widget_info (id, False);
762 widget_value* new_val;
763 widget_value* next_new_val;
764 widget_value* cur;
765 widget_value* prev;
766 widget_value* next;
767 int found;
768 int change_p = 0;
770 if (!info)
771 return 0;
773 for (new_val = val; new_val; new_val = new_val->next)
775 next_new_val = new_val->next;
776 new_val->next = NULL;
777 found = False;
778 for (prev = NULL, cur = info->val; cur; prev = cur, cur = cur->next)
779 if (!strcmp (cur->name, new_val->name))
781 found = True;
782 next = cur->next;
783 cur->next = NULL;
784 cur = merge_widget_value (cur, new_val, deep_p ? 1000 : 1,
785 &change_p);
786 if (prev)
787 prev->next = cur ? cur : next;
788 else
789 info->val = cur ? cur : next;
790 if (cur)
791 cur->next = next;
792 break;
794 if (!found)
796 /* Could not find it, add it */
797 if (prev)
798 prev->next = copy_widget_value_tree (new_val, STRUCTURAL_CHANGE);
799 else
800 info->val = copy_widget_value_tree (new_val, STRUCTURAL_CHANGE);
801 change_p = 1;
803 new_val->next = next_new_val;
806 update_all_widget_values (info, deep_p);
807 return change_p;
811 /* creating the widgets */
813 static void
814 initialize_widget_instance (instance)
815 widget_instance* instance;
817 widget_value* val;
819 for (val = instance->info->val; val; val = val->next)
820 val->change = STRUCTURAL_CHANGE;
822 update_one_widget_instance (instance, True);
824 for (val = instance->info->val; val; val = val->next)
825 val->change = NO_CHANGE;
829 static widget_creation_function
830 find_in_table (type, table)
831 char* type;
832 widget_creation_entry* table;
834 widget_creation_entry* cur;
835 for (cur = table; cur->type; cur++)
836 if (!my_strcasecmp (type, cur->type))
837 return cur->function;
838 return NULL;
841 static Boolean
842 dialog_spec_p (name)
843 char* name;
845 /* return True if name matches [EILPQeilpq][1-9][Bb] or
846 [EILPQeilpq][1-9][Bb][Rr][1-9] */
847 if (!name)
848 return False;
850 switch (name [0])
852 case 'E': case 'I': case 'L': case 'P': case 'Q':
853 case 'e': case 'i': case 'l': case 'p': case 'q':
854 if (name [1] >= '0' && name [1] <= '9')
856 if (name [2] != 'B' && name [2] != 'b')
857 return False;
858 if (!name [3])
859 return True;
860 if ((name [3] == 'T' || name [3] == 't') && !name [4])
861 return True;
862 if ((name [3] == 'R' || name [3] == 'r')
863 && name [4] >= '0' && name [4] <= '9' && !name [5])
864 return True;
865 return False;
867 else
868 return False;
870 default:
871 return False;
875 static void
876 instantiate_widget_instance (instance)
877 widget_instance* instance;
879 widget_creation_function function = NULL;
881 #if defined (USE_LUCID)
882 if (!function)
883 function = find_in_table (instance->info->type, xlw_creation_table);
884 #endif
885 #if defined(USE_MOTIF)
886 if (!function)
887 function = find_in_table (instance->info->type, xm_creation_table);
888 #endif
889 #if defined (USE_XAW)
890 if (!function)
891 function = find_in_table (instance->info->type, xaw_creation_table);
892 #endif
894 if (!function)
896 if (dialog_spec_p (instance->info->type))
898 #if defined (USE_LUCID)
899 /* not yet */
900 #endif
901 #if defined(USE_MOTIF)
902 if (!function)
903 function = xm_create_dialog;
904 #endif
905 #if defined (USE_XAW)
906 if (!function)
907 function = xaw_create_dialog;
908 #endif
912 if (!function)
914 printf ("No creation function for widget type %s\n",
915 instance->info->type);
916 abort ();
919 instance->widget = (*function) (instance);
921 if (!instance->widget)
922 abort ();
924 /* XtRealizeWidget (instance->widget);*/
927 void
928 lw_register_widget (type, name, id, val, pre_activate_cb,
929 selection_cb, post_activate_cb, highlight_cb)
930 char* type;
931 char* name;
932 LWLIB_ID id;
933 widget_value* val;
934 lw_callback pre_activate_cb;
935 lw_callback selection_cb;
936 lw_callback post_activate_cb;
937 lw_callback highlight_cb;
939 if (!get_widget_info (id, False))
940 allocate_widget_info (type, name, id, val, pre_activate_cb, selection_cb,
941 post_activate_cb, highlight_cb);
944 Widget
945 #ifdef PROTOTYPES
946 lw_get_widget (LWLIB_ID id, Widget parent, Boolean pop_up_p)
947 #else
948 lw_get_widget (id, parent, pop_up_p)
949 LWLIB_ID id;
950 Widget parent;
951 Boolean pop_up_p;
952 #endif
954 widget_instance* instance;
956 instance = find_instance (id, parent, pop_up_p);
957 return instance ? instance->widget : NULL;
960 Widget
961 #ifdef PROTOTYPES
962 lw_make_widget (LWLIB_ID id, Widget parent, Boolean pop_up_p)
963 #else
964 lw_make_widget (id, parent, pop_up_p)
965 LWLIB_ID id;
966 Widget parent;
967 Boolean pop_up_p;
968 #endif
970 widget_instance* instance;
971 widget_info* info;
973 instance = find_instance (id, parent, pop_up_p);
974 if (!instance)
976 info = get_widget_info (id, False);
977 if (!info)
978 return NULL;
979 instance = allocate_widget_instance (info, parent, pop_up_p);
980 initialize_widget_instance (instance);
982 if (!instance->widget)
983 abort ();
984 return instance->widget;
987 Widget
988 #ifdef PROTOTYPES
989 lw_create_widget (char* type, char* name, LWLIB_ID id, widget_value* val,
990 Widget parent, Boolean pop_up_p,
991 lw_callback pre_activate_cb, lw_callback selection_cb,
992 lw_callback post_activate_cb, lw_callback highlight_cb)
993 #else
994 lw_create_widget (type, name, id, val, parent, pop_up_p, pre_activate_cb,
995 selection_cb, post_activate_cb, highlight_cb)
996 char* type;
997 char* name;
998 LWLIB_ID id;
999 widget_value* val;
1000 Widget parent;
1001 Boolean pop_up_p;
1002 lw_callback pre_activate_cb;
1003 lw_callback selection_cb;
1004 lw_callback post_activate_cb;
1005 lw_callback highlight_cb;
1006 #endif
1008 lw_register_widget (type, name, id, val, pre_activate_cb, selection_cb,
1009 post_activate_cb, highlight_cb);
1010 return lw_make_widget (id, parent, pop_up_p);
1014 /* destroying the widgets */
1015 static void
1016 destroy_one_instance (instance)
1017 widget_instance* instance;
1019 /* Remove the destroy callback on the widget; that callback will try to
1020 dereference the instance object (to set its widget slot to 0, since the
1021 widget is dead.) Since the instance is now dead, we don't have to worry
1022 about the fact that its widget is dead too.
1024 This happens in the Phase2Destroy of the widget, so this callback would
1025 not have been run until arbitrarily long after the instance was freed.
1027 if (instance->widget)
1028 XtRemoveCallback (instance->widget, XtNdestroyCallback,
1029 mark_widget_destroyed, (XtPointer)instance);
1031 if (instance->widget)
1033 /* The else are pretty tricky here, including the empty statement
1034 at the end because it would be very bad to destroy a widget
1035 twice. */
1036 #if defined (USE_LUCID)
1037 if (lw_lucid_widget_p (instance->widget))
1038 xlw_destroy_instance (instance);
1039 else
1040 #endif
1041 #if defined (USE_MOTIF)
1042 if (lw_motif_widget_p (instance->widget))
1043 xm_destroy_instance (instance);
1044 else
1045 #endif
1046 #if defined (USE_XAW)
1047 if (lw_xaw_widget_p (instance->widget))
1048 xaw_destroy_instance (instance);
1049 else
1050 #endif
1051 /* do not remove the empty statement */
1055 free_widget_instance (instance);
1058 void
1059 lw_destroy_widget (w)
1060 Widget w;
1062 widget_instance* instance = get_widget_instance (w, True);
1064 if (instance)
1066 widget_info *info = instance->info;
1067 /* instance has already been removed from the list; free it */
1068 destroy_one_instance (instance);
1069 /* if there are no instances left, free the info too */
1070 if (!info->instances)
1071 lw_destroy_all_widgets (info->id);
1075 void
1076 lw_destroy_all_widgets (id)
1077 LWLIB_ID id;
1079 widget_info* info = get_widget_info (id, True);
1080 widget_instance* instance;
1081 widget_instance* next;
1083 if (info)
1085 for (instance = info->instances; instance; )
1087 next = instance->next;
1088 destroy_one_instance (instance);
1089 instance = next;
1091 free_widget_info (info);
1095 void
1096 lw_destroy_everything ()
1098 while (all_widget_info)
1099 lw_destroy_all_widgets (all_widget_info->id);
1102 void
1103 lw_destroy_all_pop_ups ()
1105 widget_info* info;
1106 widget_info* next;
1107 widget_instance* instance;
1109 for (info = all_widget_info; info; info = next)
1111 next = info->next;
1112 instance = info->instances;
1113 if (instance && instance->pop_up_p)
1114 lw_destroy_all_widgets (info->id);
1118 #ifdef USE_MOTIF
1119 extern Widget first_child (/* Widget */); /* garbage */
1120 #endif
1122 Widget
1123 lw_raise_all_pop_up_widgets ()
1125 widget_info* info;
1126 widget_instance* instance;
1127 Widget result = NULL;
1129 for (info = all_widget_info; info; info = info->next)
1130 for (instance = info->instances; instance; instance = instance->next)
1131 if (instance->pop_up_p)
1133 Widget widget = instance->widget;
1134 if (widget)
1136 if (XtIsManaged (widget)
1137 #ifdef USE_MOTIF
1138 /* What a complete load of crap!!!!
1139 When a dialogShell is on the screen, it is not managed!
1141 || (lw_motif_widget_p (instance->widget) &&
1142 XtIsManaged (first_child (widget)))
1143 #endif
1146 if (!result)
1147 result = widget;
1148 XMapRaised (XtDisplay (widget), XtWindow (widget));
1152 return result;
1155 static void
1156 #ifdef PROTOTYPES
1157 lw_pop_all_widgets (LWLIB_ID id, Boolean up)
1158 #else
1159 lw_pop_all_widgets (id, up)
1160 LWLIB_ID id;
1161 Boolean up;
1162 #endif
1164 widget_info* info = get_widget_info (id, False);
1165 widget_instance* instance;
1167 if (info)
1168 for (instance = info->instances; instance; instance = instance->next)
1169 if (instance->pop_up_p && instance->widget)
1171 #if defined (USE_LUCID)
1172 if (lw_lucid_widget_p (instance->widget))
1174 XtRealizeWidget (instance->widget);
1175 xlw_pop_instance (instance, up);
1177 #endif
1178 #if defined (USE_MOTIF)
1179 if (lw_motif_widget_p (instance->widget))
1181 XtRealizeWidget (instance->widget);
1182 xm_pop_instance (instance, up);
1184 #endif
1185 #if defined (USE_XAW)
1186 if (lw_xaw_widget_p (instance->widget))
1188 XtRealizeWidget (XtParent (instance->widget));
1189 XtRealizeWidget (instance->widget);
1190 xaw_pop_instance (instance, up);
1192 #endif
1196 void
1197 lw_pop_up_all_widgets (id)
1198 LWLIB_ID id;
1200 lw_pop_all_widgets (id, True);
1203 void
1204 lw_pop_down_all_widgets (id)
1205 LWLIB_ID id;
1207 lw_pop_all_widgets (id, False);
1210 void
1211 lw_popup_menu (widget, event)
1212 Widget widget;
1213 XEvent *event;
1215 #if defined (USE_LUCID)
1216 if (lw_lucid_widget_p (widget))
1217 xlw_popup_menu (widget, event);
1218 #endif
1219 #if defined (USE_MOTIF)
1220 if (lw_motif_widget_p (widget))
1221 xm_popup_menu (widget, event);
1222 #endif
1223 #if defined (USE_XAW)
1224 if (lw_xaw_widget_p (widget))
1225 xaw_popup_menu (widget, event);
1226 #endif
1229 \f/* get the values back */
1230 static Boolean
1231 get_one_value (instance, val)
1232 widget_instance* instance;
1233 widget_value* val;
1235 Widget widget = name_to_widget (instance, val->name);
1237 if (widget)
1239 #if defined (USE_LUCID)
1240 if (lw_lucid_widget_p (instance->widget))
1241 xlw_update_one_value (instance, widget, val);
1242 #endif
1243 #if defined (USE_MOTIF)
1244 if (lw_motif_widget_p (instance->widget))
1245 xm_update_one_value (instance, widget, val);
1246 #endif
1247 #if defined (USE_XAW)
1248 if (lw_xaw_widget_p (instance->widget))
1249 xaw_update_one_value (instance, widget, val);
1250 #endif
1251 return True;
1253 else
1254 return False;
1257 Boolean
1258 lw_get_some_values (id, val_out)
1259 LWLIB_ID id;
1260 widget_value* val_out;
1262 widget_info* info = get_widget_info (id, False);
1263 widget_instance* instance;
1264 widget_value* val;
1265 Boolean result = False;
1267 if (!info)
1268 return False;
1270 instance = info->instances;
1271 if (!instance)
1272 return False;
1274 for (val = val_out; val; val = val->next)
1275 if (get_one_value (instance, val))
1276 result = True;
1278 return result;
1281 widget_value*
1282 lw_get_all_values (id)
1283 LWLIB_ID id;
1285 widget_info* info = get_widget_info (id, False);
1286 widget_value* val = info->val;
1287 if (lw_get_some_values (id, val))
1288 return val;
1289 else
1290 return NULL;
1293 /* internal function used by the library dependent implementation to get the
1294 widget_value for a given widget in an instance */
1295 widget_value*
1296 lw_get_widget_value_for_widget (instance, w)
1297 widget_instance* instance;
1298 Widget w;
1300 char* name = XtName (w);
1301 widget_value* cur;
1302 for (cur = instance->info->val; cur; cur = cur->next)
1303 if (!strcmp (cur->name, name))
1304 return cur;
1305 return NULL;
1308 \f/* update other instances value when one thing changed */
1310 /* To forbid recursive calls */
1311 static Boolean lwlib_updating;
1313 /* This function can be used as a an XtCallback for the widgets that get
1314 modified to update other instances of the widgets. Closure should be the
1315 widget_instance. */
1316 void
1317 lw_internal_update_other_instances (widget, closure, call_data)
1318 Widget widget;
1319 XtPointer closure;
1320 XtPointer call_data;
1322 widget_instance* instance = (widget_instance*)closure;
1323 char* name = XtName (widget);
1324 widget_info* info;
1325 widget_instance* cur;
1326 widget_value* val;
1328 /* Avoid possibly infinite recursion. */
1329 if (lwlib_updating)
1330 return;
1332 /* protect against the widget being destroyed */
1333 if (XtWidgetBeingDestroyedP (widget))
1334 return;
1336 /* Return immediately if there are no other instances */
1337 info = instance->info;
1338 if (!info->instances->next)
1339 return;
1341 lwlib_updating = True;
1343 for (val = info->val; val && strcmp (val->name, name); val = val->next);
1345 if (val && get_one_value (instance, val))
1346 for (cur = info->instances; cur; cur = cur->next)
1347 if (cur != instance)
1348 set_one_value (cur, val, True);
1350 lwlib_updating = False;
1354 \f/* get the id */
1356 LWLIB_ID
1357 lw_get_widget_id (w)
1358 Widget w;
1360 widget_instance* instance = get_widget_instance (w, False);
1362 return instance ? instance->info->id : 0;
1365 \f/* set the keyboard focus */
1366 void
1367 lw_set_keyboard_focus (parent, w)
1368 Widget parent;
1369 Widget w;
1371 #if defined (USE_MOTIF)
1372 xm_set_keyboard_focus (parent, w);
1373 #else
1374 XtSetKeyboardFocus (parent, w);
1375 #endif
1378 \f/* Show busy */
1379 static void
1380 #ifdef PROTOTYPES
1381 show_one_widget_busy (Widget w, Boolean flag)
1382 #else
1383 show_one_widget_busy (w, flag)
1384 Widget w;
1385 Boolean flag;
1386 #endif
1388 Pixel foreground = 0;
1389 Pixel background = 1;
1390 Widget widget_to_invert = XtNameToWidget (w, "*sheet");
1391 if (!widget_to_invert)
1392 widget_to_invert = w;
1394 XtVaGetValues (widget_to_invert,
1395 XtNforeground, &foreground,
1396 XtNbackground, &background,
1397 NULL);
1398 XtVaSetValues (widget_to_invert,
1399 XtNforeground, background,
1400 XtNbackground, foreground,
1401 NULL);
1404 void
1405 #ifdef PROTOTYPES
1406 lw_show_busy (Widget w, Boolean busy)
1407 #else
1408 lw_show_busy (w, busy)
1409 Widget w;
1410 Boolean busy;
1411 #endif
1413 widget_instance* instance = get_widget_instance (w, False);
1414 widget_info* info;
1415 widget_instance* next;
1417 if (instance)
1419 info = instance->info;
1420 if (info->busy != busy)
1422 for (next = info->instances; next; next = next->next)
1423 if (next->widget)
1424 show_one_widget_busy (next->widget, busy);
1425 info->busy = busy;
1430 /* This hack exists because Lucid/Athena need to execute the strange
1431 function below to support geometry management. */
1432 void
1433 #ifdef PROTOTYPES
1434 lw_refigure_widget (Widget w, Boolean doit)
1435 #else
1436 lw_refigure_widget (w, doit)
1437 Widget w;
1438 Boolean doit;
1439 #endif
1441 #if defined (USE_XAW)
1442 XawPanedSetRefigureMode (w, doit);
1443 #endif
1444 #if defined (USE_MOTIF)
1445 if (doit)
1446 XtManageChild (w);
1447 else
1448 XtUnmanageChild (w);
1449 #endif
1452 /* Toolkit independent way of determining if an event window is in the
1453 menubar. */
1454 Boolean
1455 lw_window_is_in_menubar (win, menubar_widget)
1456 Window win;
1457 Widget menubar_widget;
1459 return menubar_widget
1460 #if defined (USE_LUCID)
1461 && XtWindow (menubar_widget) == win;
1462 #endif
1463 #if defined (USE_MOTIF)
1464 && ((XtWindow (menubar_widget) == win)
1465 || (XtWindowToWidget (XtDisplay (menubar_widget), win)
1466 && (XtParent (XtWindowToWidget (XtDisplay (menubar_widget), win))
1467 == menubar_widget)));
1468 #endif
1471 /* Motif hack to set the main window areas. */
1472 void
1473 lw_set_main_areas (parent, menubar, work_area)
1474 Widget parent;
1475 Widget menubar;
1476 Widget work_area;
1478 #if defined (USE_MOTIF)
1479 xm_set_main_areas (parent, menubar, work_area);
1480 #endif
1483 /* Manage resizing for Motif. This disables resizing when the menubar
1484 is about to be modified. */
1485 void
1486 #ifdef PROTOTYPES
1487 lw_allow_resizing (Widget w, Boolean flag)
1488 #else
1489 lw_allow_resizing (w, flag)
1490 Widget w;
1491 Boolean flag;
1492 #endif
1494 #if defined (USE_MOTIF)
1495 xm_manage_resizing (w, flag);
1496 #endif
1500 /* Value is non-zero if LABEL is a menu separator. If it is, *TYPE is
1501 set to an appropriate enumerator of type enum menu_separator.
1502 MOTIF_P non-zero means map separator types not supported by Motif
1503 to similar ones that are supported. */
1506 lw_separator_p (label, type, motif_p)
1507 char *label;
1508 enum menu_separator *type;
1509 int motif_p;
1511 int separator_p = 0;
1513 if (strlen (label) >= 3
1514 && bcmp (label, "--:", 3) == 0)
1516 static struct separator_table
1518 char *name;
1519 enum menu_separator type;
1521 separator_names[] =
1523 {"space", SEPARATOR_NO_LINE},
1524 {"noLine", SEPARATOR_NO_LINE},
1525 {"singleLine", SEPARATOR_SINGLE_LINE},
1526 {"doubleLine", SEPARATOR_DOUBLE_LINE},
1527 {"singleDashedLine", SEPARATOR_SINGLE_DASHED_LINE},
1528 {"doubleDashedLine", SEPARATOR_DOUBLE_DASHED_LINE},
1529 {"shadowEtchedIn", SEPARATOR_SHADOW_ETCHED_IN},
1530 {"shadowEtchedOut", SEPARATOR_SHADOW_ETCHED_OUT},
1531 {"shadowEtchedInDash", SEPARATOR_SHADOW_ETCHED_IN_DASH},
1532 {"shadowEtchedOutDash", SEPARATOR_SHADOW_ETCHED_OUT_DASH},
1533 {"shadowDoubleEtchedIn", SEPARATOR_SHADOW_DOUBLE_ETCHED_IN},
1534 {"shadowDoubleEtchedOut", SEPARATOR_SHADOW_DOUBLE_ETCHED_OUT},
1535 {"shadowDoubleEtchedInDash", SEPARATOR_SHADOW_DOUBLE_ETCHED_IN_DASH},
1536 {"shadowDoubleEtchedOutDash", SEPARATOR_SHADOW_DOUBLE_ETCHED_OUT_DASH},
1537 {0,0}
1540 int i;
1542 label += 3;
1543 for (i = 0; separator_names[i].name; ++i)
1544 if (strcmp (label, separator_names[i].name) == 0)
1546 separator_p = 1;
1547 *type = separator_names[i].type;
1549 /* If separator type is not supported under Motif,
1550 use a similar one. */
1551 if (motif_p && *type >= SEPARATOR_SHADOW_DOUBLE_ETCHED_IN)
1552 *type -= 4;
1553 break;
1556 else if (strlen (label) > 3
1557 && bcmp (label, "--", 2) == 0
1558 && label[2] != '-')
1560 /* Alternative, more Emacs-style names. */
1561 static struct separator_table
1563 char *name;
1564 enum menu_separator type;
1566 separator_names[] =
1568 {"space", SEPARATOR_NO_LINE},
1569 {"no-line", SEPARATOR_NO_LINE},
1570 {"single-line", SEPARATOR_SINGLE_LINE},
1571 {"double-line", SEPARATOR_DOUBLE_LINE},
1572 {"single-dashed-line", SEPARATOR_SINGLE_DASHED_LINE},
1573 {"double-dashed-line", SEPARATOR_DOUBLE_DASHED_LINE},
1574 {"shadow-etched-in", SEPARATOR_SHADOW_ETCHED_IN},
1575 {"shadow-etched-out", SEPARATOR_SHADOW_ETCHED_OUT},
1576 {"shadow-etched-in-dash", SEPARATOR_SHADOW_ETCHED_IN_DASH},
1577 {"shadow-etched-out-dash", SEPARATOR_SHADOW_ETCHED_OUT_DASH},
1578 {"shadow-double-etched-in", SEPARATOR_SHADOW_DOUBLE_ETCHED_IN},
1579 {"shadow-double-etched-out", SEPARATOR_SHADOW_DOUBLE_ETCHED_OUT},
1580 {"shadow-double-etched-in-dash", SEPARATOR_SHADOW_DOUBLE_ETCHED_IN_DASH},
1581 {"shadow-double-etched-out-dash",SEPARATOR_SHADOW_DOUBLE_ETCHED_OUT_DASH},
1582 {0,0}
1585 int i;
1587 label += 2;
1588 for (i = 0; separator_names[i].name; ++i)
1589 if (strcmp (label, separator_names[i].name) == 0)
1591 separator_p = 1;
1592 *type = separator_names[i].type;
1594 /* If separator type is not supported under Motif,
1595 use a similar one. */
1596 if (motif_p && *type >= SEPARATOR_SHADOW_DOUBLE_ETCHED_IN)
1597 *type -= 4;
1598 break;
1601 else
1603 /* Old-style separator, maybe. It's a separator if it contains
1604 only dashes. */
1605 while (*label == '-')
1606 ++label;
1607 separator_p = *label == 0;
1608 *type = SEPARATOR_SHADOW_ETCHED_IN;
1611 return separator_p;