src/ChangeLog: Add missing bug id.
[emacs.git] / lwlib / lwlib.c
blob5a64e4da984df23e29d30612e939d49ddbc22768
1 /* A general interface to the widgets of different toolkits.
2 Copyright (C) 1992, 1993 Lucid, Inc.
3 Copyright (C) 1994, 1995, 1996, 1999, 2000, 2001, 2002, 2003, 2004,
4 2005, 2006, 2007, 2008, 2009, 2010 Free Software Foundation, Inc.
6 This file is part of the Lucid Widget Library.
8 The Lucid Widget Library is free software; you can redistribute it and/or
9 modify it under the terms of the GNU General Public License as published by
10 the Free Software Foundation; either version 2, or (at your option)
11 any later version.
13 The Lucid Widget Library is distributed in the hope that it will be useful,
14 but WITHOUT ANY WARRANTY; without even the implied warranty of
15 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 GNU General Public License for more details.
18 You should have received a copy of the GNU General Public License
19 along with GNU Emacs; see the file COPYING. If not, write to
20 the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
21 Boston, MA 02110-1301, USA. */
23 #ifdef HAVE_CONFIG_H
24 #include <config.h>
25 #endif
27 #include <setjmp.h>
28 #include "../src/lisp.h"
30 #include <sys/types.h>
31 #include <stdio.h>
32 #include <ctype.h>
33 #include "lwlib-int.h"
34 #include "lwlib-utils.h"
35 #include <X11/StringDefs.h>
37 #if defined (USE_LUCID)
38 #include "lwlib-Xlw.h"
39 #endif
40 #if defined (USE_MOTIF)
41 #include "lwlib-Xm.h"
42 #else /* not USE_MOTIF */
43 #if defined (USE_LUCID)
44 #define USE_XAW
45 #endif /* not USE_MOTIF && USE_LUCID */
46 #endif
47 #if defined (USE_XAW)
48 #ifdef HAVE_XAW3D
49 #include <X11/Xaw3d/Paned.h>
50 #else /* !HAVE_XAW3D */
51 #include <X11/Xaw/Paned.h>
52 #endif /* HAVE_XAW3D */
53 #include "lwlib-Xaw.h"
54 #endif
56 #if !defined (USE_LUCID) && !defined (USE_MOTIF)
57 #error At least one of USE_LUCID or USE_MOTIF must be defined.
58 #endif
60 #ifndef max
61 #define max(x, y) ((x) > (y) ? (x) : (y))
62 #endif
64 /* List of all widgets managed by the library. */
65 static widget_info*
66 all_widget_info = NULL;
68 #ifdef USE_MOTIF
69 char *lwlib_toolkit_type = "motif";
70 #else
71 char *lwlib_toolkit_type = "lucid";
72 #endif
74 static widget_value *merge_widget_value P_ ((widget_value *,
75 widget_value *,
76 int, int *));
77 static void instantiate_widget_instance P_ ((widget_instance *));
78 static int my_strcasecmp P_ ((char *, char *));
79 static void safe_free_str P_ ((char *));
80 static void free_widget_value_tree P_ ((widget_value *));
81 static widget_value *copy_widget_value_tree P_ ((widget_value *,
82 change_type));
83 static widget_info *allocate_widget_info P_ ((char *, char *, LWLIB_ID,
84 widget_value *,
85 lw_callback, lw_callback,
86 lw_callback, lw_callback));
87 static void free_widget_info P_ ((widget_info *));
88 static void mark_widget_destroyed P_ ((Widget, XtPointer, XtPointer));
89 static widget_instance *allocate_widget_instance P_ ((widget_info *,
90 Widget, Boolean));
91 static void free_widget_instance P_ ((widget_instance *));
92 static widget_info *get_widget_info P_ ((LWLIB_ID, Boolean));
93 static widget_instance *get_widget_instance P_ ((Widget, Boolean));
94 static widget_instance *find_instance P_ ((LWLIB_ID, Widget, Boolean));
95 static Boolean safe_strcmp P_ ((char *, char *));
96 static Widget name_to_widget P_ ((widget_instance *, char *));
97 static void set_one_value P_ ((widget_instance *, widget_value *, Boolean));
98 static void update_one_widget_instance P_ ((widget_instance *, Boolean));
99 static void update_all_widget_values P_ ((widget_info *, Boolean));
100 static void initialize_widget_instance P_ ((widget_instance *));
101 static widget_creation_function find_in_table P_ ((char *, widget_creation_entry *));
102 static Boolean dialog_spec_p P_ ((char *));
103 static void destroy_one_instance P_ ((widget_instance *));
104 static void lw_pop_all_widgets P_ ((LWLIB_ID, Boolean));
105 static Boolean get_one_value P_ ((widget_instance *, widget_value *));
106 static void show_one_widget_busy P_ ((Widget, Boolean));
108 void
109 lwlib_memset (address, value, length)
110 char *address;
111 int value;
112 size_t length;
114 int i;
116 for (i = 0; i < length; i++)
117 address[i] = value;
120 void
121 lwlib_bcopy (from, to, length)
122 char *from;
123 char *to;
124 int length;
126 int i;
128 for (i = 0; i < length; i++)
129 to[i] = from[i];
131 \f/* utility functions for widget_instance and widget_info */
132 char *
133 safe_strdup (s)
134 const char *s;
136 char *result;
137 if (! s) return 0;
138 result = (char *) malloc (strlen (s) + 1);
139 if (! result)
140 return 0;
141 strcpy (result, s);
142 return result;
145 /* Like strcmp but ignore differences in case. */
147 static int
148 my_strcasecmp (s1, s2)
149 char *s1, *s2;
151 while (1)
153 int c1 = *s1++;
154 int c2 = *s2++;
155 if (isupper (c1))
156 c1 = tolower (c1);
157 if (isupper (c2))
158 c2 = tolower (c2);
159 if (c1 != c2)
160 return (c1 > c2 ? 1 : -1);
161 if (c1 == 0)
162 return 0;
166 static void
167 safe_free_str (s)
168 char *s;
170 free (s);
173 static widget_value *widget_value_free_list = 0;
174 static int malloc_cpt = 0;
176 widget_value *
177 malloc_widget_value ()
179 widget_value *wv;
180 if (widget_value_free_list)
182 wv = widget_value_free_list;
183 widget_value_free_list = wv->free_list;
184 wv->free_list = 0;
186 else
188 wv = (widget_value *) malloc (sizeof (widget_value));
189 malloc_cpt++;
191 lwlib_memset ((void*) wv, 0, sizeof (widget_value));
192 return wv;
195 /* this is analogous to free(). It frees only what was allocated
196 by malloc_widget_value(), and no substructures.
198 void
199 free_widget_value (wv)
200 widget_value *wv;
202 if (wv->free_list)
203 abort ();
205 if (malloc_cpt > 25)
207 /* When the number of already allocated cells is too big,
208 We free it. */
209 free (wv);
210 malloc_cpt--;
212 else
214 wv->free_list = widget_value_free_list;
215 widget_value_free_list = wv;
219 static void
220 free_widget_value_tree (wv)
221 widget_value *wv;
223 if (!wv)
224 return;
226 free (wv->name);
227 free (wv->value);
228 free (wv->key);
230 wv->name = wv->value = wv->key = (char *) 0xDEADBEEF;
232 if (wv->toolkit_data && wv->free_toolkit_data)
234 XtFree (wv->toolkit_data);
235 wv->toolkit_data = (void *) 0xDEADBEEF;
238 if (wv->contents && (wv->contents != (widget_value*)1))
240 free_widget_value_tree (wv->contents);
241 wv->contents = (widget_value *) 0xDEADBEEF;
243 if (wv->next)
245 free_widget_value_tree (wv->next);
246 wv->next = (widget_value *) 0xDEADBEEF;
248 free_widget_value (wv);
251 static widget_value *
252 copy_widget_value_tree (val, change)
253 widget_value* val;
254 change_type change;
256 widget_value* copy;
258 if (!val)
259 return NULL;
260 if (val == (widget_value *) 1)
261 return val;
263 copy = malloc_widget_value ();
264 copy->name = safe_strdup (val->name);
265 copy->value = safe_strdup (val->value);
266 copy->key = safe_strdup (val->key);
267 copy->help = val->help;
268 copy->enabled = val->enabled;
269 copy->button_type = val->button_type;
270 copy->selected = val->selected;
271 copy->edited = False;
272 copy->change = change;
273 copy->this_one_change = change;
274 copy->contents = copy_widget_value_tree (val->contents, change);
275 copy->call_data = val->call_data;
276 copy->next = copy_widget_value_tree (val->next, change);
277 copy->toolkit_data = NULL;
278 copy->free_toolkit_data = False;
279 return copy;
282 static widget_info *
283 allocate_widget_info (type, name, id, val, pre_activate_cb,
284 selection_cb, post_activate_cb, highlight_cb)
285 char* type;
286 char* name;
287 LWLIB_ID id;
288 widget_value* val;
289 lw_callback pre_activate_cb;
290 lw_callback selection_cb;
291 lw_callback post_activate_cb;
292 lw_callback highlight_cb;
294 widget_info* info = (widget_info*)malloc (sizeof (widget_info));
295 info->type = safe_strdup (type);
296 info->name = safe_strdup (name);
297 info->id = id;
298 info->val = copy_widget_value_tree (val, STRUCTURAL_CHANGE);
299 info->busy = False;
300 info->pre_activate_cb = pre_activate_cb;
301 info->selection_cb = selection_cb;
302 info->post_activate_cb = post_activate_cb;
303 info->highlight_cb = highlight_cb;
304 info->instances = NULL;
306 info->next = all_widget_info;
307 all_widget_info = info;
309 return info;
312 static void
313 free_widget_info (info)
314 widget_info* info;
316 safe_free_str (info->type);
317 safe_free_str (info->name);
318 free_widget_value_tree (info->val);
319 lwlib_memset ((void*)info, 0xDEADBEEF, sizeof (widget_info));
320 free (info);
323 static void
324 mark_widget_destroyed (widget, closure, call_data)
325 Widget widget;
326 XtPointer closure;
327 XtPointer call_data;
329 widget_instance* instance = (widget_instance*)closure;
331 /* be very conservative */
332 if (instance->widget == widget)
333 instance->widget = NULL;
336 /* The messy #ifdef PROTOTYPES here and elsewhere are prompted by a
337 flood of warnings about argument promotion from proprietary ISO C
338 compilers. (etags still only makes one entry for each function.) */
339 static widget_instance *
340 #ifdef PROTOTYPES
341 allocate_widget_instance (widget_info* info, Widget parent, Boolean pop_up_p)
342 #else
343 allocate_widget_instance (info, parent, pop_up_p)
344 widget_info* info;
345 Widget parent;
346 Boolean pop_up_p;
347 #endif
349 widget_instance* instance =
350 (widget_instance*)malloc (sizeof (widget_instance));
351 bzero (instance, sizeof *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;
358 instantiate_widget_instance (instance);
360 XtAddCallback (instance->widget, XtNdestroyCallback,
361 mark_widget_destroyed, (XtPointer)instance);
362 return instance;
365 static void
366 free_widget_instance (instance)
367 widget_instance* instance;
369 lwlib_memset ((void*)instance, 0xDEADBEEF, sizeof (widget_instance));
370 free (instance);
373 static widget_info *
374 #ifdef PROTOTYPES
375 get_widget_info (LWLIB_ID id, Boolean remove_p)
376 #else
377 get_widget_info (id, remove_p)
378 LWLIB_ID id;
379 Boolean remove_p;
380 #endif
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)
389 if (remove_p)
391 if (prev)
392 prev->next = info->next;
393 else
394 all_widget_info = info->next;
396 return info;
398 return NULL;
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;
407 return get_widget_info (id, 0);
410 static widget_instance *
411 #ifdef PROTOTYPES
412 get_widget_instance (Widget widget, Boolean remove_p)
413 #else
414 get_widget_instance (widget, remove_p)
415 Widget widget;
416 Boolean remove_p;
417 #endif
419 widget_info* info;
420 widget_instance* instance;
421 widget_instance* prev;
422 for (info = all_widget_info; info; info = info->next)
423 for (prev = NULL, instance = info->instances;
424 instance;
425 prev = instance, instance = instance->next)
426 if (instance->widget == widget)
428 if (remove_p)
430 if (prev)
431 prev->next = instance->next;
432 else
433 info->instances = instance->next;
435 return instance;
437 return (widget_instance *) 0;
440 /* Value is a pointer to the widget_instance corresponding to
441 WIDGET, or null if WIDGET is not a lwlib widget. */
443 widget_instance *
444 lw_get_widget_instance (widget)
445 Widget widget;
447 return get_widget_instance (widget, False);
450 static widget_instance*
451 #ifdef PROTOTYPES
452 find_instance (LWLIB_ID id, Widget parent, Boolean pop_up_p)
453 #else
454 find_instance (id, parent, pop_up_p)
455 LWLIB_ID id;
456 Widget parent;
457 Boolean pop_up_p;
458 #endif
460 widget_info* info = get_widget_info (id, False);
461 widget_instance* instance;
463 if (info)
464 for (instance = info->instances; instance; instance = instance->next)
465 if (instance->parent == parent && instance->pop_up_p == pop_up_p)
466 return instance;
468 return NULL;
472 /* utility function for widget_value */
473 static Boolean
474 safe_strcmp (s1, s2)
475 char* s1;
476 char* s2;
478 if (!!s1 ^ !!s2) return True;
479 return (s1 && s2) ? strcmp (s1, s2) : s1 ? False : !!s2;
483 #if 0
484 # define EXPLAIN(name, oc, nc, desc, a1, a2) \
485 printf ("Change: \"%s\"\tmax(%s=%d,%s=%d)\t%s %d %d\n", \
486 name, \
487 (oc == NO_CHANGE ? "none" : \
488 (oc == INVISIBLE_CHANGE ? "invisible" : \
489 (oc == VISIBLE_CHANGE ? "visible" : \
490 (oc == STRUCTURAL_CHANGE ? "structural" : "???")))), \
491 oc, \
492 (nc == NO_CHANGE ? "none" : \
493 (nc == INVISIBLE_CHANGE ? "invisible" : \
494 (nc == VISIBLE_CHANGE ? "visible" : \
495 (nc == STRUCTURAL_CHANGE ? "structural" : "???")))), \
496 nc, desc, a1, a2)
497 #else
498 # define EXPLAIN(name, oc, nc, desc, a1, a2)
499 #endif
502 static widget_value *
503 merge_widget_value (val1, val2, level, change_p)
504 widget_value* val1;
505 widget_value* val2;
506 int level;
507 int *change_p;
509 change_type change, this_one_change;
510 widget_value* merged_next;
511 widget_value* merged_contents;
513 if (!val1)
515 if (val2)
517 *change_p = 1;
518 return copy_widget_value_tree (val2, STRUCTURAL_CHANGE);
520 else
521 return NULL;
523 if (!val2)
525 *change_p = 1;
526 free_widget_value_tree (val1);
527 return NULL;
530 change = NO_CHANGE;
532 if (safe_strcmp (val1->name, val2->name))
534 EXPLAIN (val1->name, change, STRUCTURAL_CHANGE, "name change",
535 val1->name, val2->name);
536 change = max (change, STRUCTURAL_CHANGE);
537 safe_free_str (val1->name);
538 val1->name = safe_strdup (val2->name);
540 if (safe_strcmp (val1->value, val2->value))
542 EXPLAIN (val1->name, change, VISIBLE_CHANGE, "value change",
543 val1->value, val2->value);
544 change = max (change, VISIBLE_CHANGE);
545 safe_free_str (val1->value);
546 val1->value = safe_strdup (val2->value);
548 if (safe_strcmp (val1->key, val2->key))
550 EXPLAIN (val1->name, change, VISIBLE_CHANGE, "key change",
551 val1->key, val2->key);
552 change = max (change, VISIBLE_CHANGE);
553 safe_free_str (val1->key);
554 val1->key = safe_strdup (val2->key);
556 if (! EQ (val1->help, val2->help))
558 EXPLAIN (val1->name, change, VISIBLE_CHANGE, "help change",
559 val1->help, val2->help);
560 change = max (change, VISIBLE_CHANGE);
561 val1->help = val2->help;
563 if (val1->enabled != val2->enabled)
565 EXPLAIN (val1->name, change, VISIBLE_CHANGE, "enablement change",
566 val1->enabled, val2->enabled);
567 change = max (change, VISIBLE_CHANGE);
568 val1->enabled = val2->enabled;
570 if (val1->button_type != val2->button_type)
572 EXPLAIN (val1->name, change, VISIBLE_CHANGE, "button type change",
573 val1->button_type, val2->button_type);
574 change = max (change, VISIBLE_CHANGE);
575 val1->button_type = val2->button_type;
577 if (val1->selected != val2->selected)
579 EXPLAIN (val1->name, change, VISIBLE_CHANGE, "selection change",
580 val1->selected, val2->selected);
581 change = max (change, VISIBLE_CHANGE);
582 val1->selected = val2->selected;
584 if (val1->call_data != val2->call_data)
586 EXPLAIN (val1->name, change, INVISIBLE_CHANGE, "call-data change",
587 val1->call_data, val2->call_data);
588 change = max (change, INVISIBLE_CHANGE);
589 val1->call_data = val2->call_data;
592 if (level > 0)
594 merged_contents =
595 merge_widget_value (val1->contents, val2->contents, level - 1,
596 change_p);
598 if (val1->contents && !merged_contents)
600 /* This used to say INVISIBLE_CHANGE,
601 but it is visible and vitally important when
602 the contents of the menu bar itself are entirely deleted.
604 But maybe it doesn't matter. This fails to fix the bug. */
605 EXPLAIN (val1->name, change, STRUCTURAL_CHANGE, "(contents gone)",
606 0, 0);
607 change = max (change, STRUCTURAL_CHANGE);
609 else if (merged_contents && merged_contents->change != NO_CHANGE)
611 EXPLAIN (val1->name, change, INVISIBLE_CHANGE, "(contents change)",
612 0, 0);
613 change = max (change, INVISIBLE_CHANGE);
614 #if 0 /* This was replaced by the August 9 1996 change in lwlib-Xm.c. */
615 #ifdef USE_MOTIF
616 change = max (merged_contents->change, change);
617 #endif
618 #endif
621 val1->contents = merged_contents;
624 this_one_change = change;
626 merged_next = merge_widget_value (val1->next, val2->next, level, change_p);
628 if (val1->next && !merged_next)
630 EXPLAIN (val1->name, change, STRUCTURAL_CHANGE, "(following gone)",
631 0, 0);
632 change = max (change, STRUCTURAL_CHANGE);
634 else if (merged_next)
636 if (merged_next->change)
637 EXPLAIN (val1->name, change, merged_next->change, "(following change)",
638 0, 0);
639 change = max (change, merged_next->change);
642 val1->next = merged_next;
644 val1->this_one_change = this_one_change;
645 val1->change = change;
647 if (change > NO_CHANGE && val1->toolkit_data)
649 *change_p = 1;
650 if (val1->free_toolkit_data)
651 XtFree (val1->toolkit_data);
652 val1->toolkit_data = NULL;
655 return val1;
659 /* modifying the widgets */
660 static Widget
661 name_to_widget (instance, name)
662 widget_instance* instance;
663 char* name;
665 Widget widget = NULL;
667 if (!instance->widget)
668 return NULL;
670 if (!strcmp (XtName (instance->widget), name))
671 widget = instance->widget;
672 else
674 int length = strlen (name) + 2;
675 char* real_name = (char *) xmalloc (length);
676 real_name [0] = '*';
677 strcpy (real_name + 1, name);
679 widget = XtNameToWidget (instance->widget, real_name);
681 free (real_name);
683 return widget;
686 static void
687 #ifdef PROTOTYPES
688 set_one_value (widget_instance* instance, widget_value* val, Boolean deep_p)
689 #else
690 set_one_value (instance, val, deep_p)
691 widget_instance* instance;
692 widget_value* val;
693 Boolean deep_p;
694 #endif
696 Widget widget = name_to_widget (instance, val->name);
698 if (widget)
700 #if defined (USE_LUCID)
701 if (lw_lucid_widget_p (instance->widget))
702 xlw_update_one_widget (instance, widget, val, deep_p);
703 #endif
704 #if defined (USE_MOTIF)
705 if (lw_motif_widget_p (instance->widget))
706 xm_update_one_widget (instance, widget, val, deep_p);
707 #endif
708 #if defined (USE_XAW)
709 if (lw_xaw_widget_p (instance->widget))
710 xaw_update_one_widget (instance, widget, val, deep_p);
711 #endif
715 static void
716 #ifdef PROTOTYPES
717 update_one_widget_instance (widget_instance* instance, Boolean deep_p)
718 #else
719 update_one_widget_instance (instance, deep_p)
720 widget_instance* instance;
721 Boolean deep_p;
722 #endif
724 widget_value *val;
726 if (!instance->widget)
727 /* the widget was destroyed */
728 return;
730 for (val = instance->info->val; val; val = val->next)
731 if (val->change != NO_CHANGE)
732 set_one_value (instance, val, deep_p);
735 static void
736 #ifdef PROTOTYPES
737 update_all_widget_values (widget_info* info, Boolean deep_p)
738 #else
739 update_all_widget_values (info, deep_p)
740 widget_info* info;
741 Boolean deep_p;
742 #endif
744 widget_instance* instance;
745 widget_value* val;
747 for (instance = info->instances; instance; instance = instance->next)
748 update_one_widget_instance (instance, deep_p);
750 for (val = info->val; val; val = val->next)
751 val->change = NO_CHANGE;
755 #ifdef PROTOTYPES
756 lw_modify_all_widgets (LWLIB_ID id, widget_value* val, Boolean deep_p)
757 #else
758 lw_modify_all_widgets (id, val, deep_p)
759 LWLIB_ID id;
760 widget_value* val;
761 Boolean deep_p;
762 #endif
764 widget_info* info = get_widget_info (id, False);
765 widget_value* new_val;
766 widget_value* next_new_val;
767 widget_value* cur;
768 widget_value* prev;
769 widget_value* next;
770 int found;
771 int change_p = 0;
773 if (!info)
774 return 0;
776 for (new_val = val; new_val; new_val = new_val->next)
778 next_new_val = new_val->next;
779 new_val->next = NULL;
780 found = False;
781 for (prev = NULL, cur = info->val; cur; prev = cur, cur = cur->next)
782 if (!strcmp (cur->name, new_val->name))
784 found = True;
785 next = cur->next;
786 cur->next = NULL;
787 cur = merge_widget_value (cur, new_val, deep_p ? 1000 : 1,
788 &change_p);
789 if (prev)
790 prev->next = cur ? cur : next;
791 else
792 info->val = cur ? cur : next;
793 if (cur)
794 cur->next = next;
795 break;
797 if (!found)
799 /* Could not find it, add it */
800 if (prev)
801 prev->next = copy_widget_value_tree (new_val, STRUCTURAL_CHANGE);
802 else
803 info->val = copy_widget_value_tree (new_val, STRUCTURAL_CHANGE);
804 change_p = 1;
806 new_val->next = next_new_val;
809 update_all_widget_values (info, deep_p);
810 return change_p;
814 /* creating the widgets */
816 static void
817 initialize_widget_instance (instance)
818 widget_instance* instance;
820 widget_value* val;
822 for (val = instance->info->val; val; val = val->next)
823 val->change = STRUCTURAL_CHANGE;
825 update_one_widget_instance (instance, True);
827 for (val = instance->info->val; val; val = val->next)
828 val->change = NO_CHANGE;
832 static widget_creation_function
833 find_in_table (type, table)
834 char* type;
835 widget_creation_entry* table;
837 widget_creation_entry* cur;
838 for (cur = table; cur->type; cur++)
839 if (!my_strcasecmp (type, cur->type))
840 return cur->function;
841 return NULL;
844 static Boolean
845 dialog_spec_p (name)
846 char* name;
848 /* return True if name matches [EILPQeilpq][1-9][Bb] or
849 [EILPQeilpq][1-9][Bb][Rr][1-9] */
850 if (!name)
851 return False;
853 switch (name [0])
855 case 'E': case 'I': case 'L': case 'P': case 'Q':
856 case 'e': case 'i': case 'l': case 'p': case 'q':
857 if (name [1] >= '0' && name [1] <= '9')
859 if (name [2] != 'B' && name [2] != 'b')
860 return False;
861 if (!name [3])
862 return True;
863 if ((name [3] == 'T' || name [3] == 't') && !name [4])
864 return True;
865 if ((name [3] == 'R' || name [3] == 'r')
866 && name [4] >= '0' && name [4] <= '9' && !name [5])
867 return True;
868 return False;
870 else
871 return False;
873 default:
874 return False;
878 static void
879 instantiate_widget_instance (instance)
880 widget_instance* instance;
882 widget_creation_function function = NULL;
884 #if defined (USE_LUCID)
885 if (!function)
886 function = find_in_table (instance->info->type, xlw_creation_table);
887 #endif
888 #if defined(USE_MOTIF)
889 if (!function)
890 function = find_in_table (instance->info->type, xm_creation_table);
891 #endif
892 #if defined (USE_XAW)
893 if (!function)
894 function = find_in_table (instance->info->type, xaw_creation_table);
895 #endif
897 if (!function)
899 if (dialog_spec_p (instance->info->type))
901 #if defined (USE_LUCID)
902 /* not yet */
903 #endif
904 #if defined(USE_MOTIF)
905 if (!function)
906 function = xm_create_dialog;
907 #endif
908 #if defined (USE_XAW)
909 if (!function)
910 function = xaw_create_dialog;
911 #endif
915 if (!function)
917 printf ("No creation function for widget type %s\n",
918 instance->info->type);
919 abort ();
922 instance->widget = (*function) (instance);
924 if (!instance->widget)
925 abort ();
927 /* XtRealizeWidget (instance->widget);*/
930 void
931 lw_register_widget (type, name, id, val, pre_activate_cb,
932 selection_cb, post_activate_cb, highlight_cb)
933 char* type;
934 char* name;
935 LWLIB_ID id;
936 widget_value* val;
937 lw_callback pre_activate_cb;
938 lw_callback selection_cb;
939 lw_callback post_activate_cb;
940 lw_callback highlight_cb;
942 if (!get_widget_info (id, False))
943 allocate_widget_info (type, name, id, val, pre_activate_cb, selection_cb,
944 post_activate_cb, highlight_cb);
947 Widget
948 #ifdef PROTOTYPES
949 lw_get_widget (LWLIB_ID id, Widget parent, Boolean pop_up_p)
950 #else
951 lw_get_widget (id, parent, pop_up_p)
952 LWLIB_ID id;
953 Widget parent;
954 Boolean pop_up_p;
955 #endif
957 widget_instance* instance;
959 instance = find_instance (id, parent, pop_up_p);
960 return instance ? instance->widget : NULL;
963 Widget
964 #ifdef PROTOTYPES
965 lw_make_widget (LWLIB_ID id, Widget parent, Boolean pop_up_p)
966 #else
967 lw_make_widget (id, parent, pop_up_p)
968 LWLIB_ID id;
969 Widget parent;
970 Boolean pop_up_p;
971 #endif
973 widget_instance* instance;
974 widget_info* info;
976 instance = find_instance (id, parent, pop_up_p);
977 if (!instance)
979 info = get_widget_info (id, False);
980 if (!info)
981 return NULL;
982 instance = allocate_widget_instance (info, parent, pop_up_p);
983 initialize_widget_instance (instance);
985 if (!instance->widget)
986 abort ();
987 return instance->widget;
990 Widget
991 #ifdef PROTOTYPES
992 lw_create_widget (char* type, char* name, LWLIB_ID id, widget_value* val,
993 Widget parent, Boolean pop_up_p,
994 lw_callback pre_activate_cb, lw_callback selection_cb,
995 lw_callback post_activate_cb, lw_callback highlight_cb)
996 #else
997 lw_create_widget (type, name, id, val, parent, pop_up_p, pre_activate_cb,
998 selection_cb, post_activate_cb, highlight_cb)
999 char* type;
1000 char* name;
1001 LWLIB_ID id;
1002 widget_value* val;
1003 Widget parent;
1004 Boolean pop_up_p;
1005 lw_callback pre_activate_cb;
1006 lw_callback selection_cb;
1007 lw_callback post_activate_cb;
1008 lw_callback highlight_cb;
1009 #endif
1011 lw_register_widget (type, name, id, val, pre_activate_cb, selection_cb,
1012 post_activate_cb, highlight_cb);
1013 return lw_make_widget (id, parent, pop_up_p);
1017 /* destroying the widgets */
1018 static void
1019 destroy_one_instance (instance)
1020 widget_instance* instance;
1022 /* Remove the destroy callback on the widget; that callback will try to
1023 dereference the instance object (to set its widget slot to 0, since the
1024 widget is dead.) Since the instance is now dead, we don't have to worry
1025 about the fact that its widget is dead too.
1027 This happens in the Phase2Destroy of the widget, so this callback would
1028 not have been run until arbitrarily long after the instance was freed.
1030 if (instance->widget)
1031 XtRemoveCallback (instance->widget, XtNdestroyCallback,
1032 mark_widget_destroyed, (XtPointer)instance);
1034 if (instance->widget)
1036 /* The else are pretty tricky here, including the empty statement
1037 at the end because it would be very bad to destroy a widget
1038 twice. */
1039 #if defined (USE_LUCID)
1040 if (lw_lucid_widget_p (instance->widget))
1041 xlw_destroy_instance (instance);
1042 else
1043 #endif
1044 #if defined (USE_MOTIF)
1045 if (lw_motif_widget_p (instance->widget))
1046 xm_destroy_instance (instance);
1047 else
1048 #endif
1049 #if defined (USE_XAW)
1050 if (lw_xaw_widget_p (instance->widget))
1051 xaw_destroy_instance (instance);
1052 else
1053 #endif
1054 /* do not remove the empty statement */
1058 free_widget_instance (instance);
1061 void
1062 lw_destroy_widget (w)
1063 Widget w;
1065 widget_instance* instance = get_widget_instance (w, True);
1067 if (instance)
1069 widget_info *info = instance->info;
1070 /* instance has already been removed from the list; free it */
1071 destroy_one_instance (instance);
1072 /* if there are no instances left, free the info too */
1073 if (!info->instances)
1074 lw_destroy_all_widgets (info->id);
1078 void
1079 lw_destroy_all_widgets (id)
1080 LWLIB_ID id;
1082 widget_info* info = get_widget_info (id, True);
1083 widget_instance* instance;
1084 widget_instance* next;
1086 if (info)
1088 for (instance = info->instances; instance; )
1090 next = instance->next;
1091 destroy_one_instance (instance);
1092 instance = next;
1094 free_widget_info (info);
1098 void
1099 lw_destroy_everything ()
1101 while (all_widget_info)
1102 lw_destroy_all_widgets (all_widget_info->id);
1105 void
1106 lw_destroy_all_pop_ups ()
1108 widget_info* info;
1109 widget_info* next;
1110 widget_instance* instance;
1112 for (info = all_widget_info; info; info = next)
1114 next = info->next;
1115 instance = info->instances;
1116 if (instance && instance->pop_up_p)
1117 lw_destroy_all_widgets (info->id);
1121 #ifdef USE_MOTIF
1122 extern Widget first_child (/* Widget */); /* garbage */
1123 #endif
1125 Widget
1126 lw_raise_all_pop_up_widgets ()
1128 widget_info* info;
1129 widget_instance* instance;
1130 Widget result = NULL;
1132 for (info = all_widget_info; info; info = info->next)
1133 for (instance = info->instances; instance; instance = instance->next)
1134 if (instance->pop_up_p)
1136 Widget widget = instance->widget;
1137 if (widget)
1139 if (XtIsManaged (widget)
1140 #ifdef USE_MOTIF
1141 /* What a complete load of crap!!!!
1142 When a dialogShell is on the screen, it is not managed!
1144 || (lw_motif_widget_p (instance->widget) &&
1145 XtIsManaged (first_child (widget)))
1146 #endif
1149 if (!result)
1150 result = widget;
1151 XMapRaised (XtDisplay (widget), XtWindow (widget));
1155 return result;
1158 static void
1159 #ifdef PROTOTYPES
1160 lw_pop_all_widgets (LWLIB_ID id, Boolean up)
1161 #else
1162 lw_pop_all_widgets (id, up)
1163 LWLIB_ID id;
1164 Boolean up;
1165 #endif
1167 widget_info* info = get_widget_info (id, False);
1168 widget_instance* instance;
1170 if (info)
1171 for (instance = info->instances; instance; instance = instance->next)
1172 if (instance->pop_up_p && instance->widget)
1174 #if defined (USE_LUCID)
1175 if (lw_lucid_widget_p (instance->widget))
1177 XtRealizeWidget (instance->widget);
1178 xlw_pop_instance (instance, up);
1180 #endif
1181 #if defined (USE_MOTIF)
1182 if (lw_motif_widget_p (instance->widget))
1184 XtRealizeWidget (instance->widget);
1185 xm_pop_instance (instance, up);
1187 #endif
1188 #if defined (USE_XAW)
1189 if (lw_xaw_widget_p (instance->widget))
1191 XtRealizeWidget (XtParent (instance->widget));
1192 XtRealizeWidget (instance->widget);
1193 xaw_pop_instance (instance, up);
1195 #endif
1199 void
1200 lw_pop_up_all_widgets (id)
1201 LWLIB_ID id;
1203 lw_pop_all_widgets (id, True);
1206 void
1207 lw_pop_down_all_widgets (id)
1208 LWLIB_ID id;
1210 lw_pop_all_widgets (id, False);
1213 void
1214 lw_popup_menu (widget, event)
1215 Widget widget;
1216 XEvent *event;
1218 #if defined (USE_LUCID)
1219 if (lw_lucid_widget_p (widget))
1220 xlw_popup_menu (widget, event);
1221 #endif
1222 #if defined (USE_MOTIF)
1223 if (lw_motif_widget_p (widget))
1224 xm_popup_menu (widget, event);
1225 #endif
1226 #if defined (USE_XAW)
1227 if (lw_xaw_widget_p (widget))
1228 xaw_popup_menu (widget, event);
1229 #endif
1232 \f/* get the values back */
1233 static Boolean
1234 get_one_value (instance, val)
1235 widget_instance* instance;
1236 widget_value* val;
1238 Widget widget = name_to_widget (instance, val->name);
1240 if (widget)
1242 #if defined (USE_LUCID)
1243 if (lw_lucid_widget_p (instance->widget))
1244 xlw_update_one_value (instance, widget, val);
1245 #endif
1246 #if defined (USE_MOTIF)
1247 if (lw_motif_widget_p (instance->widget))
1248 xm_update_one_value (instance, widget, val);
1249 #endif
1250 #if defined (USE_XAW)
1251 if (lw_xaw_widget_p (instance->widget))
1252 xaw_update_one_value (instance, widget, val);
1253 #endif
1254 return True;
1256 else
1257 return False;
1260 Boolean
1261 lw_get_some_values (id, val_out)
1262 LWLIB_ID id;
1263 widget_value* val_out;
1265 widget_info* info = get_widget_info (id, False);
1266 widget_instance* instance;
1267 widget_value* val;
1268 Boolean result = False;
1270 if (!info)
1271 return False;
1273 instance = info->instances;
1274 if (!instance)
1275 return False;
1277 for (val = val_out; val; val = val->next)
1278 if (get_one_value (instance, val))
1279 result = True;
1281 return result;
1284 widget_value*
1285 lw_get_all_values (id)
1286 LWLIB_ID id;
1288 widget_info* info = get_widget_info (id, False);
1289 widget_value* val = info->val;
1290 if (lw_get_some_values (id, val))
1291 return val;
1292 else
1293 return NULL;
1296 /* internal function used by the library dependent implementation to get the
1297 widget_value for a given widget in an instance */
1298 widget_value*
1299 lw_get_widget_value_for_widget (instance, w)
1300 widget_instance* instance;
1301 Widget w;
1303 char* name = XtName (w);
1304 widget_value* cur;
1305 for (cur = instance->info->val; cur; cur = cur->next)
1306 if (!strcmp (cur->name, name))
1307 return cur;
1308 return NULL;
1311 \f/* update other instances value when one thing changed */
1313 /* To forbid recursive calls */
1314 static Boolean lwlib_updating;
1316 /* This function can be used as a an XtCallback for the widgets that get
1317 modified to update other instances of the widgets. Closure should be the
1318 widget_instance. */
1319 void
1320 lw_internal_update_other_instances (widget, closure, call_data)
1321 Widget widget;
1322 XtPointer closure;
1323 XtPointer call_data;
1325 widget_instance* instance = (widget_instance*)closure;
1326 char* name = XtName (widget);
1327 widget_info* info;
1328 widget_instance* cur;
1329 widget_value* val;
1331 /* Avoid possibly infinite recursion. */
1332 if (lwlib_updating)
1333 return;
1335 /* protect against the widget being destroyed */
1336 if (XtWidgetBeingDestroyedP (widget))
1337 return;
1339 /* Return immediately if there are no other instances */
1340 info = instance->info;
1341 if (!info->instances->next)
1342 return;
1344 lwlib_updating = True;
1346 for (val = info->val; val && strcmp (val->name, name); val = val->next);
1348 if (val && get_one_value (instance, val))
1349 for (cur = info->instances; cur; cur = cur->next)
1350 if (cur != instance)
1351 set_one_value (cur, val, True);
1353 lwlib_updating = False;
1357 \f/* get the id */
1359 LWLIB_ID
1360 lw_get_widget_id (w)
1361 Widget w;
1363 widget_instance* instance = get_widget_instance (w, False);
1365 return instance ? instance->info->id : 0;
1368 \f/* set the keyboard focus */
1369 void
1370 lw_set_keyboard_focus (parent, w)
1371 Widget parent;
1372 Widget w;
1374 #if defined (USE_MOTIF)
1375 xm_set_keyboard_focus (parent, w);
1376 #else
1377 XtSetKeyboardFocus (parent, w);
1378 #endif
1381 \f/* Show busy */
1382 static void
1383 #ifdef PROTOTYPES
1384 show_one_widget_busy (Widget w, Boolean flag)
1385 #else
1386 show_one_widget_busy (w, flag)
1387 Widget w;
1388 Boolean flag;
1389 #endif
1391 Pixel foreground = 0;
1392 Pixel background = 1;
1393 Widget widget_to_invert = XtNameToWidget (w, "*sheet");
1394 if (!widget_to_invert)
1395 widget_to_invert = w;
1397 XtVaGetValues (widget_to_invert,
1398 XtNforeground, &foreground,
1399 XtNbackground, &background,
1400 NULL);
1401 XtVaSetValues (widget_to_invert,
1402 XtNforeground, background,
1403 XtNbackground, foreground,
1404 NULL);
1407 void
1408 #ifdef PROTOTYPES
1409 lw_show_busy (Widget w, Boolean busy)
1410 #else
1411 lw_show_busy (w, busy)
1412 Widget w;
1413 Boolean busy;
1414 #endif
1416 widget_instance* instance = get_widget_instance (w, False);
1417 widget_info* info;
1418 widget_instance* next;
1420 if (instance)
1422 info = instance->info;
1423 if (info->busy != busy)
1425 for (next = info->instances; next; next = next->next)
1426 if (next->widget)
1427 show_one_widget_busy (next->widget, busy);
1428 info->busy = busy;
1433 /* This hack exists because Lucid/Athena need to execute the strange
1434 function below to support geometry management. */
1435 void
1436 #ifdef PROTOTYPES
1437 lw_refigure_widget (Widget w, Boolean doit)
1438 #else
1439 lw_refigure_widget (w, doit)
1440 Widget w;
1441 Boolean doit;
1442 #endif
1444 #if defined (USE_XAW)
1445 XawPanedSetRefigureMode (w, doit);
1446 #endif
1447 #if defined (USE_MOTIF)
1448 if (doit)
1449 XtManageChild (w);
1450 else
1451 XtUnmanageChild (w);
1452 #endif
1455 /* Toolkit independent way of determining if an event window is in the
1456 menubar. */
1457 Boolean
1458 lw_window_is_in_menubar (win, menubar_widget)
1459 Window win;
1460 Widget menubar_widget;
1462 return menubar_widget
1463 #if defined (USE_LUCID)
1464 && XtWindow (menubar_widget) == win;
1465 #endif
1466 #if defined (USE_MOTIF)
1467 && ((XtWindow (menubar_widget) == win)
1468 || (XtWindowToWidget (XtDisplay (menubar_widget), win)
1469 && (XtParent (XtWindowToWidget (XtDisplay (menubar_widget), win))
1470 == menubar_widget)));
1471 #endif
1474 /* Motif hack to set the main window areas. */
1475 void
1476 lw_set_main_areas (parent, menubar, work_area)
1477 Widget parent;
1478 Widget menubar;
1479 Widget work_area;
1481 #if defined (USE_MOTIF)
1482 xm_set_main_areas (parent, menubar, work_area);
1483 #endif
1486 /* Manage resizing for Motif. This disables resizing when the menubar
1487 is about to be modified. */
1488 void
1489 #ifdef PROTOTYPES
1490 lw_allow_resizing (Widget w, Boolean flag)
1491 #else
1492 lw_allow_resizing (w, flag)
1493 Widget w;
1494 Boolean flag;
1495 #endif
1497 #if defined (USE_MOTIF)
1498 xm_manage_resizing (w, flag);
1499 #endif
1503 /* Value is non-zero if LABEL is a menu separator. If it is, *TYPE is
1504 set to an appropriate enumerator of type enum menu_separator.
1505 MOTIF_P non-zero means map separator types not supported by Motif
1506 to similar ones that are supported. */
1509 lw_separator_p (label, type, motif_p)
1510 char *label;
1511 enum menu_separator *type;
1512 int motif_p;
1514 int separator_p = 0;
1516 if (strlen (label) >= 3
1517 && bcmp (label, "--:", 3) == 0)
1519 static struct separator_table
1521 char *name;
1522 enum menu_separator type;
1524 separator_names[] =
1526 {"space", SEPARATOR_NO_LINE},
1527 {"noLine", SEPARATOR_NO_LINE},
1528 {"singleLine", SEPARATOR_SINGLE_LINE},
1529 {"doubleLine", SEPARATOR_DOUBLE_LINE},
1530 {"singleDashedLine", SEPARATOR_SINGLE_DASHED_LINE},
1531 {"doubleDashedLine", SEPARATOR_DOUBLE_DASHED_LINE},
1532 {"shadowEtchedIn", SEPARATOR_SHADOW_ETCHED_IN},
1533 {"shadowEtchedOut", SEPARATOR_SHADOW_ETCHED_OUT},
1534 {"shadowEtchedInDash", SEPARATOR_SHADOW_ETCHED_IN_DASH},
1535 {"shadowEtchedOutDash", SEPARATOR_SHADOW_ETCHED_OUT_DASH},
1536 {"shadowDoubleEtchedIn", SEPARATOR_SHADOW_DOUBLE_ETCHED_IN},
1537 {"shadowDoubleEtchedOut", SEPARATOR_SHADOW_DOUBLE_ETCHED_OUT},
1538 {"shadowDoubleEtchedInDash", SEPARATOR_SHADOW_DOUBLE_ETCHED_IN_DASH},
1539 {"shadowDoubleEtchedOutDash", SEPARATOR_SHADOW_DOUBLE_ETCHED_OUT_DASH},
1540 {0,0}
1543 int i;
1545 label += 3;
1546 for (i = 0; separator_names[i].name; ++i)
1547 if (strcmp (label, separator_names[i].name) == 0)
1549 separator_p = 1;
1550 *type = separator_names[i].type;
1552 /* If separator type is not supported under Motif,
1553 use a similar one. */
1554 if (motif_p && *type >= SEPARATOR_SHADOW_DOUBLE_ETCHED_IN)
1555 *type -= 4;
1556 break;
1559 else if (strlen (label) > 3
1560 && bcmp (label, "--", 2) == 0
1561 && label[2] != '-')
1563 /* Alternative, more Emacs-style names. */
1564 static struct separator_table
1566 char *name;
1567 enum menu_separator type;
1569 separator_names[] =
1571 {"space", SEPARATOR_NO_LINE},
1572 {"no-line", SEPARATOR_NO_LINE},
1573 {"single-line", SEPARATOR_SINGLE_LINE},
1574 {"double-line", SEPARATOR_DOUBLE_LINE},
1575 {"single-dashed-line", SEPARATOR_SINGLE_DASHED_LINE},
1576 {"double-dashed-line", SEPARATOR_DOUBLE_DASHED_LINE},
1577 {"shadow-etched-in", SEPARATOR_SHADOW_ETCHED_IN},
1578 {"shadow-etched-out", SEPARATOR_SHADOW_ETCHED_OUT},
1579 {"shadow-etched-in-dash", SEPARATOR_SHADOW_ETCHED_IN_DASH},
1580 {"shadow-etched-out-dash", SEPARATOR_SHADOW_ETCHED_OUT_DASH},
1581 {"shadow-double-etched-in", SEPARATOR_SHADOW_DOUBLE_ETCHED_IN},
1582 {"shadow-double-etched-out", SEPARATOR_SHADOW_DOUBLE_ETCHED_OUT},
1583 {"shadow-double-etched-in-dash", SEPARATOR_SHADOW_DOUBLE_ETCHED_IN_DASH},
1584 {"shadow-double-etched-out-dash",SEPARATOR_SHADOW_DOUBLE_ETCHED_OUT_DASH},
1585 {0,0}
1588 int i;
1590 label += 2;
1591 for (i = 0; separator_names[i].name; ++i)
1592 if (strcmp (label, separator_names[i].name) == 0)
1594 separator_p = 1;
1595 *type = separator_names[i].type;
1597 /* If separator type is not supported under Motif,
1598 use a similar one. */
1599 if (motif_p && *type >= SEPARATOR_SHADOW_DOUBLE_ETCHED_IN)
1600 *type -= 4;
1601 break;
1604 else
1606 /* Old-style separator, maybe. It's a separator if it contains
1607 only dashes. */
1608 while (*label == '-')
1609 ++label;
1610 separator_p = *label == 0;
1611 *type = SEPARATOR_SHADOW_ETCHED_IN;
1614 return separator_p;
1617 /* arch-tag: 3d730f36-a441-4a71-9971-48ef3b5a4d9f
1618 (do not change this comment) */