New macro with-temp-buffer-window and related fixes.
[emacs.git] / lwlib / lwlib.c
blobad3792dd59d7a3cf9508aa76fea508b63f1d4c2d
1 /* A general interface to the widgets of different toolkits.
3 Copyright (C) 1992, 1993 Lucid, Inc.
4 Copyright (C) 1994-1996, 1999-2012 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 #include <config.h>
25 #include <setjmp.h>
26 #include <lisp.h>
27 #include <c-strcase.h>
29 #include <sys/types.h>
30 #include <stdio.h>
31 #include "lwlib-int.h"
32 #include "lwlib-utils.h"
33 #include <X11/StringDefs.h>
35 #if defined (USE_LUCID)
36 #include "lwlib-Xlw.h"
37 #endif
38 #if defined (USE_MOTIF)
39 #include "lwlib-Xm.h"
40 #else /* not USE_MOTIF */
41 #if defined (USE_LUCID)
42 #define USE_XAW
43 #endif /* not USE_MOTIF && USE_LUCID */
44 #endif
45 #if defined (USE_XAW)
46 #ifdef HAVE_XAW3D
47 #include <X11/Xaw3d/Paned.h>
48 #else /* !HAVE_XAW3D */
49 #include <X11/Xaw/Paned.h>
50 #endif /* HAVE_XAW3D */
51 #include "lwlib-Xaw.h"
52 #endif
54 #if !defined (USE_LUCID) && !defined (USE_MOTIF)
55 #error At least one of USE_LUCID or USE_MOTIF must be defined.
56 #endif
58 #ifndef max
59 #define max(x, y) ((x) > (y) ? (x) : (y))
60 #endif
62 /* List of all widgets managed by the library. */
63 static widget_info*
64 all_widget_info = NULL;
66 #ifdef USE_MOTIF
67 const char *lwlib_toolkit_type = "motif";
68 #else
69 const char *lwlib_toolkit_type = "lucid";
70 #endif
72 static widget_value *merge_widget_value (widget_value *,
73 widget_value *,
74 int, int *);
75 static void instantiate_widget_instance (widget_instance *);
76 static void safe_free_str (char *);
77 static void free_widget_value_tree (widget_value *);
78 static widget_value *copy_widget_value_tree (widget_value *,
79 change_type);
80 static widget_info *allocate_widget_info (const char *, const char *, LWLIB_ID,
81 widget_value *,
82 lw_callback, lw_callback,
83 lw_callback, lw_callback);
84 static void free_widget_info (widget_info *);
85 static void mark_widget_destroyed (Widget, XtPointer, XtPointer);
86 static widget_instance *allocate_widget_instance (widget_info *,
87 Widget, Boolean);
88 static void free_widget_instance (widget_instance *);
89 static widget_info *get_widget_info (LWLIB_ID, Boolean);
90 static widget_instance *get_widget_instance (Widget, Boolean);
91 static widget_instance *find_instance (LWLIB_ID, Widget, Boolean);
92 static Boolean safe_strcmp (const char *, const char *);
93 static Widget name_to_widget (widget_instance *, const char *);
94 static void set_one_value (widget_instance *, widget_value *, Boolean);
95 static void update_one_widget_instance (widget_instance *, Boolean);
96 static void update_all_widget_values (widget_info *, Boolean);
97 static void initialize_widget_instance (widget_instance *);
98 static widget_creation_function find_in_table (const char *, const widget_creation_entry *);
99 static Boolean dialog_spec_p (const char *);
100 static void destroy_one_instance (widget_instance *);
101 static void lw_pop_all_widgets (LWLIB_ID, Boolean);
102 static Boolean get_one_value (widget_instance *, widget_value *);
103 static void show_one_widget_busy (Widget, Boolean);
104 \f/* utility functions for widget_instance and widget_info */
105 char *
106 safe_strdup (const char *s)
108 char *result;
109 if (! s) return 0;
110 result = (char *) xmalloc (strlen (s) + 1);
111 strcpy (result, s);
112 return result;
115 static void
116 safe_free_str (char *s)
118 xfree (s);
121 static widget_value *widget_value_free_list = 0;
122 static int malloc_cpt = 0;
124 widget_value *
125 malloc_widget_value (void)
127 widget_value *wv;
128 if (widget_value_free_list)
130 wv = widget_value_free_list;
131 widget_value_free_list = wv->free_list;
132 wv->free_list = 0;
134 else
136 wv = (widget_value *) xmalloc (sizeof (widget_value));
137 malloc_cpt++;
139 memset ((void*) wv, 0, sizeof (widget_value));
140 return wv;
143 /* this is analogous to free(). It frees only what was allocated
144 by malloc_widget_value(), and no substructures.
146 void
147 free_widget_value (widget_value *wv)
149 if (wv->free_list)
150 abort ();
152 if (malloc_cpt > 25)
154 /* When the number of already allocated cells is too big,
155 We free it. */
156 xfree (wv);
157 malloc_cpt--;
159 else
161 wv->free_list = widget_value_free_list;
162 widget_value_free_list = wv;
166 static void
167 free_widget_value_tree (widget_value *wv)
169 if (!wv)
170 return;
172 xfree (wv->name);
173 xfree (wv->value);
174 xfree (wv->key);
176 wv->name = wv->value = wv->key = (char *) 0xDEADBEEF;
178 if (wv->toolkit_data && wv->free_toolkit_data)
180 XtFree (wv->toolkit_data);
181 wv->toolkit_data = (void *) 0xDEADBEEF;
184 if (wv->contents && (wv->contents != (widget_value*)1))
186 free_widget_value_tree (wv->contents);
187 wv->contents = (widget_value *) 0xDEADBEEF;
189 if (wv->next)
191 free_widget_value_tree (wv->next);
192 wv->next = (widget_value *) 0xDEADBEEF;
194 free_widget_value (wv);
197 static widget_value *
198 copy_widget_value_tree (widget_value *val, change_type change)
200 widget_value* copy;
202 if (!val)
203 return NULL;
204 if (val == (widget_value *) 1)
205 return val;
207 copy = malloc_widget_value ();
208 copy->name = safe_strdup (val->name);
209 copy->value = safe_strdup (val->value);
210 copy->key = safe_strdup (val->key);
211 copy->help = val->help;
212 copy->enabled = val->enabled;
213 copy->button_type = val->button_type;
214 copy->selected = val->selected;
215 copy->edited = False;
216 copy->change = change;
217 copy->this_one_change = change;
218 copy->contents = copy_widget_value_tree (val->contents, change);
219 copy->call_data = val->call_data;
220 copy->next = copy_widget_value_tree (val->next, change);
221 copy->toolkit_data = NULL;
222 copy->free_toolkit_data = False;
223 return copy;
226 static widget_info *
227 allocate_widget_info (const char* type,
228 const char* name,
229 LWLIB_ID id,
230 widget_value* val,
231 lw_callback pre_activate_cb,
232 lw_callback selection_cb,
233 lw_callback post_activate_cb,
234 lw_callback highlight_cb)
236 widget_info* info = (widget_info*) xmalloc (sizeof (widget_info));
237 info->type = safe_strdup (type);
238 info->name = safe_strdup (name);
239 info->id = id;
240 info->val = copy_widget_value_tree (val, STRUCTURAL_CHANGE);
241 info->busy = False;
242 info->pre_activate_cb = pre_activate_cb;
243 info->selection_cb = selection_cb;
244 info->post_activate_cb = post_activate_cb;
245 info->highlight_cb = highlight_cb;
246 info->instances = NULL;
248 info->next = all_widget_info;
249 all_widget_info = info;
251 return info;
254 static void
255 free_widget_info (widget_info *info)
257 safe_free_str (info->type);
258 safe_free_str (info->name);
259 free_widget_value_tree (info->val);
260 memset ((void*)info, 0xDEADBEEF, sizeof (widget_info));
261 xfree (info);
264 static void
265 mark_widget_destroyed (Widget widget, XtPointer closure, XtPointer call_data)
267 widget_instance* instance = (widget_instance*)closure;
269 /* be very conservative */
270 if (instance->widget == widget)
271 instance->widget = NULL;
274 static widget_instance *
275 allocate_widget_instance (widget_info* info, Widget parent, Boolean pop_up_p)
277 widget_instance* instance =
278 (widget_instance*) xmalloc (sizeof (widget_instance));
279 memset (instance, 0, sizeof *instance);
280 instance->parent = parent;
281 instance->pop_up_p = pop_up_p;
282 instance->info = info;
283 instance->next = info->instances;
284 info->instances = instance;
286 instantiate_widget_instance (instance);
288 XtAddCallback (instance->widget, XtNdestroyCallback,
289 mark_widget_destroyed, (XtPointer)instance);
290 return instance;
293 static void
294 free_widget_instance (widget_instance *instance)
296 memset ((void*)instance, 0xDEADBEEF, sizeof (widget_instance));
297 xfree (instance);
300 static widget_info *
301 get_widget_info (LWLIB_ID id, Boolean remove_p)
303 widget_info* info;
304 widget_info* prev;
305 for (prev = NULL, info = all_widget_info;
306 info;
307 prev = info, info = info->next)
308 if (info->id == id)
310 if (remove_p)
312 if (prev)
313 prev->next = info->next;
314 else
315 all_widget_info = info->next;
317 return info;
319 return NULL;
322 /* Internal function used by the library dependent implementation to get the
323 widget_value for a given widget in an instance */
324 widget_info *
325 lw_get_widget_info (LWLIB_ID id)
327 return get_widget_info (id, 0);
330 static widget_instance *
331 get_widget_instance (Widget widget, Boolean remove_p)
333 widget_info* info;
334 widget_instance* instance;
335 widget_instance* prev;
336 for (info = all_widget_info; info; info = info->next)
337 for (prev = NULL, instance = info->instances;
338 instance;
339 prev = instance, instance = instance->next)
340 if (instance->widget == widget)
342 if (remove_p)
344 if (prev)
345 prev->next = instance->next;
346 else
347 info->instances = instance->next;
349 return instance;
351 return (widget_instance *) 0;
354 /* Value is a pointer to the widget_instance corresponding to
355 WIDGET, or null if WIDGET is not a lwlib widget. */
357 widget_instance *
358 lw_get_widget_instance (Widget widget)
360 return get_widget_instance (widget, False);
363 static widget_instance*
364 find_instance (LWLIB_ID id, Widget parent, Boolean pop_up_p)
366 widget_info* info = get_widget_info (id, False);
367 widget_instance* instance;
369 if (info)
370 for (instance = info->instances; instance; instance = instance->next)
371 if (instance->parent == parent && instance->pop_up_p == pop_up_p)
372 return instance;
374 return NULL;
378 /* utility function for widget_value */
379 static Boolean
380 safe_strcmp (const char *s1, const char *s2)
382 if (!!s1 ^ !!s2) return True;
383 return (s1 && s2) ? strcmp (s1, s2) : s1 ? False : !!s2;
387 #if 0
388 # define EXPLAIN(name, oc, nc, desc, a1, a2) \
389 printf ("Change: \"%s\"\tmax(%s=%d,%s=%d)\t%s %d %d\n", \
390 name, \
391 (oc == NO_CHANGE ? "none" : \
392 (oc == INVISIBLE_CHANGE ? "invisible" : \
393 (oc == VISIBLE_CHANGE ? "visible" : \
394 (oc == STRUCTURAL_CHANGE ? "structural" : "???")))), \
395 oc, \
396 (nc == NO_CHANGE ? "none" : \
397 (nc == INVISIBLE_CHANGE ? "invisible" : \
398 (nc == VISIBLE_CHANGE ? "visible" : \
399 (nc == STRUCTURAL_CHANGE ? "structural" : "???")))), \
400 nc, desc, a1, a2)
401 #else
402 # define EXPLAIN(name, oc, nc, desc, a1, a2) ((void) 0)
403 #endif
406 static widget_value *
407 merge_widget_value (widget_value *val1,
408 widget_value *val2,
409 int level,
410 int *change_p)
412 change_type change, this_one_change;
413 widget_value* merged_next;
414 widget_value* merged_contents;
416 if (!val1)
418 if (val2)
420 *change_p = 1;
421 return copy_widget_value_tree (val2, STRUCTURAL_CHANGE);
423 else
424 return NULL;
426 if (!val2)
428 *change_p = 1;
429 free_widget_value_tree (val1);
430 return NULL;
433 change = NO_CHANGE;
435 if (safe_strcmp (val1->name, val2->name))
437 EXPLAIN (val1->name, change, STRUCTURAL_CHANGE, "name change",
438 val1->name, val2->name);
439 change = max (change, STRUCTURAL_CHANGE);
440 safe_free_str (val1->name);
441 val1->name = safe_strdup (val2->name);
443 if (safe_strcmp (val1->value, val2->value))
445 EXPLAIN (val1->name, change, VISIBLE_CHANGE, "value change",
446 val1->value, val2->value);
447 change = max (change, VISIBLE_CHANGE);
448 safe_free_str (val1->value);
449 val1->value = safe_strdup (val2->value);
451 if (safe_strcmp (val1->key, val2->key))
453 EXPLAIN (val1->name, change, VISIBLE_CHANGE, "key change",
454 val1->key, val2->key);
455 change = max (change, VISIBLE_CHANGE);
456 safe_free_str (val1->key);
457 val1->key = safe_strdup (val2->key);
459 if (! EQ (val1->help, val2->help))
461 EXPLAIN (val1->name, change, VISIBLE_CHANGE, "help change",
462 val1->help, val2->help);
463 change = max (change, VISIBLE_CHANGE);
464 val1->help = val2->help;
466 if (val1->enabled != val2->enabled)
468 EXPLAIN (val1->name, change, VISIBLE_CHANGE, "enablement change",
469 val1->enabled, val2->enabled);
470 change = max (change, VISIBLE_CHANGE);
471 val1->enabled = val2->enabled;
473 if (val1->button_type != val2->button_type)
475 EXPLAIN (val1->name, change, VISIBLE_CHANGE, "button type change",
476 val1->button_type, val2->button_type);
477 change = max (change, VISIBLE_CHANGE);
478 val1->button_type = val2->button_type;
480 if (val1->selected != val2->selected)
482 EXPLAIN (val1->name, change, VISIBLE_CHANGE, "selection change",
483 val1->selected, val2->selected);
484 change = max (change, VISIBLE_CHANGE);
485 val1->selected = val2->selected;
487 if (val1->call_data != val2->call_data)
489 EXPLAIN (val1->name, change, INVISIBLE_CHANGE, "call-data change",
490 val1->call_data, val2->call_data);
491 change = max (change, INVISIBLE_CHANGE);
492 val1->call_data = val2->call_data;
495 if (level > 0)
497 merged_contents =
498 merge_widget_value (val1->contents, val2->contents, level - 1,
499 change_p);
501 if (val1->contents && !merged_contents)
503 /* This used to say INVISIBLE_CHANGE,
504 but it is visible and vitally important when
505 the contents of the menu bar itself are entirely deleted.
507 But maybe it doesn't matter. This fails to fix the bug. */
508 EXPLAIN (val1->name, change, STRUCTURAL_CHANGE, "(contents gone)",
509 0, 0);
510 change = max (change, STRUCTURAL_CHANGE);
512 else if (merged_contents && merged_contents->change != NO_CHANGE)
514 EXPLAIN (val1->name, change, INVISIBLE_CHANGE, "(contents change)",
515 0, 0);
516 change = max (change, INVISIBLE_CHANGE);
517 #if 0 /* This was replaced by the August 9 1996 change in lwlib-Xm.c. */
518 #ifdef USE_MOTIF
519 change = max (merged_contents->change, change);
520 #endif
521 #endif
524 val1->contents = merged_contents;
527 this_one_change = change;
529 merged_next = merge_widget_value (val1->next, val2->next, level, change_p);
531 if (val1->next && !merged_next)
533 EXPLAIN (val1->name, change, STRUCTURAL_CHANGE, "(following gone)",
534 0, 0);
535 change = max (change, STRUCTURAL_CHANGE);
537 else if (merged_next)
539 if (merged_next->change)
540 EXPLAIN (val1->name, change, merged_next->change, "(following change)",
541 0, 0);
542 change = max (change, merged_next->change);
545 val1->next = merged_next;
547 val1->this_one_change = this_one_change;
548 val1->change = change;
550 if (change > NO_CHANGE && val1->toolkit_data)
552 *change_p = 1;
553 if (val1->free_toolkit_data)
554 XtFree (val1->toolkit_data);
555 val1->toolkit_data = NULL;
558 return val1;
562 /* modifying the widgets */
563 static Widget
564 name_to_widget (widget_instance *instance, const char *name)
566 Widget widget = NULL;
568 if (!instance->widget)
569 return NULL;
571 if (!strcmp (XtName (instance->widget), name))
572 widget = instance->widget;
573 else
575 int length = strlen (name) + 2;
576 char* real_name = (char *) xmalloc (length);
577 real_name [0] = '*';
578 strcpy (real_name + 1, name);
580 widget = XtNameToWidget (instance->widget, real_name);
582 xfree (real_name);
584 return widget;
587 static void
588 set_one_value (widget_instance* instance, widget_value* val, Boolean deep_p)
590 Widget widget = name_to_widget (instance, val->name);
592 if (widget)
594 #if defined (USE_LUCID)
595 if (lw_lucid_widget_p (instance->widget))
596 xlw_update_one_widget (instance, widget, val, deep_p);
597 #endif
598 #if defined (USE_MOTIF)
599 if (lw_motif_widget_p (instance->widget))
600 xm_update_one_widget (instance, widget, val, deep_p);
601 #endif
602 #if defined (USE_XAW)
603 if (lw_xaw_widget_p (instance->widget))
604 xaw_update_one_widget (instance, widget, val, deep_p);
605 #endif
609 static void
610 update_one_widget_instance (widget_instance* instance, Boolean deep_p)
612 widget_value *val;
614 if (!instance->widget)
615 /* the widget was destroyed */
616 return;
618 for (val = instance->info->val; val; val = val->next)
619 if (val->change != NO_CHANGE)
620 set_one_value (instance, val, deep_p);
623 static void
624 update_all_widget_values (widget_info* info, Boolean deep_p)
626 widget_instance* instance;
627 widget_value* val;
629 for (instance = info->instances; instance; instance = instance->next)
630 update_one_widget_instance (instance, deep_p);
632 for (val = info->val; val; val = val->next)
633 val->change = NO_CHANGE;
637 lw_modify_all_widgets (LWLIB_ID id, widget_value* val, Boolean deep_p)
639 widget_info* info = get_widget_info (id, False);
640 widget_value* new_val;
641 widget_value* next_new_val;
642 widget_value* cur;
643 widget_value* prev;
644 widget_value* next;
645 int found;
646 int change_p = 0;
648 if (!info)
649 return 0;
651 for (new_val = val; new_val; new_val = new_val->next)
653 next_new_val = new_val->next;
654 new_val->next = NULL;
655 found = False;
656 for (prev = NULL, cur = info->val; cur; prev = cur, cur = cur->next)
657 if (!strcmp (cur->name, new_val->name))
659 found = True;
660 next = cur->next;
661 cur->next = NULL;
662 cur = merge_widget_value (cur, new_val, deep_p ? 1000 : 1,
663 &change_p);
664 if (prev)
665 prev->next = cur ? cur : next;
666 else
667 info->val = cur ? cur : next;
668 if (cur)
669 cur->next = next;
670 break;
672 if (!found)
674 /* Could not find it, add it */
675 if (prev)
676 prev->next = copy_widget_value_tree (new_val, STRUCTURAL_CHANGE);
677 else
678 info->val = copy_widget_value_tree (new_val, STRUCTURAL_CHANGE);
679 change_p = 1;
681 new_val->next = next_new_val;
684 update_all_widget_values (info, deep_p);
685 return change_p;
689 /* creating the widgets */
691 static void
692 initialize_widget_instance (widget_instance *instance)
694 widget_value* val;
696 for (val = instance->info->val; val; val = val->next)
697 val->change = STRUCTURAL_CHANGE;
699 update_one_widget_instance (instance, True);
701 for (val = instance->info->val; val; val = val->next)
702 val->change = NO_CHANGE;
706 static widget_creation_function
707 find_in_table (const char *type, const widget_creation_entry *table)
709 const widget_creation_entry* cur;
710 for (cur = table; cur->type; cur++)
711 if (!c_strcasecmp (type, cur->type))
712 return cur->function;
713 return NULL;
716 static Boolean
717 dialog_spec_p (const char *name)
719 /* return True if name matches [EILPQeilpq][1-9][Bb] or
720 [EILPQeilpq][1-9][Bb][Rr][1-9] */
721 if (!name)
722 return False;
724 switch (name [0])
726 case 'E': case 'I': case 'L': case 'P': case 'Q':
727 case 'e': case 'i': case 'l': case 'p': case 'q':
728 if (name [1] >= '0' && name [1] <= '9')
730 if (name [2] != 'B' && name [2] != 'b')
731 return False;
732 if (!name [3])
733 return True;
734 if ((name [3] == 'T' || name [3] == 't') && !name [4])
735 return True;
736 if ((name [3] == 'R' || name [3] == 'r')
737 && name [4] >= '0' && name [4] <= '9' && !name [5])
738 return True;
739 return False;
741 else
742 return False;
744 default:
745 return False;
749 static void
750 instantiate_widget_instance (widget_instance *instance)
752 widget_creation_function function = NULL;
754 #if defined (USE_LUCID)
755 if (!function)
756 function = find_in_table (instance->info->type, xlw_creation_table);
757 #endif
758 #if defined(USE_MOTIF)
759 if (!function)
760 function = find_in_table (instance->info->type, xm_creation_table);
761 #endif
762 #if defined (USE_XAW)
763 if (!function)
764 function = find_in_table (instance->info->type, xaw_creation_table);
765 #endif
767 if (!function)
769 if (dialog_spec_p (instance->info->type))
771 #if defined (USE_LUCID)
772 /* not yet */
773 #endif
774 #if defined(USE_MOTIF)
775 if (!function)
776 function = xm_create_dialog;
777 #endif
778 #if defined (USE_XAW)
779 if (!function)
780 function = xaw_create_dialog;
781 #endif
785 if (!function)
787 printf ("No creation function for widget type %s\n",
788 instance->info->type);
789 abort ();
792 instance->widget = (*function) (instance);
794 if (!instance->widget)
795 abort ();
797 /* XtRealizeWidget (instance->widget);*/
800 void
801 lw_register_widget (const char* type,
802 const char* name,
803 LWLIB_ID id,
804 widget_value* val,
805 lw_callback pre_activate_cb,
806 lw_callback selection_cb,
807 lw_callback post_activate_cb,
808 lw_callback highlight_cb)
810 if (!get_widget_info (id, False))
811 allocate_widget_info (type, name, id, val, pre_activate_cb, selection_cb,
812 post_activate_cb, highlight_cb);
815 Widget
816 lw_get_widget (LWLIB_ID id, Widget parent, Boolean pop_up_p)
818 widget_instance* instance;
820 instance = find_instance (id, parent, pop_up_p);
821 return instance ? instance->widget : NULL;
824 Widget
825 lw_make_widget (LWLIB_ID id, Widget parent, Boolean pop_up_p)
827 widget_instance* instance;
828 widget_info* info;
830 instance = find_instance (id, parent, pop_up_p);
831 if (!instance)
833 info = get_widget_info (id, False);
834 if (!info)
835 return NULL;
836 instance = allocate_widget_instance (info, parent, pop_up_p);
837 initialize_widget_instance (instance);
839 if (!instance->widget)
840 abort ();
841 return instance->widget;
844 Widget
845 lw_create_widget (const char* type, const char* name, LWLIB_ID id, widget_value* val,
846 Widget parent, Boolean pop_up_p,
847 lw_callback pre_activate_cb, lw_callback selection_cb,
848 lw_callback post_activate_cb, lw_callback highlight_cb)
850 lw_register_widget (type, name, id, val, pre_activate_cb, selection_cb,
851 post_activate_cb, highlight_cb);
852 return lw_make_widget (id, parent, pop_up_p);
856 /* destroying the widgets */
857 static void
858 destroy_one_instance (widget_instance *instance)
860 /* Remove the destroy callback on the widget; that callback will try to
861 dereference the instance object (to set its widget slot to 0, since the
862 widget is dead.) Since the instance is now dead, we don't have to worry
863 about the fact that its widget is dead too.
865 This happens in the Phase2Destroy of the widget, so this callback would
866 not have been run until arbitrarily long after the instance was freed.
868 if (instance->widget)
869 XtRemoveCallback (instance->widget, XtNdestroyCallback,
870 mark_widget_destroyed, (XtPointer)instance);
872 if (instance->widget)
874 /* The else are pretty tricky here, including the empty statement
875 at the end because it would be very bad to destroy a widget
876 twice. */
877 #if defined (USE_LUCID)
878 if (lw_lucid_widget_p (instance->widget))
879 xlw_destroy_instance (instance);
880 else
881 #endif
882 #if defined (USE_MOTIF)
883 if (lw_motif_widget_p (instance->widget))
884 xm_destroy_instance (instance);
885 else
886 #endif
887 #if defined (USE_XAW)
888 if (lw_xaw_widget_p (instance->widget))
889 xaw_destroy_instance (instance);
890 else
891 #endif
893 /* Empty compound statement to terminate if-then-else chain. */
897 free_widget_instance (instance);
900 void
901 lw_destroy_widget (Widget w)
903 widget_instance* instance = get_widget_instance (w, True);
905 if (instance)
907 widget_info *info = instance->info;
908 /* instance has already been removed from the list; free it */
909 destroy_one_instance (instance);
910 /* if there are no instances left, free the info too */
911 if (!info->instances)
912 lw_destroy_all_widgets (info->id);
916 void
917 lw_destroy_all_widgets (LWLIB_ID id)
919 widget_info* info = get_widget_info (id, True);
920 widget_instance* instance;
921 widget_instance* next;
923 if (info)
925 for (instance = info->instances; instance; )
927 next = instance->next;
928 destroy_one_instance (instance);
929 instance = next;
931 free_widget_info (info);
935 void
936 lw_destroy_everything (void)
938 while (all_widget_info)
939 lw_destroy_all_widgets (all_widget_info->id);
942 void
943 lw_destroy_all_pop_ups (void)
945 widget_info* info;
946 widget_info* next;
947 widget_instance* instance;
949 for (info = all_widget_info; info; info = next)
951 next = info->next;
952 instance = info->instances;
953 if (instance && instance->pop_up_p)
954 lw_destroy_all_widgets (info->id);
958 #ifdef USE_MOTIF
959 extern Widget first_child (Widget); /* garbage */
960 #endif
962 Widget
963 lw_raise_all_pop_up_widgets (void)
965 widget_info* info;
966 widget_instance* instance;
967 Widget result = NULL;
969 for (info = all_widget_info; info; info = info->next)
970 for (instance = info->instances; instance; instance = instance->next)
971 if (instance->pop_up_p)
973 Widget widget = instance->widget;
974 if (widget)
976 if (XtIsManaged (widget)
977 #ifdef USE_MOTIF
978 /* What a complete load of crap!!!!
979 When a dialogShell is on the screen, it is not managed!
981 || (lw_motif_widget_p (instance->widget) &&
982 XtIsManaged (first_child (widget)))
983 #endif
986 if (!result)
987 result = widget;
988 XMapRaised (XtDisplay (widget), XtWindow (widget));
992 return result;
995 static void
996 lw_pop_all_widgets (LWLIB_ID id, Boolean up)
998 widget_info* info = get_widget_info (id, False);
999 widget_instance* instance;
1001 if (info)
1002 for (instance = info->instances; instance; instance = instance->next)
1003 if (instance->pop_up_p && instance->widget)
1005 #if defined (USE_LUCID)
1006 if (lw_lucid_widget_p (instance->widget))
1008 XtRealizeWidget (instance->widget);
1009 xlw_pop_instance (instance, up);
1011 #endif
1012 #if defined (USE_MOTIF)
1013 if (lw_motif_widget_p (instance->widget))
1015 XtRealizeWidget (instance->widget);
1016 xm_pop_instance (instance, up);
1018 #endif
1019 #if defined (USE_XAW)
1020 if (lw_xaw_widget_p (instance->widget))
1022 XtRealizeWidget (XtParent (instance->widget));
1023 XtRealizeWidget (instance->widget);
1024 xaw_pop_instance (instance, up);
1026 #endif
1030 void
1031 lw_pop_up_all_widgets (LWLIB_ID id)
1033 lw_pop_all_widgets (id, True);
1036 void
1037 lw_pop_down_all_widgets (LWLIB_ID id)
1039 lw_pop_all_widgets (id, False);
1042 void
1043 lw_popup_menu (Widget widget, XEvent *event)
1045 #if defined (USE_LUCID)
1046 if (lw_lucid_widget_p (widget))
1047 xlw_popup_menu (widget, event);
1048 #endif
1049 #if defined (USE_MOTIF)
1050 if (lw_motif_widget_p (widget))
1051 xm_popup_menu (widget, event);
1052 #endif
1053 #if defined (USE_XAW)
1054 if (lw_xaw_widget_p (widget))
1055 xaw_popup_menu (widget, event);
1056 #endif
1059 \f/* get the values back */
1060 static Boolean
1061 get_one_value (widget_instance *instance, widget_value *val)
1063 Widget widget = name_to_widget (instance, val->name);
1065 if (widget)
1067 #if defined (USE_LUCID)
1068 if (lw_lucid_widget_p (instance->widget))
1069 xlw_update_one_value (instance, widget, val);
1070 #endif
1071 #if defined (USE_MOTIF)
1072 if (lw_motif_widget_p (instance->widget))
1073 xm_update_one_value (instance, widget, val);
1074 #endif
1075 #if defined (USE_XAW)
1076 if (lw_xaw_widget_p (instance->widget))
1077 xaw_update_one_value (instance, widget, val);
1078 #endif
1079 return True;
1081 else
1082 return False;
1085 Boolean
1086 lw_get_some_values (LWLIB_ID id, widget_value *val_out)
1088 widget_info* info = get_widget_info (id, False);
1089 widget_instance* instance;
1090 widget_value* val;
1091 Boolean result = False;
1093 if (!info)
1094 return False;
1096 instance = info->instances;
1097 if (!instance)
1098 return False;
1100 for (val = val_out; val; val = val->next)
1101 if (get_one_value (instance, val))
1102 result = True;
1104 return result;
1107 widget_value*
1108 lw_get_all_values (LWLIB_ID id)
1110 widget_info* info = get_widget_info (id, False);
1111 widget_value* val = info->val;
1112 if (lw_get_some_values (id, val))
1113 return val;
1114 else
1115 return NULL;
1118 /* internal function used by the library dependent implementation to get the
1119 widget_value for a given widget in an instance */
1120 widget_value*
1121 lw_get_widget_value_for_widget (widget_instance *instance, Widget w)
1123 char* name = XtName (w);
1124 widget_value* cur;
1125 for (cur = instance->info->val; cur; cur = cur->next)
1126 if (!strcmp (cur->name, name))
1127 return cur;
1128 return NULL;
1131 \f/* update other instances value when one thing changed */
1133 /* To forbid recursive calls */
1134 static Boolean lwlib_updating;
1136 /* This function can be used as an XtCallback for the widgets that get
1137 modified to update other instances of the widgets. Closure should be the
1138 widget_instance. */
1139 void
1140 lw_internal_update_other_instances (Widget widget,
1141 XtPointer closure,
1142 XtPointer call_data)
1144 widget_instance* instance = (widget_instance*)closure;
1145 char* name = XtName (widget);
1146 widget_info* info;
1147 widget_instance* cur;
1148 widget_value* val;
1150 /* Avoid possibly infinite recursion. */
1151 if (lwlib_updating)
1152 return;
1154 /* protect against the widget being destroyed */
1155 if (XtWidgetBeingDestroyedP (widget))
1156 return;
1158 /* Return immediately if there are no other instances */
1159 info = instance->info;
1160 if (!info->instances->next)
1161 return;
1163 lwlib_updating = True;
1165 for (val = info->val; val && strcmp (val->name, name); val = val->next);
1167 if (val && get_one_value (instance, val))
1168 for (cur = info->instances; cur; cur = cur->next)
1169 if (cur != instance)
1170 set_one_value (cur, val, True);
1172 lwlib_updating = False;
1176 \f/* get the id */
1178 LWLIB_ID
1179 lw_get_widget_id (Widget w)
1181 widget_instance* instance = get_widget_instance (w, False);
1183 return instance ? instance->info->id : 0;
1186 \f/* set the keyboard focus */
1187 void
1188 lw_set_keyboard_focus (Widget parent, Widget w)
1190 #if defined (USE_MOTIF)
1191 xm_set_keyboard_focus (parent, w);
1192 #else
1193 XtSetKeyboardFocus (parent, w);
1194 #endif
1197 \f/* Show busy */
1198 static void
1199 show_one_widget_busy (Widget w, Boolean flag)
1201 Pixel foreground = 0;
1202 Pixel background = 1;
1203 Widget widget_to_invert = XtNameToWidget (w, "*sheet");
1204 if (!widget_to_invert)
1205 widget_to_invert = w;
1207 XtVaGetValues (widget_to_invert,
1208 XtNforeground, &foreground,
1209 XtNbackground, &background,
1210 NULL);
1211 XtVaSetValues (widget_to_invert,
1212 XtNforeground, background,
1213 XtNbackground, foreground,
1214 NULL);
1217 void
1218 lw_show_busy (Widget w, Boolean busy)
1220 widget_instance* instance = get_widget_instance (w, False);
1221 widget_info* info;
1222 widget_instance* next;
1224 if (instance)
1226 info = instance->info;
1227 if (info->busy != busy)
1229 for (next = info->instances; next; next = next->next)
1230 if (next->widget)
1231 show_one_widget_busy (next->widget, busy);
1232 info->busy = busy;
1237 /* This hack exists because Lucid/Athena need to execute the strange
1238 function below to support geometry management. */
1239 void
1240 lw_refigure_widget (Widget w, Boolean doit)
1242 #if defined (USE_XAW)
1243 XawPanedSetRefigureMode (w, doit);
1244 #endif
1245 #if defined (USE_MOTIF)
1246 if (doit)
1247 XtManageChild (w);
1248 else
1249 XtUnmanageChild (w);
1250 #endif
1253 /* Toolkit independent way of determining if an event window is in the
1254 menubar. */
1255 Boolean
1256 lw_window_is_in_menubar (Window win, Widget menubar_widget)
1258 return menubar_widget
1259 #if defined (USE_LUCID)
1260 && XtWindow (menubar_widget) == win;
1261 #endif
1262 #if defined (USE_MOTIF)
1263 && ((XtWindow (menubar_widget) == win)
1264 || (XtWindowToWidget (XtDisplay (menubar_widget), win)
1265 && (XtParent (XtWindowToWidget (XtDisplay (menubar_widget), win))
1266 == menubar_widget)));
1267 #endif
1270 /* Motif hack to set the main window areas. */
1271 void
1272 lw_set_main_areas (Widget parent, Widget menubar, Widget work_area)
1274 #if defined (USE_MOTIF)
1275 xm_set_main_areas (parent, menubar, work_area);
1276 #endif
1279 /* Manage resizing for Motif. This disables resizing when the menubar
1280 is about to be modified. */
1281 void
1282 lw_allow_resizing (Widget w, Boolean flag)
1284 #if defined (USE_MOTIF)
1285 xm_manage_resizing (w, flag);
1286 #endif
1290 /* Value is non-zero if LABEL is a menu separator. If it is, *TYPE is
1291 set to an appropriate enumerator of type enum menu_separator.
1292 MOTIF_P non-zero means map separator types not supported by Motif
1293 to similar ones that are supported. */
1296 lw_separator_p (const char *label, enum menu_separator *type, int motif_p)
1298 int separator_p = 0;
1300 if (strlen (label) >= 3
1301 && memcmp (label, "--:", 3) == 0)
1303 static struct separator_table
1305 const char *name;
1306 enum menu_separator type;
1308 separator_names[] =
1310 {"space", SEPARATOR_NO_LINE},
1311 {"noLine", SEPARATOR_NO_LINE},
1312 {"singleLine", SEPARATOR_SINGLE_LINE},
1313 {"doubleLine", SEPARATOR_DOUBLE_LINE},
1314 {"singleDashedLine", SEPARATOR_SINGLE_DASHED_LINE},
1315 {"doubleDashedLine", SEPARATOR_DOUBLE_DASHED_LINE},
1316 {"shadowEtchedIn", SEPARATOR_SHADOW_ETCHED_IN},
1317 {"shadowEtchedOut", SEPARATOR_SHADOW_ETCHED_OUT},
1318 {"shadowEtchedInDash", SEPARATOR_SHADOW_ETCHED_IN_DASH},
1319 {"shadowEtchedOutDash", SEPARATOR_SHADOW_ETCHED_OUT_DASH},
1320 {"shadowDoubleEtchedIn", SEPARATOR_SHADOW_DOUBLE_ETCHED_IN},
1321 {"shadowDoubleEtchedOut", SEPARATOR_SHADOW_DOUBLE_ETCHED_OUT},
1322 {"shadowDoubleEtchedInDash", SEPARATOR_SHADOW_DOUBLE_ETCHED_IN_DASH},
1323 {"shadowDoubleEtchedOutDash", SEPARATOR_SHADOW_DOUBLE_ETCHED_OUT_DASH},
1324 {0,0}
1327 int i;
1329 label += 3;
1330 for (i = 0; separator_names[i].name; ++i)
1331 if (strcmp (label, separator_names[i].name) == 0)
1333 separator_p = 1;
1334 *type = separator_names[i].type;
1336 /* If separator type is not supported under Motif,
1337 use a similar one. */
1338 if (motif_p && *type >= SEPARATOR_SHADOW_DOUBLE_ETCHED_IN)
1339 *type -= 4;
1340 break;
1343 else if (strlen (label) > 3
1344 && memcmp (label, "--", 2) == 0
1345 && label[2] != '-')
1347 /* Alternative, more Emacs-style names. */
1348 static struct separator_table
1350 const char *name;
1351 enum menu_separator type;
1353 separator_names[] =
1355 {"space", SEPARATOR_NO_LINE},
1356 {"no-line", SEPARATOR_NO_LINE},
1357 {"single-line", SEPARATOR_SINGLE_LINE},
1358 {"double-line", SEPARATOR_DOUBLE_LINE},
1359 {"single-dashed-line", SEPARATOR_SINGLE_DASHED_LINE},
1360 {"double-dashed-line", SEPARATOR_DOUBLE_DASHED_LINE},
1361 {"shadow-etched-in", SEPARATOR_SHADOW_ETCHED_IN},
1362 {"shadow-etched-out", SEPARATOR_SHADOW_ETCHED_OUT},
1363 {"shadow-etched-in-dash", SEPARATOR_SHADOW_ETCHED_IN_DASH},
1364 {"shadow-etched-out-dash", SEPARATOR_SHADOW_ETCHED_OUT_DASH},
1365 {"shadow-double-etched-in", SEPARATOR_SHADOW_DOUBLE_ETCHED_IN},
1366 {"shadow-double-etched-out", SEPARATOR_SHADOW_DOUBLE_ETCHED_OUT},
1367 {"shadow-double-etched-in-dash", SEPARATOR_SHADOW_DOUBLE_ETCHED_IN_DASH},
1368 {"shadow-double-etched-out-dash",SEPARATOR_SHADOW_DOUBLE_ETCHED_OUT_DASH},
1369 {0,0}
1372 int i;
1374 label += 2;
1375 for (i = 0; separator_names[i].name; ++i)
1376 if (strcmp (label, separator_names[i].name) == 0)
1378 separator_p = 1;
1379 *type = separator_names[i].type;
1381 /* If separator type is not supported under Motif,
1382 use a similar one. */
1383 if (motif_p && *type >= SEPARATOR_SHADOW_DOUBLE_ETCHED_IN)
1384 *type -= 4;
1385 break;
1388 else
1390 /* Old-style separator, maybe. It's a separator if it contains
1391 only dashes. */
1392 while (*label == '-')
1393 ++label;
1394 separator_p = *label == 0;
1395 *type = SEPARATOR_SHADOW_ETCHED_IN;
1398 return separator_p;