Use add/delete_read_fd in xsmfns to simplify. Also restart with initial_argv.
[emacs.git] / lwlib / lwlib.c
blobe03196d79275d12b1a8f12188efa35c1f78850cf
1 /* A general interface to the widgets of different toolkits.
2 Copyright (C) 1992, 1993 Lucid, Inc.
3 Copyright (C) 1994-1996, 1999-2011 Free Software Foundation, Inc.
5 This file is part of the Lucid Widget Library.
7 The Lucid Widget Library is free software; you can redistribute it and/or
8 modify it under the terms of the GNU General Public License as published by
9 the Free Software Foundation; either version 2, or (at your option)
10 any later version.
12 The Lucid Widget Library is distributed in the hope that it will be useful,
13 but WITHOUT ANY WARRANTY; without even the implied warranty of
14 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 GNU General Public License for more details.
17 You should have received a copy of the GNU General Public License
18 along with GNU Emacs; see the file COPYING. If not, write to
19 the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
20 Boston, MA 02110-1301, USA. */
22 #ifdef HAVE_CONFIG_H
23 #include <config.h>
24 #endif
26 #include <setjmp.h>
27 #include "../src/lisp.h"
29 #include <sys/types.h>
30 #include <stdio.h>
31 #include <ctype.h>
32 #include "lwlib-int.h"
33 #include "lwlib-utils.h"
34 #include <X11/StringDefs.h>
36 #if defined (USE_LUCID)
37 #include "lwlib-Xlw.h"
38 #endif
39 #if defined (USE_MOTIF)
40 #include "lwlib-Xm.h"
41 #else /* not USE_MOTIF */
42 #if defined (USE_LUCID)
43 #define USE_XAW
44 #endif /* not USE_MOTIF && USE_LUCID */
45 #endif
46 #if defined (USE_XAW)
47 #ifdef HAVE_XAW3D
48 #include <X11/Xaw3d/Paned.h>
49 #else /* !HAVE_XAW3D */
50 #include <X11/Xaw/Paned.h>
51 #endif /* HAVE_XAW3D */
52 #include "lwlib-Xaw.h"
53 #endif
55 #if !defined (USE_LUCID) && !defined (USE_MOTIF)
56 #error At least one of USE_LUCID or USE_MOTIF must be defined.
57 #endif
59 #ifndef max
60 #define max(x, y) ((x) > (y) ? (x) : (y))
61 #endif
63 /* List of all widgets managed by the library. */
64 static widget_info*
65 all_widget_info = NULL;
67 #ifdef USE_MOTIF
68 const char *lwlib_toolkit_type = "motif";
69 #else
70 const char *lwlib_toolkit_type = "lucid";
71 #endif
73 static widget_value *merge_widget_value (widget_value *,
74 widget_value *,
75 int, int *);
76 static void instantiate_widget_instance (widget_instance *);
77 static int my_strcasecmp (const char *, const char *);
78 static void safe_free_str (char *);
79 static void free_widget_value_tree (widget_value *);
80 static widget_value *copy_widget_value_tree (widget_value *,
81 change_type);
82 static widget_info *allocate_widget_info (const char *, const char *, LWLIB_ID,
83 widget_value *,
84 lw_callback, lw_callback,
85 lw_callback, lw_callback);
86 static void free_widget_info (widget_info *);
87 static void mark_widget_destroyed (Widget, XtPointer, XtPointer);
88 static widget_instance *allocate_widget_instance (widget_info *,
89 Widget, Boolean);
90 static void free_widget_instance (widget_instance *);
91 static widget_info *get_widget_info (LWLIB_ID, Boolean);
92 static widget_instance *get_widget_instance (Widget, Boolean);
93 static widget_instance *find_instance (LWLIB_ID, Widget, Boolean);
94 static Boolean safe_strcmp (const char *, const char *);
95 static Widget name_to_widget (widget_instance *, const char *);
96 static void set_one_value (widget_instance *, widget_value *, Boolean);
97 static void update_one_widget_instance (widget_instance *, Boolean);
98 static void update_all_widget_values (widget_info *, Boolean);
99 static void initialize_widget_instance (widget_instance *);
100 static widget_creation_function find_in_table (const char *, const widget_creation_entry *);
101 static Boolean dialog_spec_p (const char *);
102 static void destroy_one_instance (widget_instance *);
103 static void lw_pop_all_widgets (LWLIB_ID, Boolean);
104 static Boolean get_one_value (widget_instance *, widget_value *);
105 static void show_one_widget_busy (Widget, Boolean);
106 \f/* utility functions for widget_instance and widget_info */
107 char *
108 safe_strdup (const char *s)
110 char *result;
111 if (! s) return 0;
112 result = (char *) xmalloc (strlen (s) + 1);
113 strcpy (result, s);
114 return result;
117 /* Like strcmp but ignore differences in case. */
119 static int
120 my_strcasecmp (const char *s1, const char *s2)
122 while (1)
124 int c1 = *s1++;
125 int c2 = *s2++;
126 if (isupper (c1))
127 c1 = tolower (c1);
128 if (isupper (c2))
129 c2 = tolower (c2);
130 if (c1 != c2)
131 return (c1 > c2 ? 1 : -1);
132 if (c1 == 0)
133 return 0;
137 static void
138 safe_free_str (char *s)
140 free (s);
143 static widget_value *widget_value_free_list = 0;
144 static int malloc_cpt = 0;
146 widget_value *
147 malloc_widget_value (void)
149 widget_value *wv;
150 if (widget_value_free_list)
152 wv = widget_value_free_list;
153 widget_value_free_list = wv->free_list;
154 wv->free_list = 0;
156 else
158 wv = (widget_value *) xmalloc (sizeof (widget_value));
159 malloc_cpt++;
161 memset ((void*) wv, 0, sizeof (widget_value));
162 return wv;
165 /* this is analogous to free(). It frees only what was allocated
166 by malloc_widget_value(), and no substructures.
168 void
169 free_widget_value (widget_value *wv)
171 if (wv->free_list)
172 abort ();
174 if (malloc_cpt > 25)
176 /* When the number of already allocated cells is too big,
177 We free it. */
178 free (wv);
179 malloc_cpt--;
181 else
183 wv->free_list = widget_value_free_list;
184 widget_value_free_list = wv;
188 static void
189 free_widget_value_tree (widget_value *wv)
191 if (!wv)
192 return;
194 free (wv->name);
195 free (wv->value);
196 free (wv->key);
198 wv->name = wv->value = wv->key = (char *) 0xDEADBEEF;
200 if (wv->toolkit_data && wv->free_toolkit_data)
202 XtFree (wv->toolkit_data);
203 wv->toolkit_data = (void *) 0xDEADBEEF;
206 if (wv->contents && (wv->contents != (widget_value*)1))
208 free_widget_value_tree (wv->contents);
209 wv->contents = (widget_value *) 0xDEADBEEF;
211 if (wv->next)
213 free_widget_value_tree (wv->next);
214 wv->next = (widget_value *) 0xDEADBEEF;
216 free_widget_value (wv);
219 static widget_value *
220 copy_widget_value_tree (widget_value *val, change_type change)
222 widget_value* copy;
224 if (!val)
225 return NULL;
226 if (val == (widget_value *) 1)
227 return val;
229 copy = malloc_widget_value ();
230 copy->name = safe_strdup (val->name);
231 copy->value = safe_strdup (val->value);
232 copy->key = safe_strdup (val->key);
233 copy->help = val->help;
234 copy->enabled = val->enabled;
235 copy->button_type = val->button_type;
236 copy->selected = val->selected;
237 copy->edited = False;
238 copy->change = change;
239 copy->this_one_change = change;
240 copy->contents = copy_widget_value_tree (val->contents, change);
241 copy->call_data = val->call_data;
242 copy->next = copy_widget_value_tree (val->next, change);
243 copy->toolkit_data = NULL;
244 copy->free_toolkit_data = False;
245 return copy;
248 static widget_info *
249 allocate_widget_info (const char* type,
250 const char* name,
251 LWLIB_ID id,
252 widget_value* val,
253 lw_callback pre_activate_cb,
254 lw_callback selection_cb,
255 lw_callback post_activate_cb,
256 lw_callback highlight_cb)
258 widget_info* info = (widget_info*) xmalloc (sizeof (widget_info));
259 info->type = safe_strdup (type);
260 info->name = safe_strdup (name);
261 info->id = id;
262 info->val = copy_widget_value_tree (val, STRUCTURAL_CHANGE);
263 info->busy = False;
264 info->pre_activate_cb = pre_activate_cb;
265 info->selection_cb = selection_cb;
266 info->post_activate_cb = post_activate_cb;
267 info->highlight_cb = highlight_cb;
268 info->instances = NULL;
270 info->next = all_widget_info;
271 all_widget_info = info;
273 return info;
276 static void
277 free_widget_info (widget_info *info)
279 safe_free_str (info->type);
280 safe_free_str (info->name);
281 free_widget_value_tree (info->val);
282 memset ((void*)info, 0xDEADBEEF, sizeof (widget_info));
283 free (info);
286 static void
287 mark_widget_destroyed (Widget widget, XtPointer closure, XtPointer call_data)
289 widget_instance* instance = (widget_instance*)closure;
291 /* be very conservative */
292 if (instance->widget == widget)
293 instance->widget = NULL;
296 static widget_instance *
297 allocate_widget_instance (widget_info* info, Widget parent, Boolean pop_up_p)
299 widget_instance* instance =
300 (widget_instance*) xmalloc (sizeof (widget_instance));
301 memset (instance, 0, sizeof *instance);
302 instance->parent = parent;
303 instance->pop_up_p = pop_up_p;
304 instance->info = info;
305 instance->next = info->instances;
306 info->instances = instance;
308 instantiate_widget_instance (instance);
310 XtAddCallback (instance->widget, XtNdestroyCallback,
311 mark_widget_destroyed, (XtPointer)instance);
312 return instance;
315 static void
316 free_widget_instance (widget_instance *instance)
318 memset ((void*)instance, 0xDEADBEEF, sizeof (widget_instance));
319 free (instance);
322 static widget_info *
323 get_widget_info (LWLIB_ID id, Boolean remove_p)
325 widget_info* info;
326 widget_info* prev;
327 for (prev = NULL, info = all_widget_info;
328 info;
329 prev = info, info = info->next)
330 if (info->id == id)
332 if (remove_p)
334 if (prev)
335 prev->next = info->next;
336 else
337 all_widget_info = info->next;
339 return info;
341 return NULL;
344 /* Internal function used by the library dependent implementation to get the
345 widget_value for a given widget in an instance */
346 widget_info *
347 lw_get_widget_info (LWLIB_ID id)
349 return get_widget_info (id, 0);
352 static widget_instance *
353 get_widget_instance (Widget widget, Boolean remove_p)
355 widget_info* info;
356 widget_instance* instance;
357 widget_instance* prev;
358 for (info = all_widget_info; info; info = info->next)
359 for (prev = NULL, instance = info->instances;
360 instance;
361 prev = instance, instance = instance->next)
362 if (instance->widget == widget)
364 if (remove_p)
366 if (prev)
367 prev->next = instance->next;
368 else
369 info->instances = instance->next;
371 return instance;
373 return (widget_instance *) 0;
376 /* Value is a pointer to the widget_instance corresponding to
377 WIDGET, or null if WIDGET is not a lwlib widget. */
379 widget_instance *
380 lw_get_widget_instance (Widget widget)
382 return get_widget_instance (widget, False);
385 static widget_instance*
386 find_instance (LWLIB_ID id, Widget parent, Boolean pop_up_p)
388 widget_info* info = get_widget_info (id, False);
389 widget_instance* instance;
391 if (info)
392 for (instance = info->instances; instance; instance = instance->next)
393 if (instance->parent == parent && instance->pop_up_p == pop_up_p)
394 return instance;
396 return NULL;
400 /* utility function for widget_value */
401 static Boolean
402 safe_strcmp (const char *s1, const char *s2)
404 if (!!s1 ^ !!s2) return True;
405 return (s1 && s2) ? strcmp (s1, s2) : s1 ? False : !!s2;
409 #if 0
410 # define EXPLAIN(name, oc, nc, desc, a1, a2) \
411 printf ("Change: \"%s\"\tmax(%s=%d,%s=%d)\t%s %d %d\n", \
412 name, \
413 (oc == NO_CHANGE ? "none" : \
414 (oc == INVISIBLE_CHANGE ? "invisible" : \
415 (oc == VISIBLE_CHANGE ? "visible" : \
416 (oc == STRUCTURAL_CHANGE ? "structural" : "???")))), \
417 oc, \
418 (nc == NO_CHANGE ? "none" : \
419 (nc == INVISIBLE_CHANGE ? "invisible" : \
420 (nc == VISIBLE_CHANGE ? "visible" : \
421 (nc == STRUCTURAL_CHANGE ? "structural" : "???")))), \
422 nc, desc, a1, a2)
423 #else
424 # define EXPLAIN(name, oc, nc, desc, a1, a2)
425 #endif
428 static widget_value *
429 merge_widget_value (widget_value *val1,
430 widget_value *val2,
431 int level,
432 int *change_p)
434 change_type change, this_one_change;
435 widget_value* merged_next;
436 widget_value* merged_contents;
438 if (!val1)
440 if (val2)
442 *change_p = 1;
443 return copy_widget_value_tree (val2, STRUCTURAL_CHANGE);
445 else
446 return NULL;
448 if (!val2)
450 *change_p = 1;
451 free_widget_value_tree (val1);
452 return NULL;
455 change = NO_CHANGE;
457 if (safe_strcmp (val1->name, val2->name))
459 EXPLAIN (val1->name, change, STRUCTURAL_CHANGE, "name change",
460 val1->name, val2->name);
461 change = max (change, STRUCTURAL_CHANGE);
462 safe_free_str (val1->name);
463 val1->name = safe_strdup (val2->name);
465 if (safe_strcmp (val1->value, val2->value))
467 EXPLAIN (val1->name, change, VISIBLE_CHANGE, "value change",
468 val1->value, val2->value);
469 change = max (change, VISIBLE_CHANGE);
470 safe_free_str (val1->value);
471 val1->value = safe_strdup (val2->value);
473 if (safe_strcmp (val1->key, val2->key))
475 EXPLAIN (val1->name, change, VISIBLE_CHANGE, "key change",
476 val1->key, val2->key);
477 change = max (change, VISIBLE_CHANGE);
478 safe_free_str (val1->key);
479 val1->key = safe_strdup (val2->key);
481 if (! EQ (val1->help, val2->help))
483 EXPLAIN (val1->name, change, VISIBLE_CHANGE, "help change",
484 val1->help, val2->help);
485 change = max (change, VISIBLE_CHANGE);
486 val1->help = val2->help;
488 if (val1->enabled != val2->enabled)
490 EXPLAIN (val1->name, change, VISIBLE_CHANGE, "enablement change",
491 val1->enabled, val2->enabled);
492 change = max (change, VISIBLE_CHANGE);
493 val1->enabled = val2->enabled;
495 if (val1->button_type != val2->button_type)
497 EXPLAIN (val1->name, change, VISIBLE_CHANGE, "button type change",
498 val1->button_type, val2->button_type);
499 change = max (change, VISIBLE_CHANGE);
500 val1->button_type = val2->button_type;
502 if (val1->selected != val2->selected)
504 EXPLAIN (val1->name, change, VISIBLE_CHANGE, "selection change",
505 val1->selected, val2->selected);
506 change = max (change, VISIBLE_CHANGE);
507 val1->selected = val2->selected;
509 if (val1->call_data != val2->call_data)
511 EXPLAIN (val1->name, change, INVISIBLE_CHANGE, "call-data change",
512 val1->call_data, val2->call_data);
513 change = max (change, INVISIBLE_CHANGE);
514 val1->call_data = val2->call_data;
517 if (level > 0)
519 merged_contents =
520 merge_widget_value (val1->contents, val2->contents, level - 1,
521 change_p);
523 if (val1->contents && !merged_contents)
525 /* This used to say INVISIBLE_CHANGE,
526 but it is visible and vitally important when
527 the contents of the menu bar itself are entirely deleted.
529 But maybe it doesn't matter. This fails to fix the bug. */
530 EXPLAIN (val1->name, change, STRUCTURAL_CHANGE, "(contents gone)",
531 0, 0);
532 change = max (change, STRUCTURAL_CHANGE);
534 else if (merged_contents && merged_contents->change != NO_CHANGE)
536 EXPLAIN (val1->name, change, INVISIBLE_CHANGE, "(contents change)",
537 0, 0);
538 change = max (change, INVISIBLE_CHANGE);
539 #if 0 /* This was replaced by the August 9 1996 change in lwlib-Xm.c. */
540 #ifdef USE_MOTIF
541 change = max (merged_contents->change, change);
542 #endif
543 #endif
546 val1->contents = merged_contents;
549 this_one_change = change;
551 merged_next = merge_widget_value (val1->next, val2->next, level, change_p);
553 if (val1->next && !merged_next)
555 EXPLAIN (val1->name, change, STRUCTURAL_CHANGE, "(following gone)",
556 0, 0);
557 change = max (change, STRUCTURAL_CHANGE);
559 else if (merged_next)
561 if (merged_next->change)
562 EXPLAIN (val1->name, change, merged_next->change, "(following change)",
563 0, 0);
564 change = max (change, merged_next->change);
567 val1->next = merged_next;
569 val1->this_one_change = this_one_change;
570 val1->change = change;
572 if (change > NO_CHANGE && val1->toolkit_data)
574 *change_p = 1;
575 if (val1->free_toolkit_data)
576 XtFree (val1->toolkit_data);
577 val1->toolkit_data = NULL;
580 return val1;
584 /* modifying the widgets */
585 static Widget
586 name_to_widget (widget_instance *instance, const char *name)
588 Widget widget = NULL;
590 if (!instance->widget)
591 return NULL;
593 if (!strcmp (XtName (instance->widget), name))
594 widget = instance->widget;
595 else
597 int length = strlen (name) + 2;
598 char* real_name = (char *) xmalloc (length);
599 real_name [0] = '*';
600 strcpy (real_name + 1, name);
602 widget = XtNameToWidget (instance->widget, real_name);
604 free (real_name);
606 return widget;
609 static void
610 set_one_value (widget_instance* instance, widget_value* val, Boolean deep_p)
612 Widget widget = name_to_widget (instance, val->name);
614 if (widget)
616 #if defined (USE_LUCID)
617 if (lw_lucid_widget_p (instance->widget))
618 xlw_update_one_widget (instance, widget, val, deep_p);
619 #endif
620 #if defined (USE_MOTIF)
621 if (lw_motif_widget_p (instance->widget))
622 xm_update_one_widget (instance, widget, val, deep_p);
623 #endif
624 #if defined (USE_XAW)
625 if (lw_xaw_widget_p (instance->widget))
626 xaw_update_one_widget (instance, widget, val, deep_p);
627 #endif
631 static void
632 update_one_widget_instance (widget_instance* instance, Boolean deep_p)
634 widget_value *val;
636 if (!instance->widget)
637 /* the widget was destroyed */
638 return;
640 for (val = instance->info->val; val; val = val->next)
641 if (val->change != NO_CHANGE)
642 set_one_value (instance, val, deep_p);
645 static void
646 update_all_widget_values (widget_info* info, Boolean deep_p)
648 widget_instance* instance;
649 widget_value* val;
651 for (instance = info->instances; instance; instance = instance->next)
652 update_one_widget_instance (instance, deep_p);
654 for (val = info->val; val; val = val->next)
655 val->change = NO_CHANGE;
659 lw_modify_all_widgets (LWLIB_ID id, widget_value* val, Boolean deep_p)
661 widget_info* info = get_widget_info (id, False);
662 widget_value* new_val;
663 widget_value* next_new_val;
664 widget_value* cur;
665 widget_value* prev;
666 widget_value* next;
667 int found;
668 int change_p = 0;
670 if (!info)
671 return 0;
673 for (new_val = val; new_val; new_val = new_val->next)
675 next_new_val = new_val->next;
676 new_val->next = NULL;
677 found = False;
678 for (prev = NULL, cur = info->val; cur; prev = cur, cur = cur->next)
679 if (!strcmp (cur->name, new_val->name))
681 found = True;
682 next = cur->next;
683 cur->next = NULL;
684 cur = merge_widget_value (cur, new_val, deep_p ? 1000 : 1,
685 &change_p);
686 if (prev)
687 prev->next = cur ? cur : next;
688 else
689 info->val = cur ? cur : next;
690 if (cur)
691 cur->next = next;
692 break;
694 if (!found)
696 /* Could not find it, add it */
697 if (prev)
698 prev->next = copy_widget_value_tree (new_val, STRUCTURAL_CHANGE);
699 else
700 info->val = copy_widget_value_tree (new_val, STRUCTURAL_CHANGE);
701 change_p = 1;
703 new_val->next = next_new_val;
706 update_all_widget_values (info, deep_p);
707 return change_p;
711 /* creating the widgets */
713 static void
714 initialize_widget_instance (widget_instance *instance)
716 widget_value* val;
718 for (val = instance->info->val; val; val = val->next)
719 val->change = STRUCTURAL_CHANGE;
721 update_one_widget_instance (instance, True);
723 for (val = instance->info->val; val; val = val->next)
724 val->change = NO_CHANGE;
728 static widget_creation_function
729 find_in_table (const char *type, const widget_creation_entry *table)
731 const widget_creation_entry* cur;
732 for (cur = table; cur->type; cur++)
733 if (!my_strcasecmp (type, cur->type))
734 return cur->function;
735 return NULL;
738 static Boolean
739 dialog_spec_p (const char *name)
741 /* return True if name matches [EILPQeilpq][1-9][Bb] or
742 [EILPQeilpq][1-9][Bb][Rr][1-9] */
743 if (!name)
744 return False;
746 switch (name [0])
748 case 'E': case 'I': case 'L': case 'P': case 'Q':
749 case 'e': case 'i': case 'l': case 'p': case 'q':
750 if (name [1] >= '0' && name [1] <= '9')
752 if (name [2] != 'B' && name [2] != 'b')
753 return False;
754 if (!name [3])
755 return True;
756 if ((name [3] == 'T' || name [3] == 't') && !name [4])
757 return True;
758 if ((name [3] == 'R' || name [3] == 'r')
759 && name [4] >= '0' && name [4] <= '9' && !name [5])
760 return True;
761 return False;
763 else
764 return False;
766 default:
767 return False;
771 static void
772 instantiate_widget_instance (widget_instance *instance)
774 widget_creation_function function = NULL;
776 #if defined (USE_LUCID)
777 if (!function)
778 function = find_in_table (instance->info->type, xlw_creation_table);
779 #endif
780 #if defined(USE_MOTIF)
781 if (!function)
782 function = find_in_table (instance->info->type, xm_creation_table);
783 #endif
784 #if defined (USE_XAW)
785 if (!function)
786 function = find_in_table (instance->info->type, xaw_creation_table);
787 #endif
789 if (!function)
791 if (dialog_spec_p (instance->info->type))
793 #if defined (USE_LUCID)
794 /* not yet */
795 #endif
796 #if defined(USE_MOTIF)
797 if (!function)
798 function = xm_create_dialog;
799 #endif
800 #if defined (USE_XAW)
801 if (!function)
802 function = xaw_create_dialog;
803 #endif
807 if (!function)
809 printf ("No creation function for widget type %s\n",
810 instance->info->type);
811 abort ();
814 instance->widget = (*function) (instance);
816 if (!instance->widget)
817 abort ();
819 /* XtRealizeWidget (instance->widget);*/
822 void
823 lw_register_widget (const char* type,
824 const char* name,
825 LWLIB_ID id,
826 widget_value* val,
827 lw_callback pre_activate_cb,
828 lw_callback selection_cb,
829 lw_callback post_activate_cb,
830 lw_callback highlight_cb)
832 if (!get_widget_info (id, False))
833 allocate_widget_info (type, name, id, val, pre_activate_cb, selection_cb,
834 post_activate_cb, highlight_cb);
837 Widget
838 lw_get_widget (LWLIB_ID id, Widget parent, Boolean pop_up_p)
840 widget_instance* instance;
842 instance = find_instance (id, parent, pop_up_p);
843 return instance ? instance->widget : NULL;
846 Widget
847 lw_make_widget (LWLIB_ID id, Widget parent, Boolean pop_up_p)
849 widget_instance* instance;
850 widget_info* info;
852 instance = find_instance (id, parent, pop_up_p);
853 if (!instance)
855 info = get_widget_info (id, False);
856 if (!info)
857 return NULL;
858 instance = allocate_widget_instance (info, parent, pop_up_p);
859 initialize_widget_instance (instance);
861 if (!instance->widget)
862 abort ();
863 return instance->widget;
866 Widget
867 lw_create_widget (const char* type, const char* name, LWLIB_ID id, widget_value* val,
868 Widget parent, Boolean pop_up_p,
869 lw_callback pre_activate_cb, lw_callback selection_cb,
870 lw_callback post_activate_cb, lw_callback highlight_cb)
872 lw_register_widget (type, name, id, val, pre_activate_cb, selection_cb,
873 post_activate_cb, highlight_cb);
874 return lw_make_widget (id, parent, pop_up_p);
878 /* destroying the widgets */
879 static void
880 destroy_one_instance (widget_instance *instance)
882 /* Remove the destroy callback on the widget; that callback will try to
883 dereference the instance object (to set its widget slot to 0, since the
884 widget is dead.) Since the instance is now dead, we don't have to worry
885 about the fact that its widget is dead too.
887 This happens in the Phase2Destroy of the widget, so this callback would
888 not have been run until arbitrarily long after the instance was freed.
890 if (instance->widget)
891 XtRemoveCallback (instance->widget, XtNdestroyCallback,
892 mark_widget_destroyed, (XtPointer)instance);
894 if (instance->widget)
896 /* The else are pretty tricky here, including the empty statement
897 at the end because it would be very bad to destroy a widget
898 twice. */
899 #if defined (USE_LUCID)
900 if (lw_lucid_widget_p (instance->widget))
901 xlw_destroy_instance (instance);
902 else
903 #endif
904 #if defined (USE_MOTIF)
905 if (lw_motif_widget_p (instance->widget))
906 xm_destroy_instance (instance);
907 else
908 #endif
909 #if defined (USE_XAW)
910 if (lw_xaw_widget_p (instance->widget))
911 xaw_destroy_instance (instance);
912 else
913 #endif
914 /* do not remove the empty statement */
918 free_widget_instance (instance);
921 void
922 lw_destroy_widget (Widget w)
924 widget_instance* instance = get_widget_instance (w, True);
926 if (instance)
928 widget_info *info = instance->info;
929 /* instance has already been removed from the list; free it */
930 destroy_one_instance (instance);
931 /* if there are no instances left, free the info too */
932 if (!info->instances)
933 lw_destroy_all_widgets (info->id);
937 void
938 lw_destroy_all_widgets (LWLIB_ID id)
940 widget_info* info = get_widget_info (id, True);
941 widget_instance* instance;
942 widget_instance* next;
944 if (info)
946 for (instance = info->instances; instance; )
948 next = instance->next;
949 destroy_one_instance (instance);
950 instance = next;
952 free_widget_info (info);
956 void
957 lw_destroy_everything (void)
959 while (all_widget_info)
960 lw_destroy_all_widgets (all_widget_info->id);
963 void
964 lw_destroy_all_pop_ups (void)
966 widget_info* info;
967 widget_info* next;
968 widget_instance* instance;
970 for (info = all_widget_info; info; info = next)
972 next = info->next;
973 instance = info->instances;
974 if (instance && instance->pop_up_p)
975 lw_destroy_all_widgets (info->id);
979 #ifdef USE_MOTIF
980 extern Widget first_child (/* Widget */); /* garbage */
981 #endif
983 Widget
984 lw_raise_all_pop_up_widgets (void)
986 widget_info* info;
987 widget_instance* instance;
988 Widget result = NULL;
990 for (info = all_widget_info; info; info = info->next)
991 for (instance = info->instances; instance; instance = instance->next)
992 if (instance->pop_up_p)
994 Widget widget = instance->widget;
995 if (widget)
997 if (XtIsManaged (widget)
998 #ifdef USE_MOTIF
999 /* What a complete load of crap!!!!
1000 When a dialogShell is on the screen, it is not managed!
1002 || (lw_motif_widget_p (instance->widget) &&
1003 XtIsManaged (first_child (widget)))
1004 #endif
1007 if (!result)
1008 result = widget;
1009 XMapRaised (XtDisplay (widget), XtWindow (widget));
1013 return result;
1016 static void
1017 lw_pop_all_widgets (LWLIB_ID id, Boolean up)
1019 widget_info* info = get_widget_info (id, False);
1020 widget_instance* instance;
1022 if (info)
1023 for (instance = info->instances; instance; instance = instance->next)
1024 if (instance->pop_up_p && instance->widget)
1026 #if defined (USE_LUCID)
1027 if (lw_lucid_widget_p (instance->widget))
1029 XtRealizeWidget (instance->widget);
1030 xlw_pop_instance (instance, up);
1032 #endif
1033 #if defined (USE_MOTIF)
1034 if (lw_motif_widget_p (instance->widget))
1036 XtRealizeWidget (instance->widget);
1037 xm_pop_instance (instance, up);
1039 #endif
1040 #if defined (USE_XAW)
1041 if (lw_xaw_widget_p (instance->widget))
1043 XtRealizeWidget (XtParent (instance->widget));
1044 XtRealizeWidget (instance->widget);
1045 xaw_pop_instance (instance, up);
1047 #endif
1051 void
1052 lw_pop_up_all_widgets (LWLIB_ID id)
1054 lw_pop_all_widgets (id, True);
1057 void
1058 lw_pop_down_all_widgets (LWLIB_ID id)
1060 lw_pop_all_widgets (id, False);
1063 void
1064 lw_popup_menu (Widget widget, XEvent *event)
1066 #if defined (USE_LUCID)
1067 if (lw_lucid_widget_p (widget))
1068 xlw_popup_menu (widget, event);
1069 #endif
1070 #if defined (USE_MOTIF)
1071 if (lw_motif_widget_p (widget))
1072 xm_popup_menu (widget, event);
1073 #endif
1074 #if defined (USE_XAW)
1075 if (lw_xaw_widget_p (widget))
1076 xaw_popup_menu (widget, event);
1077 #endif
1080 \f/* get the values back */
1081 static Boolean
1082 get_one_value (widget_instance *instance, widget_value *val)
1084 Widget widget = name_to_widget (instance, val->name);
1086 if (widget)
1088 #if defined (USE_LUCID)
1089 if (lw_lucid_widget_p (instance->widget))
1090 xlw_update_one_value (instance, widget, val);
1091 #endif
1092 #if defined (USE_MOTIF)
1093 if (lw_motif_widget_p (instance->widget))
1094 xm_update_one_value (instance, widget, val);
1095 #endif
1096 #if defined (USE_XAW)
1097 if (lw_xaw_widget_p (instance->widget))
1098 xaw_update_one_value (instance, widget, val);
1099 #endif
1100 return True;
1102 else
1103 return False;
1106 Boolean
1107 lw_get_some_values (LWLIB_ID id, widget_value *val_out)
1109 widget_info* info = get_widget_info (id, False);
1110 widget_instance* instance;
1111 widget_value* val;
1112 Boolean result = False;
1114 if (!info)
1115 return False;
1117 instance = info->instances;
1118 if (!instance)
1119 return False;
1121 for (val = val_out; val; val = val->next)
1122 if (get_one_value (instance, val))
1123 result = True;
1125 return result;
1128 widget_value*
1129 lw_get_all_values (LWLIB_ID id)
1131 widget_info* info = get_widget_info (id, False);
1132 widget_value* val = info->val;
1133 if (lw_get_some_values (id, val))
1134 return val;
1135 else
1136 return NULL;
1139 /* internal function used by the library dependent implementation to get the
1140 widget_value for a given widget in an instance */
1141 widget_value*
1142 lw_get_widget_value_for_widget (widget_instance *instance, Widget w)
1144 char* name = XtName (w);
1145 widget_value* cur;
1146 for (cur = instance->info->val; cur; cur = cur->next)
1147 if (!strcmp (cur->name, name))
1148 return cur;
1149 return NULL;
1152 \f/* update other instances value when one thing changed */
1154 /* To forbid recursive calls */
1155 static Boolean lwlib_updating;
1157 /* This function can be used as a an XtCallback for the widgets that get
1158 modified to update other instances of the widgets. Closure should be the
1159 widget_instance. */
1160 void
1161 lw_internal_update_other_instances (Widget widget,
1162 XtPointer closure,
1163 XtPointer call_data)
1165 widget_instance* instance = (widget_instance*)closure;
1166 char* name = XtName (widget);
1167 widget_info* info;
1168 widget_instance* cur;
1169 widget_value* val;
1171 /* Avoid possibly infinite recursion. */
1172 if (lwlib_updating)
1173 return;
1175 /* protect against the widget being destroyed */
1176 if (XtWidgetBeingDestroyedP (widget))
1177 return;
1179 /* Return immediately if there are no other instances */
1180 info = instance->info;
1181 if (!info->instances->next)
1182 return;
1184 lwlib_updating = True;
1186 for (val = info->val; val && strcmp (val->name, name); val = val->next);
1188 if (val && get_one_value (instance, val))
1189 for (cur = info->instances; cur; cur = cur->next)
1190 if (cur != instance)
1191 set_one_value (cur, val, True);
1193 lwlib_updating = False;
1197 \f/* get the id */
1199 LWLIB_ID
1200 lw_get_widget_id (Widget w)
1202 widget_instance* instance = get_widget_instance (w, False);
1204 return instance ? instance->info->id : 0;
1207 \f/* set the keyboard focus */
1208 void
1209 lw_set_keyboard_focus (Widget parent, Widget w)
1211 #if defined (USE_MOTIF)
1212 xm_set_keyboard_focus (parent, w);
1213 #else
1214 XtSetKeyboardFocus (parent, w);
1215 #endif
1218 \f/* Show busy */
1219 static void
1220 show_one_widget_busy (Widget w, Boolean flag)
1222 Pixel foreground = 0;
1223 Pixel background = 1;
1224 Widget widget_to_invert = XtNameToWidget (w, "*sheet");
1225 if (!widget_to_invert)
1226 widget_to_invert = w;
1228 XtVaGetValues (widget_to_invert,
1229 XtNforeground, &foreground,
1230 XtNbackground, &background,
1231 NULL);
1232 XtVaSetValues (widget_to_invert,
1233 XtNforeground, background,
1234 XtNbackground, foreground,
1235 NULL);
1238 void
1239 lw_show_busy (Widget w, Boolean busy)
1241 widget_instance* instance = get_widget_instance (w, False);
1242 widget_info* info;
1243 widget_instance* next;
1245 if (instance)
1247 info = instance->info;
1248 if (info->busy != busy)
1250 for (next = info->instances; next; next = next->next)
1251 if (next->widget)
1252 show_one_widget_busy (next->widget, busy);
1253 info->busy = busy;
1258 /* This hack exists because Lucid/Athena need to execute the strange
1259 function below to support geometry management. */
1260 void
1261 lw_refigure_widget (Widget w, Boolean doit)
1263 #if defined (USE_XAW)
1264 XawPanedSetRefigureMode (w, doit);
1265 #endif
1266 #if defined (USE_MOTIF)
1267 if (doit)
1268 XtManageChild (w);
1269 else
1270 XtUnmanageChild (w);
1271 #endif
1274 /* Toolkit independent way of determining if an event window is in the
1275 menubar. */
1276 Boolean
1277 lw_window_is_in_menubar (Window win, Widget menubar_widget)
1279 return menubar_widget
1280 #if defined (USE_LUCID)
1281 && XtWindow (menubar_widget) == win;
1282 #endif
1283 #if defined (USE_MOTIF)
1284 && ((XtWindow (menubar_widget) == win)
1285 || (XtWindowToWidget (XtDisplay (menubar_widget), win)
1286 && (XtParent (XtWindowToWidget (XtDisplay (menubar_widget), win))
1287 == menubar_widget)));
1288 #endif
1291 /* Motif hack to set the main window areas. */
1292 void
1293 lw_set_main_areas (Widget parent, Widget menubar, Widget work_area)
1295 #if defined (USE_MOTIF)
1296 xm_set_main_areas (parent, menubar, work_area);
1297 #endif
1300 /* Manage resizing for Motif. This disables resizing when the menubar
1301 is about to be modified. */
1302 void
1303 lw_allow_resizing (Widget w, Boolean flag)
1305 #if defined (USE_MOTIF)
1306 xm_manage_resizing (w, flag);
1307 #endif
1311 /* Value is non-zero if LABEL is a menu separator. If it is, *TYPE is
1312 set to an appropriate enumerator of type enum menu_separator.
1313 MOTIF_P non-zero means map separator types not supported by Motif
1314 to similar ones that are supported. */
1317 lw_separator_p (const char *label, enum menu_separator *type, int motif_p)
1319 int separator_p = 0;
1321 if (strlen (label) >= 3
1322 && memcmp (label, "--:", 3) == 0)
1324 static struct separator_table
1326 const char *name;
1327 enum menu_separator type;
1329 separator_names[] =
1331 {"space", SEPARATOR_NO_LINE},
1332 {"noLine", SEPARATOR_NO_LINE},
1333 {"singleLine", SEPARATOR_SINGLE_LINE},
1334 {"doubleLine", SEPARATOR_DOUBLE_LINE},
1335 {"singleDashedLine", SEPARATOR_SINGLE_DASHED_LINE},
1336 {"doubleDashedLine", SEPARATOR_DOUBLE_DASHED_LINE},
1337 {"shadowEtchedIn", SEPARATOR_SHADOW_ETCHED_IN},
1338 {"shadowEtchedOut", SEPARATOR_SHADOW_ETCHED_OUT},
1339 {"shadowEtchedInDash", SEPARATOR_SHADOW_ETCHED_IN_DASH},
1340 {"shadowEtchedOutDash", SEPARATOR_SHADOW_ETCHED_OUT_DASH},
1341 {"shadowDoubleEtchedIn", SEPARATOR_SHADOW_DOUBLE_ETCHED_IN},
1342 {"shadowDoubleEtchedOut", SEPARATOR_SHADOW_DOUBLE_ETCHED_OUT},
1343 {"shadowDoubleEtchedInDash", SEPARATOR_SHADOW_DOUBLE_ETCHED_IN_DASH},
1344 {"shadowDoubleEtchedOutDash", SEPARATOR_SHADOW_DOUBLE_ETCHED_OUT_DASH},
1345 {0,0}
1348 int i;
1350 label += 3;
1351 for (i = 0; separator_names[i].name; ++i)
1352 if (strcmp (label, separator_names[i].name) == 0)
1354 separator_p = 1;
1355 *type = separator_names[i].type;
1357 /* If separator type is not supported under Motif,
1358 use a similar one. */
1359 if (motif_p && *type >= SEPARATOR_SHADOW_DOUBLE_ETCHED_IN)
1360 *type -= 4;
1361 break;
1364 else if (strlen (label) > 3
1365 && memcmp (label, "--", 2) == 0
1366 && label[2] != '-')
1368 /* Alternative, more Emacs-style names. */
1369 static struct separator_table
1371 const char *name;
1372 enum menu_separator type;
1374 separator_names[] =
1376 {"space", SEPARATOR_NO_LINE},
1377 {"no-line", SEPARATOR_NO_LINE},
1378 {"single-line", SEPARATOR_SINGLE_LINE},
1379 {"double-line", SEPARATOR_DOUBLE_LINE},
1380 {"single-dashed-line", SEPARATOR_SINGLE_DASHED_LINE},
1381 {"double-dashed-line", SEPARATOR_DOUBLE_DASHED_LINE},
1382 {"shadow-etched-in", SEPARATOR_SHADOW_ETCHED_IN},
1383 {"shadow-etched-out", SEPARATOR_SHADOW_ETCHED_OUT},
1384 {"shadow-etched-in-dash", SEPARATOR_SHADOW_ETCHED_IN_DASH},
1385 {"shadow-etched-out-dash", SEPARATOR_SHADOW_ETCHED_OUT_DASH},
1386 {"shadow-double-etched-in", SEPARATOR_SHADOW_DOUBLE_ETCHED_IN},
1387 {"shadow-double-etched-out", SEPARATOR_SHADOW_DOUBLE_ETCHED_OUT},
1388 {"shadow-double-etched-in-dash", SEPARATOR_SHADOW_DOUBLE_ETCHED_IN_DASH},
1389 {"shadow-double-etched-out-dash",SEPARATOR_SHADOW_DOUBLE_ETCHED_OUT_DASH},
1390 {0,0}
1393 int i;
1395 label += 2;
1396 for (i = 0; separator_names[i].name; ++i)
1397 if (strcmp (label, separator_names[i].name) == 0)
1399 separator_p = 1;
1400 *type = separator_names[i].type;
1402 /* If separator type is not supported under Motif,
1403 use a similar one. */
1404 if (motif_p && *type >= SEPARATOR_SHADOW_DOUBLE_ETCHED_IN)
1405 *type -= 4;
1406 break;
1409 else
1411 /* Old-style separator, maybe. It's a separator if it contains
1412 only dashes. */
1413 while (*label == '-')
1414 ++label;
1415 separator_p = *label == 0;
1416 *type = SEPARATOR_SHADOW_ETCHED_IN;
1419 return separator_p;