(solar-moment, solar-exact-local-noon)
[emacs.git] / lwlib / lwlib.c
blob7b2752b82e9df66c083f65040a049411f9cc8371
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 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 NeXT
24 #undef __STRICT_BSD__ /* ick */
25 #endif
27 #ifdef HAVE_CONFIG_H
28 #include <config.h>
29 #endif
31 #include "../src/lisp.h"
33 #include <sys/types.h>
34 #include <stdio.h>
35 #include <ctype.h>
36 #include "lwlib-int.h"
37 #include "lwlib-utils.h"
38 #include <X11/StringDefs.h>
40 #if defined (USE_LUCID)
41 #include "lwlib-Xlw.h"
42 #endif
43 #if defined (USE_MOTIF)
44 #include "lwlib-Xm.h"
45 #else /* not USE_MOTIF */
46 #if defined (USE_LUCID)
47 #define USE_XAW
48 #endif /* not USE_MOTIF && USE_LUCID */
49 #endif
50 #if defined (USE_XAW)
51 #ifdef HAVE_XAW3D
52 #include <X11/Xaw3d/Paned.h>
53 #else /* !HAVE_XAW3D */
54 #include <X11/Xaw/Paned.h>
55 #endif /* HAVE_XAW3D */
56 #include "lwlib-Xaw.h"
57 #endif
59 #if !defined (USE_LUCID) && !defined (USE_MOTIF)
60 #error At least one of USE_LUCID or USE_MOTIF must be defined.
61 #endif
63 #ifndef max
64 #define max(x, y) ((x) > (y) ? (x) : (y))
65 #endif
67 /* List of all widgets managed by the library. */
68 static widget_info*
69 all_widget_info = NULL;
71 #ifdef USE_MOTIF
72 char *lwlib_toolkit_type = "motif";
73 #else
74 char *lwlib_toolkit_type = "lucid";
75 #endif
77 static widget_value *merge_widget_value P_ ((widget_value *,
78 widget_value *,
79 int, int *));
80 static void instantiate_widget_instance P_ ((widget_instance *));
81 static int my_strcasecmp P_ ((char *, char *));
82 static void safe_free_str P_ ((char *));
83 static void free_widget_value_tree P_ ((widget_value *));
84 static widget_value *copy_widget_value_tree P_ ((widget_value *,
85 change_type));
86 static widget_info *allocate_widget_info P_ ((char *, char *, LWLIB_ID,
87 widget_value *,
88 lw_callback, lw_callback,
89 lw_callback, lw_callback));
90 static void free_widget_info P_ ((widget_info *));
91 static void mark_widget_destroyed P_ ((Widget, XtPointer, XtPointer));
92 static widget_instance *allocate_widget_instance P_ ((widget_info *,
93 Widget, Boolean));
94 static void free_widget_instance P_ ((widget_instance *));
95 static widget_info *get_widget_info P_ ((LWLIB_ID, Boolean));
96 static widget_instance *get_widget_instance P_ ((Widget, Boolean));
97 static widget_instance *find_instance P_ ((LWLIB_ID, Widget, Boolean));
98 static Boolean safe_strcmp P_ ((char *, char *));
99 static Widget name_to_widget P_ ((widget_instance *, char *));
100 static void set_one_value P_ ((widget_instance *, widget_value *, Boolean));
101 static void update_one_widget_instance P_ ((widget_instance *, Boolean));
102 static void update_all_widget_values P_ ((widget_info *, Boolean));
103 static void initialize_widget_instance P_ ((widget_instance *));
104 static widget_creation_function find_in_table P_ ((char *, widget_creation_entry *));
105 static Boolean dialog_spec_p P_ ((char *));
106 static void destroy_one_instance P_ ((widget_instance *));
107 static void lw_pop_all_widgets P_ ((LWLIB_ID, Boolean));
108 static Boolean get_one_value P_ ((widget_instance *, widget_value *));
109 static void show_one_widget_busy P_ ((Widget, Boolean));
111 void
112 lwlib_memset (address, value, length)
113 char *address;
114 int value;
115 size_t length;
117 int i;
119 for (i = 0; i < length; i++)
120 address[i] = value;
123 void
124 lwlib_bcopy (from, to, length)
125 char *from;
126 char *to;
127 int length;
129 int i;
131 for (i = 0; i < length; i++)
132 to[i] = from[i];
134 \f/* utility functions for widget_instance and widget_info */
135 char *
136 safe_strdup (s)
137 const char *s;
139 char *result;
140 if (! s) return 0;
141 result = (char *) malloc (strlen (s) + 1);
142 if (! result)
143 return 0;
144 strcpy (result, s);
145 return result;
148 /* Like strcmp but ignore differences in case. */
150 static int
151 my_strcasecmp (s1, s2)
152 char *s1, *s2;
154 while (1)
156 int c1 = *s1++;
157 int c2 = *s2++;
158 if (isupper (c1))
159 c1 = tolower (c1);
160 if (isupper (c2))
161 c2 = tolower (c2);
162 if (c1 != c2)
163 return (c1 > c2 ? 1 : -1);
164 if (c1 == 0)
165 return 0;
169 static void
170 safe_free_str (s)
171 char *s;
173 if (s) free (s);
176 static widget_value *widget_value_free_list = 0;
177 static int malloc_cpt = 0;
179 widget_value *
180 malloc_widget_value ()
182 widget_value *wv;
183 if (widget_value_free_list)
185 wv = widget_value_free_list;
186 widget_value_free_list = wv->free_list;
187 wv->free_list = 0;
189 else
191 wv = (widget_value *) malloc (sizeof (widget_value));
192 malloc_cpt++;
194 lwlib_memset ((void*) wv, 0, sizeof (widget_value));
195 return wv;
198 /* this is analogous to free(). It frees only what was allocated
199 by malloc_widget_value(), and no substructures.
201 void
202 free_widget_value (wv)
203 widget_value *wv;
205 if (wv->free_list)
206 abort ();
208 if (malloc_cpt > 25)
210 /* When the number of already allocated cells is too big,
211 We free it. */
212 free (wv);
213 malloc_cpt--;
215 else
217 wv->free_list = widget_value_free_list;
218 widget_value_free_list = wv;
222 static void
223 free_widget_value_tree (wv)
224 widget_value *wv;
226 if (!wv)
227 return;
229 if (wv->name) free (wv->name);
230 if (wv->value) free (wv->value);
231 if (wv->key) free (wv->key);
233 wv->name = wv->value = wv->key = (char *) 0xDEADBEEF;
235 if (wv->toolkit_data && wv->free_toolkit_data)
237 XtFree (wv->toolkit_data);
238 wv->toolkit_data = (void *) 0xDEADBEEF;
241 if (wv->contents && (wv->contents != (widget_value*)1))
243 free_widget_value_tree (wv->contents);
244 wv->contents = (widget_value *) 0xDEADBEEF;
246 if (wv->next)
248 free_widget_value_tree (wv->next);
249 wv->next = (widget_value *) 0xDEADBEEF;
251 free_widget_value (wv);
254 static widget_value *
255 copy_widget_value_tree (val, change)
256 widget_value* val;
257 change_type change;
259 widget_value* copy;
261 if (!val)
262 return NULL;
263 if (val == (widget_value *) 1)
264 return val;
266 copy = malloc_widget_value ();
267 copy->name = safe_strdup (val->name);
268 copy->value = safe_strdup (val->value);
269 copy->key = safe_strdup (val->key);
270 copy->help = val->help;
271 copy->enabled = val->enabled;
272 copy->button_type = val->button_type;
273 copy->selected = val->selected;
274 copy->edited = False;
275 copy->change = change;
276 copy->this_one_change = change;
277 copy->contents = copy_widget_value_tree (val->contents, change);
278 copy->call_data = val->call_data;
279 copy->next = copy_widget_value_tree (val->next, change);
280 copy->toolkit_data = NULL;
281 copy->free_toolkit_data = False;
282 return copy;
285 static widget_info *
286 allocate_widget_info (type, name, id, val, pre_activate_cb,
287 selection_cb, post_activate_cb, highlight_cb)
288 char* type;
289 char* name;
290 LWLIB_ID id;
291 widget_value* val;
292 lw_callback pre_activate_cb;
293 lw_callback selection_cb;
294 lw_callback post_activate_cb;
295 lw_callback highlight_cb;
297 widget_info* info = (widget_info*)malloc (sizeof (widget_info));
298 info->type = safe_strdup (type);
299 info->name = safe_strdup (name);
300 info->id = id;
301 info->val = copy_widget_value_tree (val, STRUCTURAL_CHANGE);
302 info->busy = False;
303 info->pre_activate_cb = pre_activate_cb;
304 info->selection_cb = selection_cb;
305 info->post_activate_cb = post_activate_cb;
306 info->highlight_cb = highlight_cb;
307 info->instances = NULL;
309 info->next = all_widget_info;
310 all_widget_info = info;
312 return info;
315 static void
316 free_widget_info (info)
317 widget_info* info;
319 safe_free_str (info->type);
320 safe_free_str (info->name);
321 free_widget_value_tree (info->val);
322 lwlib_memset ((void*)info, 0xDEADBEEF, sizeof (widget_info));
323 free (info);
326 static void
327 mark_widget_destroyed (widget, closure, call_data)
328 Widget widget;
329 XtPointer closure;
330 XtPointer call_data;
332 widget_instance* instance = (widget_instance*)closure;
334 /* be very conservative */
335 if (instance->widget == widget)
336 instance->widget = NULL;
339 /* The messy #ifdef PROTOTYPES here and elsewhere are prompted by a
340 flood of warnings about argument promotion from proprietary ISO C
341 compilers. (etags still only makes one entry for each function.) */
342 static widget_instance *
343 #ifdef PROTOTYPES
344 allocate_widget_instance (widget_info* info, Widget parent, Boolean pop_up_p)
345 #else
346 allocate_widget_instance (info, parent, pop_up_p)
347 widget_info* info;
348 Widget parent;
349 Boolean pop_up_p;
350 #endif
352 widget_instance* instance =
353 (widget_instance*)malloc (sizeof (widget_instance));
354 bzero (instance, sizeof *instance);
355 instance->parent = parent;
356 instance->pop_up_p = pop_up_p;
357 instance->info = info;
358 instance->next = info->instances;
359 info->instances = instance;
361 instantiate_widget_instance (instance);
363 XtAddCallback (instance->widget, XtNdestroyCallback,
364 mark_widget_destroyed, (XtPointer)instance);
365 return instance;
368 static void
369 free_widget_instance (instance)
370 widget_instance* instance;
372 lwlib_memset ((void*)instance, 0xDEADBEEF, sizeof (widget_instance));
373 free (instance);
376 static widget_info *
377 #ifdef PROTOTYPES
378 get_widget_info (LWLIB_ID id, Boolean remove_p)
379 #else
380 get_widget_info (id, remove_p)
381 LWLIB_ID id;
382 Boolean remove_p;
383 #endif
385 widget_info* info;
386 widget_info* prev;
387 for (prev = NULL, info = all_widget_info;
388 info;
389 prev = info, info = info->next)
390 if (info->id == id)
392 if (remove_p)
394 if (prev)
395 prev->next = info->next;
396 else
397 all_widget_info = info->next;
399 return info;
401 return NULL;
404 /* Internal function used by the library dependent implementation to get the
405 widget_value for a given widget in an instance */
406 widget_info *
407 lw_get_widget_info (id)
408 LWLIB_ID id;
410 return get_widget_info (id, 0);
413 static widget_instance *
414 #ifdef PROTOTYPES
415 get_widget_instance (Widget widget, Boolean remove_p)
416 #else
417 get_widget_instance (widget, remove_p)
418 Widget widget;
419 Boolean remove_p;
420 #endif
422 widget_info* info;
423 widget_instance* instance;
424 widget_instance* prev;
425 for (info = all_widget_info; info; info = info->next)
426 for (prev = NULL, instance = info->instances;
427 instance;
428 prev = instance, instance = instance->next)
429 if (instance->widget == widget)
431 if (remove_p)
433 if (prev)
434 prev->next = instance->next;
435 else
436 info->instances = instance->next;
438 return instance;
440 return (widget_instance *) 0;
443 /* Value is a pointer to the widget_instance corresponding to
444 WIDGET, or null if WIDGET is not a lwlib widget. */
446 widget_instance *
447 lw_get_widget_instance (widget)
448 Widget widget;
450 return get_widget_instance (widget, False);
453 static widget_instance*
454 #ifdef PROTOTYPES
455 find_instance (LWLIB_ID id, Widget parent, Boolean pop_up_p)
456 #else
457 find_instance (id, parent, pop_up_p)
458 LWLIB_ID id;
459 Widget parent;
460 Boolean pop_up_p;
461 #endif
463 widget_info* info = get_widget_info (id, False);
464 widget_instance* instance;
466 if (info)
467 for (instance = info->instances; instance; instance = instance->next)
468 if (instance->parent == parent && instance->pop_up_p == pop_up_p)
469 return instance;
471 return NULL;
475 /* utility function for widget_value */
476 static Boolean
477 safe_strcmp (s1, s2)
478 char* s1;
479 char* s2;
481 if (!!s1 ^ !!s2) return True;
482 return (s1 && s2) ? strcmp (s1, s2) : s1 ? False : !!s2;
486 #if 0
487 # define EXPLAIN(name, oc, nc, desc, a1, a2) \
488 printf ("Change: \"%s\"\tmax(%s=%d,%s=%d)\t%s %d %d\n", \
489 name, \
490 (oc == NO_CHANGE ? "none" : \
491 (oc == INVISIBLE_CHANGE ? "invisible" : \
492 (oc == VISIBLE_CHANGE ? "visible" : \
493 (oc == STRUCTURAL_CHANGE ? "structural" : "???")))), \
494 oc, \
495 (nc == NO_CHANGE ? "none" : \
496 (nc == INVISIBLE_CHANGE ? "invisible" : \
497 (nc == VISIBLE_CHANGE ? "visible" : \
498 (nc == STRUCTURAL_CHANGE ? "structural" : "???")))), \
499 nc, desc, a1, a2)
500 #else
501 # define EXPLAIN(name, oc, nc, desc, a1, a2)
502 #endif
505 static widget_value *
506 merge_widget_value (val1, val2, level, change_p)
507 widget_value* val1;
508 widget_value* val2;
509 int level;
510 int *change_p;
512 change_type change, this_one_change;
513 widget_value* merged_next;
514 widget_value* merged_contents;
516 if (!val1)
518 if (val2)
520 *change_p = 1;
521 return copy_widget_value_tree (val2, STRUCTURAL_CHANGE);
523 else
524 return NULL;
526 if (!val2)
528 *change_p = 1;
529 free_widget_value_tree (val1);
530 return NULL;
533 change = NO_CHANGE;
535 if (safe_strcmp (val1->name, val2->name))
537 EXPLAIN (val1->name, change, STRUCTURAL_CHANGE, "name change",
538 val1->name, val2->name);
539 change = max (change, STRUCTURAL_CHANGE);
540 safe_free_str (val1->name);
541 val1->name = safe_strdup (val2->name);
543 if (safe_strcmp (val1->value, val2->value))
545 EXPLAIN (val1->name, change, VISIBLE_CHANGE, "value change",
546 val1->value, val2->value);
547 change = max (change, VISIBLE_CHANGE);
548 safe_free_str (val1->value);
549 val1->value = safe_strdup (val2->value);
551 if (safe_strcmp (val1->key, val2->key))
553 EXPLAIN (val1->name, change, VISIBLE_CHANGE, "key change",
554 val1->key, val2->key);
555 change = max (change, VISIBLE_CHANGE);
556 safe_free_str (val1->key);
557 val1->key = safe_strdup (val2->key);
559 if (! EQ (val1->help, val2->help))
561 EXPLAIN (val1->name, change, VISIBLE_CHANGE, "help change",
562 val1->help, val2->help);
563 change = max (change, VISIBLE_CHANGE);
564 val1->help = val2->help;
566 if (val1->enabled != val2->enabled)
568 EXPLAIN (val1->name, change, VISIBLE_CHANGE, "enablement change",
569 val1->enabled, val2->enabled);
570 change = max (change, VISIBLE_CHANGE);
571 val1->enabled = val2->enabled;
573 if (val1->button_type != val2->button_type)
575 EXPLAIN (val1->name, change, VISIBLE_CHANGE, "button type change",
576 val1->button_type, val2->button_type);
577 change = max (change, VISIBLE_CHANGE);
578 val1->button_type = val2->button_type;
580 if (val1->selected != val2->selected)
582 EXPLAIN (val1->name, change, VISIBLE_CHANGE, "selection change",
583 val1->selected, val2->selected);
584 change = max (change, VISIBLE_CHANGE);
585 val1->selected = val2->selected;
587 if (val1->call_data != val2->call_data)
589 EXPLAIN (val1->name, change, INVISIBLE_CHANGE, "call-data change",
590 val1->call_data, val2->call_data);
591 change = max (change, INVISIBLE_CHANGE);
592 val1->call_data = val2->call_data;
595 if (level > 0)
597 merged_contents =
598 merge_widget_value (val1->contents, val2->contents, level - 1,
599 change_p);
601 if (val1->contents && !merged_contents)
603 /* This used to say INVISIBLE_CHANGE,
604 but it is visible and vitally important when
605 the contents of the menu bar itself are entirely deleted.
607 But maybe it doesn't matter. This fails to fix the bug. */
608 EXPLAIN (val1->name, change, STRUCTURAL_CHANGE, "(contents gone)",
609 0, 0);
610 change = max (change, STRUCTURAL_CHANGE);
612 else if (merged_contents && merged_contents->change != NO_CHANGE)
614 EXPLAIN (val1->name, change, INVISIBLE_CHANGE, "(contents change)",
615 0, 0);
616 change = max (change, INVISIBLE_CHANGE);
617 #if 0 /* This was replaced by the August 9 1996 change in lwlib-Xm.c. */
618 #ifdef USE_MOTIF
619 change = max (merged_contents->change, change);
620 #endif
621 #endif
624 val1->contents = merged_contents;
627 this_one_change = change;
629 merged_next = merge_widget_value (val1->next, val2->next, level, change_p);
631 if (val1->next && !merged_next)
633 EXPLAIN (val1->name, change, STRUCTURAL_CHANGE, "(following gone)",
634 0, 0);
635 change = max (change, STRUCTURAL_CHANGE);
637 else if (merged_next)
639 if (merged_next->change)
640 EXPLAIN (val1->name, change, merged_next->change, "(following change)",
641 0, 0);
642 change = max (change, merged_next->change);
645 val1->next = merged_next;
647 val1->this_one_change = this_one_change;
648 val1->change = change;
650 if (change > NO_CHANGE && val1->toolkit_data)
652 *change_p = 1;
653 if (val1->free_toolkit_data)
654 XtFree (val1->toolkit_data);
655 val1->toolkit_data = NULL;
658 return val1;
662 /* modifying the widgets */
663 static Widget
664 name_to_widget (instance, name)
665 widget_instance* instance;
666 char* name;
668 Widget widget = NULL;
670 if (!instance->widget)
671 return NULL;
673 if (!strcmp (XtName (instance->widget), name))
674 widget = instance->widget;
675 else
677 int length = strlen (name) + 2;
678 char* real_name = (char *) xmalloc (length);
679 real_name [0] = '*';
680 strcpy (real_name + 1, name);
682 widget = XtNameToWidget (instance->widget, real_name);
684 free (real_name);
686 return widget;
689 static void
690 #ifdef PROTOTYPES
691 set_one_value (widget_instance* instance, widget_value* val, Boolean deep_p)
692 #else
693 set_one_value (instance, val, deep_p)
694 widget_instance* instance;
695 widget_value* val;
696 Boolean deep_p;
697 #endif
699 Widget widget = name_to_widget (instance, val->name);
701 if (widget)
703 #if defined (USE_LUCID)
704 if (lw_lucid_widget_p (instance->widget))
705 xlw_update_one_widget (instance, widget, val, deep_p);
706 #endif
707 #if defined (USE_MOTIF)
708 if (lw_motif_widget_p (instance->widget))
709 xm_update_one_widget (instance, widget, val, deep_p);
710 #endif
711 #if defined (USE_XAW)
712 if (lw_xaw_widget_p (instance->widget))
713 xaw_update_one_widget (instance, widget, val, deep_p);
714 #endif
718 static void
719 #ifdef PROTOTYPES
720 update_one_widget_instance (widget_instance* instance, Boolean deep_p)
721 #else
722 update_one_widget_instance (instance, deep_p)
723 widget_instance* instance;
724 Boolean deep_p;
725 #endif
727 widget_value *val;
729 if (!instance->widget)
730 /* the widget was destroyed */
731 return;
733 for (val = instance->info->val; val; val = val->next)
734 if (val->change != NO_CHANGE)
735 set_one_value (instance, val, deep_p);
738 static void
739 #ifdef PROTOTYPES
740 update_all_widget_values (widget_info* info, Boolean deep_p)
741 #else
742 update_all_widget_values (info, deep_p)
743 widget_info* info;
744 Boolean deep_p;
745 #endif
747 widget_instance* instance;
748 widget_value* val;
750 for (instance = info->instances; instance; instance = instance->next)
751 update_one_widget_instance (instance, deep_p);
753 for (val = info->val; val; val = val->next)
754 val->change = NO_CHANGE;
758 #ifdef PROTOTYPES
759 lw_modify_all_widgets (LWLIB_ID id, widget_value* val, Boolean deep_p)
760 #else
761 lw_modify_all_widgets (id, val, deep_p)
762 LWLIB_ID id;
763 widget_value* val;
764 Boolean deep_p;
765 #endif
767 widget_info* info = get_widget_info (id, False);
768 widget_value* new_val;
769 widget_value* next_new_val;
770 widget_value* cur;
771 widget_value* prev;
772 widget_value* next;
773 int found;
774 int change_p = 0;
776 if (!info)
777 return 0;
779 for (new_val = val; new_val; new_val = new_val->next)
781 next_new_val = new_val->next;
782 new_val->next = NULL;
783 found = False;
784 for (prev = NULL, cur = info->val; cur; prev = cur, cur = cur->next)
785 if (!strcmp (cur->name, new_val->name))
787 found = True;
788 next = cur->next;
789 cur->next = NULL;
790 cur = merge_widget_value (cur, new_val, deep_p ? 1000 : 1,
791 &change_p);
792 if (prev)
793 prev->next = cur ? cur : next;
794 else
795 info->val = cur ? cur : next;
796 if (cur)
797 cur->next = next;
798 break;
800 if (!found)
802 /* Could not find it, add it */
803 if (prev)
804 prev->next = copy_widget_value_tree (new_val, STRUCTURAL_CHANGE);
805 else
806 info->val = copy_widget_value_tree (new_val, STRUCTURAL_CHANGE);
807 change_p = 1;
809 new_val->next = next_new_val;
812 update_all_widget_values (info, deep_p);
813 return change_p;
817 /* creating the widgets */
819 static void
820 initialize_widget_instance (instance)
821 widget_instance* instance;
823 widget_value* val;
825 for (val = instance->info->val; val; val = val->next)
826 val->change = STRUCTURAL_CHANGE;
828 update_one_widget_instance (instance, True);
830 for (val = instance->info->val; val; val = val->next)
831 val->change = NO_CHANGE;
835 static widget_creation_function
836 find_in_table (type, table)
837 char* type;
838 widget_creation_entry* table;
840 widget_creation_entry* cur;
841 for (cur = table; cur->type; cur++)
842 if (!my_strcasecmp (type, cur->type))
843 return cur->function;
844 return NULL;
847 static Boolean
848 dialog_spec_p (name)
849 char* name;
851 /* return True if name matches [EILPQeilpq][1-9][Bb] or
852 [EILPQeilpq][1-9][Bb][Rr][1-9] */
853 if (!name)
854 return False;
856 switch (name [0])
858 case 'E': case 'I': case 'L': case 'P': case 'Q':
859 case 'e': case 'i': case 'l': case 'p': case 'q':
860 if (name [1] >= '0' && name [1] <= '9')
862 if (name [2] != 'B' && name [2] != 'b')
863 return False;
864 if (!name [3])
865 return True;
866 if ((name [3] == 'T' || name [3] == 't') && !name [4])
867 return True;
868 if ((name [3] == 'R' || name [3] == 'r')
869 && name [4] >= '0' && name [4] <= '9' && !name [5])
870 return True;
871 return False;
873 else
874 return False;
876 default:
877 return False;
881 static void
882 instantiate_widget_instance (instance)
883 widget_instance* instance;
885 widget_creation_function function = NULL;
887 #if defined (USE_LUCID)
888 if (!function)
889 function = find_in_table (instance->info->type, xlw_creation_table);
890 #endif
891 #if defined(USE_MOTIF)
892 if (!function)
893 function = find_in_table (instance->info->type, xm_creation_table);
894 #endif
895 #if defined (USE_XAW)
896 if (!function)
897 function = find_in_table (instance->info->type, xaw_creation_table);
898 #endif
900 if (!function)
902 if (dialog_spec_p (instance->info->type))
904 #if defined (USE_LUCID)
905 /* not yet */
906 #endif
907 #if defined(USE_MOTIF)
908 if (!function)
909 function = xm_create_dialog;
910 #endif
911 #if defined (USE_XAW)
912 if (!function)
913 function = xaw_create_dialog;
914 #endif
918 if (!function)
920 printf ("No creation function for widget type %s\n",
921 instance->info->type);
922 abort ();
925 instance->widget = (*function) (instance);
927 if (!instance->widget)
928 abort ();
930 /* XtRealizeWidget (instance->widget);*/
933 void
934 lw_register_widget (type, name, id, val, pre_activate_cb,
935 selection_cb, post_activate_cb, highlight_cb)
936 char* type;
937 char* name;
938 LWLIB_ID id;
939 widget_value* val;
940 lw_callback pre_activate_cb;
941 lw_callback selection_cb;
942 lw_callback post_activate_cb;
943 lw_callback highlight_cb;
945 if (!get_widget_info (id, False))
946 allocate_widget_info (type, name, id, val, pre_activate_cb, selection_cb,
947 post_activate_cb, highlight_cb);
950 Widget
951 #ifdef PROTOTYPES
952 lw_get_widget (LWLIB_ID id, Widget parent, Boolean pop_up_p)
953 #else
954 lw_get_widget (id, parent, pop_up_p)
955 LWLIB_ID id;
956 Widget parent;
957 Boolean pop_up_p;
958 #endif
960 widget_instance* instance;
962 instance = find_instance (id, parent, pop_up_p);
963 return instance ? instance->widget : NULL;
966 Widget
967 #ifdef PROTOTYPES
968 lw_make_widget (LWLIB_ID id, Widget parent, Boolean pop_up_p)
969 #else
970 lw_make_widget (id, parent, pop_up_p)
971 LWLIB_ID id;
972 Widget parent;
973 Boolean pop_up_p;
974 #endif
976 widget_instance* instance;
977 widget_info* info;
979 instance = find_instance (id, parent, pop_up_p);
980 if (!instance)
982 info = get_widget_info (id, False);
983 if (!info)
984 return NULL;
985 instance = allocate_widget_instance (info, parent, pop_up_p);
986 initialize_widget_instance (instance);
988 if (!instance->widget)
989 abort ();
990 return instance->widget;
993 Widget
994 #ifdef PROTOTYPES
995 lw_create_widget (char* type, char* name, LWLIB_ID id, widget_value* val,
996 Widget parent, Boolean pop_up_p,
997 lw_callback pre_activate_cb, lw_callback selection_cb,
998 lw_callback post_activate_cb, lw_callback highlight_cb)
999 #else
1000 lw_create_widget (type, name, id, val, parent, pop_up_p, pre_activate_cb,
1001 selection_cb, post_activate_cb, highlight_cb)
1002 char* type;
1003 char* name;
1004 LWLIB_ID id;
1005 widget_value* val;
1006 Widget parent;
1007 Boolean pop_up_p;
1008 lw_callback pre_activate_cb;
1009 lw_callback selection_cb;
1010 lw_callback post_activate_cb;
1011 lw_callback highlight_cb;
1012 #endif
1014 lw_register_widget (type, name, id, val, pre_activate_cb, selection_cb,
1015 post_activate_cb, highlight_cb);
1016 return lw_make_widget (id, parent, pop_up_p);
1020 /* destroying the widgets */
1021 static void
1022 destroy_one_instance (instance)
1023 widget_instance* instance;
1025 /* Remove the destroy callback on the widget; that callback will try to
1026 dereference the instance object (to set its widget slot to 0, since the
1027 widget is dead.) Since the instance is now dead, we don't have to worry
1028 about the fact that its widget is dead too.
1030 This happens in the Phase2Destroy of the widget, so this callback would
1031 not have been run until arbitrarily long after the instance was freed.
1033 if (instance->widget)
1034 XtRemoveCallback (instance->widget, XtNdestroyCallback,
1035 mark_widget_destroyed, (XtPointer)instance);
1037 if (instance->widget)
1039 /* The else are pretty tricky here, including the empty statement
1040 at the end because it would be very bad to destroy a widget
1041 twice. */
1042 #if defined (USE_LUCID)
1043 if (lw_lucid_widget_p (instance->widget))
1044 xlw_destroy_instance (instance);
1045 else
1046 #endif
1047 #if defined (USE_MOTIF)
1048 if (lw_motif_widget_p (instance->widget))
1049 xm_destroy_instance (instance);
1050 else
1051 #endif
1052 #if defined (USE_XAW)
1053 if (lw_xaw_widget_p (instance->widget))
1054 xaw_destroy_instance (instance);
1055 else
1056 #endif
1057 /* do not remove the empty statement */
1061 free_widget_instance (instance);
1064 void
1065 lw_destroy_widget (w)
1066 Widget w;
1068 widget_instance* instance = get_widget_instance (w, True);
1070 if (instance)
1072 widget_info *info = instance->info;
1073 /* instance has already been removed from the list; free it */
1074 destroy_one_instance (instance);
1075 /* if there are no instances left, free the info too */
1076 if (!info->instances)
1077 lw_destroy_all_widgets (info->id);
1081 void
1082 lw_destroy_all_widgets (id)
1083 LWLIB_ID id;
1085 widget_info* info = get_widget_info (id, True);
1086 widget_instance* instance;
1087 widget_instance* next;
1089 if (info)
1091 for (instance = info->instances; instance; )
1093 next = instance->next;
1094 destroy_one_instance (instance);
1095 instance = next;
1097 free_widget_info (info);
1101 void
1102 lw_destroy_everything ()
1104 while (all_widget_info)
1105 lw_destroy_all_widgets (all_widget_info->id);
1108 void
1109 lw_destroy_all_pop_ups ()
1111 widget_info* info;
1112 widget_info* next;
1113 widget_instance* instance;
1115 for (info = all_widget_info; info; info = next)
1117 next = info->next;
1118 instance = info->instances;
1119 if (instance && instance->pop_up_p)
1120 lw_destroy_all_widgets (info->id);
1124 #ifdef USE_MOTIF
1125 extern Widget first_child (/* Widget */); /* garbage */
1126 #endif
1128 Widget
1129 lw_raise_all_pop_up_widgets ()
1131 widget_info* info;
1132 widget_instance* instance;
1133 Widget result = NULL;
1135 for (info = all_widget_info; info; info = info->next)
1136 for (instance = info->instances; instance; instance = instance->next)
1137 if (instance->pop_up_p)
1139 Widget widget = instance->widget;
1140 if (widget)
1142 if (XtIsManaged (widget)
1143 #ifdef USE_MOTIF
1144 /* What a complete load of crap!!!!
1145 When a dialogShell is on the screen, it is not managed!
1147 || (lw_motif_widget_p (instance->widget) &&
1148 XtIsManaged (first_child (widget)))
1149 #endif
1152 if (!result)
1153 result = widget;
1154 XMapRaised (XtDisplay (widget), XtWindow (widget));
1158 return result;
1161 static void
1162 #ifdef PROTOTYPES
1163 lw_pop_all_widgets (LWLIB_ID id, Boolean up)
1164 #else
1165 lw_pop_all_widgets (id, up)
1166 LWLIB_ID id;
1167 Boolean up;
1168 #endif
1170 widget_info* info = get_widget_info (id, False);
1171 widget_instance* instance;
1173 if (info)
1174 for (instance = info->instances; instance; instance = instance->next)
1175 if (instance->pop_up_p && instance->widget)
1177 #if defined (USE_LUCID)
1178 if (lw_lucid_widget_p (instance->widget))
1180 XtRealizeWidget (instance->widget);
1181 xlw_pop_instance (instance, up);
1183 #endif
1184 #if defined (USE_MOTIF)
1185 if (lw_motif_widget_p (instance->widget))
1187 XtRealizeWidget (instance->widget);
1188 xm_pop_instance (instance, up);
1190 #endif
1191 #if defined (USE_XAW)
1192 if (lw_xaw_widget_p (instance->widget))
1194 XtRealizeWidget (XtParent (instance->widget));
1195 XtRealizeWidget (instance->widget);
1196 xaw_pop_instance (instance, up);
1198 #endif
1202 void
1203 lw_pop_up_all_widgets (id)
1204 LWLIB_ID id;
1206 lw_pop_all_widgets (id, True);
1209 void
1210 lw_pop_down_all_widgets (id)
1211 LWLIB_ID id;
1213 lw_pop_all_widgets (id, False);
1216 void
1217 lw_popup_menu (widget, event)
1218 Widget widget;
1219 XEvent *event;
1221 #if defined (USE_LUCID)
1222 if (lw_lucid_widget_p (widget))
1223 xlw_popup_menu (widget, event);
1224 #endif
1225 #if defined (USE_MOTIF)
1226 if (lw_motif_widget_p (widget))
1227 xm_popup_menu (widget, event);
1228 #endif
1229 #if defined (USE_XAW)
1230 if (lw_xaw_widget_p (widget))
1231 xaw_popup_menu (widget, event);
1232 #endif
1235 \f/* get the values back */
1236 static Boolean
1237 get_one_value (instance, val)
1238 widget_instance* instance;
1239 widget_value* val;
1241 Widget widget = name_to_widget (instance, val->name);
1243 if (widget)
1245 #if defined (USE_LUCID)
1246 if (lw_lucid_widget_p (instance->widget))
1247 xlw_update_one_value (instance, widget, val);
1248 #endif
1249 #if defined (USE_MOTIF)
1250 if (lw_motif_widget_p (instance->widget))
1251 xm_update_one_value (instance, widget, val);
1252 #endif
1253 #if defined (USE_XAW)
1254 if (lw_xaw_widget_p (instance->widget))
1255 xaw_update_one_value (instance, widget, val);
1256 #endif
1257 return True;
1259 else
1260 return False;
1263 Boolean
1264 lw_get_some_values (id, val_out)
1265 LWLIB_ID id;
1266 widget_value* val_out;
1268 widget_info* info = get_widget_info (id, False);
1269 widget_instance* instance;
1270 widget_value* val;
1271 Boolean result = False;
1273 if (!info)
1274 return False;
1276 instance = info->instances;
1277 if (!instance)
1278 return False;
1280 for (val = val_out; val; val = val->next)
1281 if (get_one_value (instance, val))
1282 result = True;
1284 return result;
1287 widget_value*
1288 lw_get_all_values (id)
1289 LWLIB_ID id;
1291 widget_info* info = get_widget_info (id, False);
1292 widget_value* val = info->val;
1293 if (lw_get_some_values (id, val))
1294 return val;
1295 else
1296 return NULL;
1299 /* internal function used by the library dependent implementation to get the
1300 widget_value for a given widget in an instance */
1301 widget_value*
1302 lw_get_widget_value_for_widget (instance, w)
1303 widget_instance* instance;
1304 Widget w;
1306 char* name = XtName (w);
1307 widget_value* cur;
1308 for (cur = instance->info->val; cur; cur = cur->next)
1309 if (!strcmp (cur->name, name))
1310 return cur;
1311 return NULL;
1314 \f/* update other instances value when one thing changed */
1316 /* To forbid recursive calls */
1317 static Boolean lwlib_updating;
1319 /* This function can be used as a an XtCallback for the widgets that get
1320 modified to update other instances of the widgets. Closure should be the
1321 widget_instance. */
1322 void
1323 lw_internal_update_other_instances (widget, closure, call_data)
1324 Widget widget;
1325 XtPointer closure;
1326 XtPointer call_data;
1328 widget_instance* instance = (widget_instance*)closure;
1329 char* name = XtName (widget);
1330 widget_info* info;
1331 widget_instance* cur;
1332 widget_value* val;
1334 /* Avoid possibly infinite recursion. */
1335 if (lwlib_updating)
1336 return;
1338 /* protect against the widget being destroyed */
1339 if (XtWidgetBeingDestroyedP (widget))
1340 return;
1342 /* Return immediately if there are no other instances */
1343 info = instance->info;
1344 if (!info->instances->next)
1345 return;
1347 lwlib_updating = True;
1349 for (val = info->val; val && strcmp (val->name, name); val = val->next);
1351 if (val && get_one_value (instance, val))
1352 for (cur = info->instances; cur; cur = cur->next)
1353 if (cur != instance)
1354 set_one_value (cur, val, True);
1356 lwlib_updating = False;
1360 \f/* get the id */
1362 LWLIB_ID
1363 lw_get_widget_id (w)
1364 Widget w;
1366 widget_instance* instance = get_widget_instance (w, False);
1368 return instance ? instance->info->id : 0;
1371 \f/* set the keyboard focus */
1372 void
1373 lw_set_keyboard_focus (parent, w)
1374 Widget parent;
1375 Widget w;
1377 #if defined (USE_MOTIF)
1378 xm_set_keyboard_focus (parent, w);
1379 #else
1380 XtSetKeyboardFocus (parent, w);
1381 #endif
1384 \f/* Show busy */
1385 static void
1386 #ifdef PROTOTYPES
1387 show_one_widget_busy (Widget w, Boolean flag)
1388 #else
1389 show_one_widget_busy (w, flag)
1390 Widget w;
1391 Boolean flag;
1392 #endif
1394 Pixel foreground = 0;
1395 Pixel background = 1;
1396 Widget widget_to_invert = XtNameToWidget (w, "*sheet");
1397 if (!widget_to_invert)
1398 widget_to_invert = w;
1400 XtVaGetValues (widget_to_invert,
1401 XtNforeground, &foreground,
1402 XtNbackground, &background,
1403 NULL);
1404 XtVaSetValues (widget_to_invert,
1405 XtNforeground, background,
1406 XtNbackground, foreground,
1407 NULL);
1410 void
1411 #ifdef PROTOTYPES
1412 lw_show_busy (Widget w, Boolean busy)
1413 #else
1414 lw_show_busy (w, busy)
1415 Widget w;
1416 Boolean busy;
1417 #endif
1419 widget_instance* instance = get_widget_instance (w, False);
1420 widget_info* info;
1421 widget_instance* next;
1423 if (instance)
1425 info = instance->info;
1426 if (info->busy != busy)
1428 for (next = info->instances; next; next = next->next)
1429 if (next->widget)
1430 show_one_widget_busy (next->widget, busy);
1431 info->busy = busy;
1436 /* This hack exists because Lucid/Athena need to execute the strange
1437 function below to support geometry management. */
1438 void
1439 #ifdef PROTOTYPES
1440 lw_refigure_widget (Widget w, Boolean doit)
1441 #else
1442 lw_refigure_widget (w, doit)
1443 Widget w;
1444 Boolean doit;
1445 #endif
1447 #if defined (USE_XAW)
1448 XawPanedSetRefigureMode (w, doit);
1449 #endif
1450 #if defined (USE_MOTIF)
1451 if (doit)
1452 XtManageChild (w);
1453 else
1454 XtUnmanageChild (w);
1455 #endif
1458 /* Toolkit independent way of determining if an event window is in the
1459 menubar. */
1460 Boolean
1461 lw_window_is_in_menubar (win, menubar_widget)
1462 Window win;
1463 Widget menubar_widget;
1465 return menubar_widget
1466 #if defined (USE_LUCID)
1467 && XtWindow (menubar_widget) == win;
1468 #endif
1469 #if defined (USE_MOTIF)
1470 && ((XtWindow (menubar_widget) == win)
1471 || (XtWindowToWidget (XtDisplay (menubar_widget), win)
1472 && (XtParent (XtWindowToWidget (XtDisplay (menubar_widget), win))
1473 == menubar_widget)));
1474 #endif
1477 /* Motif hack to set the main window areas. */
1478 void
1479 lw_set_main_areas (parent, menubar, work_area)
1480 Widget parent;
1481 Widget menubar;
1482 Widget work_area;
1484 #if defined (USE_MOTIF)
1485 xm_set_main_areas (parent, menubar, work_area);
1486 #endif
1489 /* Manage resizing for Motif. This disables resizing when the menubar
1490 is about to be modified. */
1491 void
1492 #ifdef PROTOTYPES
1493 lw_allow_resizing (Widget w, Boolean flag)
1494 #else
1495 lw_allow_resizing (w, flag)
1496 Widget w;
1497 Boolean flag;
1498 #endif
1500 #if defined (USE_MOTIF)
1501 xm_manage_resizing (w, flag);
1502 #endif
1506 /* Value is non-zero if LABEL is a menu separator. If it is, *TYPE is
1507 set to an appropriate enumerator of type enum menu_separator.
1508 MOTIF_P non-zero means map separator types not supported by Motif
1509 to similar ones that are supported. */
1512 lw_separator_p (label, type, motif_p)
1513 char *label;
1514 enum menu_separator *type;
1515 int motif_p;
1517 int separator_p = 0;
1519 if (strlen (label) >= 3
1520 && bcmp (label, "--:", 3) == 0)
1522 static struct separator_table
1524 char *name;
1525 enum menu_separator type;
1527 separator_names[] =
1529 {"space", SEPARATOR_NO_LINE},
1530 {"noLine", SEPARATOR_NO_LINE},
1531 {"singleLine", SEPARATOR_SINGLE_LINE},
1532 {"doubleLine", SEPARATOR_DOUBLE_LINE},
1533 {"singleDashedLine", SEPARATOR_SINGLE_DASHED_LINE},
1534 {"doubleDashedLine", SEPARATOR_DOUBLE_DASHED_LINE},
1535 {"shadowEtchedIn", SEPARATOR_SHADOW_ETCHED_IN},
1536 {"shadowEtchedOut", SEPARATOR_SHADOW_ETCHED_OUT},
1537 {"shadowEtchedInDash", SEPARATOR_SHADOW_ETCHED_IN_DASH},
1538 {"shadowEtchedOutDash", SEPARATOR_SHADOW_ETCHED_OUT_DASH},
1539 {"shadowDoubleEtchedIn", SEPARATOR_SHADOW_DOUBLE_ETCHED_IN},
1540 {"shadowDoubleEtchedOut", SEPARATOR_SHADOW_DOUBLE_ETCHED_OUT},
1541 {"shadowDoubleEtchedInDash", SEPARATOR_SHADOW_DOUBLE_ETCHED_IN_DASH},
1542 {"shadowDoubleEtchedOutDash", SEPARATOR_SHADOW_DOUBLE_ETCHED_OUT_DASH},
1543 {0,0}
1546 int i;
1548 label += 3;
1549 for (i = 0; separator_names[i].name; ++i)
1550 if (strcmp (label, separator_names[i].name) == 0)
1552 separator_p = 1;
1553 *type = separator_names[i].type;
1555 /* If separator type is not supported under Motif,
1556 use a similar one. */
1557 if (motif_p && *type >= SEPARATOR_SHADOW_DOUBLE_ETCHED_IN)
1558 *type -= 4;
1559 break;
1562 else if (strlen (label) > 3
1563 && bcmp (label, "--", 2) == 0
1564 && label[2] != '-')
1566 /* Alternative, more Emacs-style names. */
1567 static struct separator_table
1569 char *name;
1570 enum menu_separator type;
1572 separator_names[] =
1574 {"space", SEPARATOR_NO_LINE},
1575 {"no-line", SEPARATOR_NO_LINE},
1576 {"single-line", SEPARATOR_SINGLE_LINE},
1577 {"double-line", SEPARATOR_DOUBLE_LINE},
1578 {"single-dashed-line", SEPARATOR_SINGLE_DASHED_LINE},
1579 {"double-dashed-line", SEPARATOR_DOUBLE_DASHED_LINE},
1580 {"shadow-etched-in", SEPARATOR_SHADOW_ETCHED_IN},
1581 {"shadow-etched-out", SEPARATOR_SHADOW_ETCHED_OUT},
1582 {"shadow-etched-in-dash", SEPARATOR_SHADOW_ETCHED_IN_DASH},
1583 {"shadow-etched-out-dash", SEPARATOR_SHADOW_ETCHED_OUT_DASH},
1584 {"shadow-double-etched-in", SEPARATOR_SHADOW_DOUBLE_ETCHED_IN},
1585 {"shadow-double-etched-out", SEPARATOR_SHADOW_DOUBLE_ETCHED_OUT},
1586 {"shadow-double-etched-in-dash", SEPARATOR_SHADOW_DOUBLE_ETCHED_IN_DASH},
1587 {"shadow-double-etched-out-dash",SEPARATOR_SHADOW_DOUBLE_ETCHED_OUT_DASH},
1588 {0,0}
1591 int i;
1593 label += 2;
1594 for (i = 0; separator_names[i].name; ++i)
1595 if (strcmp (label, separator_names[i].name) == 0)
1597 separator_p = 1;
1598 *type = separator_names[i].type;
1600 /* If separator type is not supported under Motif,
1601 use a similar one. */
1602 if (motif_p && *type >= SEPARATOR_SHADOW_DOUBLE_ETCHED_IN)
1603 *type -= 4;
1604 break;
1607 else
1609 /* Old-style separator, maybe. It's a separator if it contains
1610 only dashes. */
1611 while (*label == '-')
1612 ++label;
1613 separator_p = *label == 0;
1614 *type = SEPARATOR_SHADOW_ETCHED_IN;
1617 return separator_p;
1620 /* arch-tag: 3d730f36-a441-4a71-9971-48ef3b5a4d9f
1621 (do not change this comment) */