Alphabetic order is proving tricky today
[emacs.git] / lwlib / lwlib.c
blob5820be8d7a4dc3e9c923e6992682fd26bfbb0f12
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 <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 void safe_free_str (char *);
78 static void free_widget_value_tree (widget_value *);
79 static widget_value *copy_widget_value_tree (widget_value *,
80 change_type);
81 static widget_info *allocate_widget_info (const char *, const char *, LWLIB_ID,
82 widget_value *,
83 lw_callback, lw_callback,
84 lw_callback, lw_callback);
85 static void free_widget_info (widget_info *);
86 static void mark_widget_destroyed (Widget, XtPointer, XtPointer);
87 static widget_instance *allocate_widget_instance (widget_info *,
88 Widget, Boolean);
89 static void free_widget_instance (widget_instance *);
90 static widget_info *get_widget_info (LWLIB_ID, Boolean);
91 static widget_instance *get_widget_instance (Widget, Boolean);
92 static widget_instance *find_instance (LWLIB_ID, Widget, Boolean);
93 static Boolean safe_strcmp (const char *, const char *);
94 static Widget name_to_widget (widget_instance *, const char *);
95 static void set_one_value (widget_instance *, widget_value *, Boolean);
96 static void update_one_widget_instance (widget_instance *, Boolean);
97 static void update_all_widget_values (widget_info *, Boolean);
98 static void initialize_widget_instance (widget_instance *);
99 static widget_creation_function find_in_table (const char *, const widget_creation_entry *);
100 static Boolean dialog_spec_p (const char *);
101 static void destroy_one_instance (widget_instance *);
102 static void lw_pop_all_widgets (LWLIB_ID, Boolean);
103 static Boolean get_one_value (widget_instance *, widget_value *);
104 static void show_one_widget_busy (Widget, Boolean);
105 \f/* utility functions for widget_instance and widget_info */
106 char *
107 safe_strdup (const char *s)
109 char *result;
110 if (! s) return 0;
111 result = (char *) xmalloc (strlen (s) + 1);
112 strcpy (result, s);
113 return result;
116 static void
117 safe_free_str (char *s)
119 xfree (s);
122 static widget_value *widget_value_free_list = 0;
123 static int malloc_cpt = 0;
125 widget_value *
126 malloc_widget_value (void)
128 widget_value *wv;
129 if (widget_value_free_list)
131 wv = widget_value_free_list;
132 widget_value_free_list = wv->free_list;
133 wv->free_list = 0;
135 else
137 wv = (widget_value *) xmalloc (sizeof (widget_value));
138 malloc_cpt++;
140 memset ((void*) wv, 0, sizeof (widget_value));
141 return wv;
144 /* this is analogous to free(). It frees only what was allocated
145 by malloc_widget_value(), and no substructures.
147 void
148 free_widget_value (widget_value *wv)
150 if (wv->free_list)
151 abort ();
153 if (malloc_cpt > 25)
155 /* When the number of already allocated cells is too big,
156 We free it. */
157 xfree (wv);
158 malloc_cpt--;
160 else
162 wv->free_list = widget_value_free_list;
163 widget_value_free_list = wv;
167 static void
168 free_widget_value_tree (widget_value *wv)
170 if (!wv)
171 return;
173 xfree (wv->name);
174 xfree (wv->value);
175 xfree (wv->key);
177 wv->name = wv->value = wv->key = (char *) 0xDEADBEEF;
179 if (wv->toolkit_data && wv->free_toolkit_data)
181 XtFree (wv->toolkit_data);
182 wv->toolkit_data = (void *) 0xDEADBEEF;
185 if (wv->contents && (wv->contents != (widget_value*)1))
187 free_widget_value_tree (wv->contents);
188 wv->contents = (widget_value *) 0xDEADBEEF;
190 if (wv->next)
192 free_widget_value_tree (wv->next);
193 wv->next = (widget_value *) 0xDEADBEEF;
195 free_widget_value (wv);
198 static widget_value *
199 copy_widget_value_tree (widget_value *val, change_type change)
201 widget_value* copy;
203 if (!val)
204 return NULL;
205 if (val == (widget_value *) 1)
206 return val;
208 copy = malloc_widget_value ();
209 copy->name = safe_strdup (val->name);
210 copy->value = safe_strdup (val->value);
211 copy->key = safe_strdup (val->key);
212 copy->help = val->help;
213 copy->enabled = val->enabled;
214 copy->button_type = val->button_type;
215 copy->selected = val->selected;
216 copy->edited = False;
217 copy->change = change;
218 copy->this_one_change = change;
219 copy->contents = copy_widget_value_tree (val->contents, change);
220 copy->call_data = val->call_data;
221 copy->next = copy_widget_value_tree (val->next, change);
222 copy->toolkit_data = NULL;
223 copy->free_toolkit_data = False;
224 return copy;
227 static widget_info *
228 allocate_widget_info (const char* type,
229 const char* name,
230 LWLIB_ID id,
231 widget_value* val,
232 lw_callback pre_activate_cb,
233 lw_callback selection_cb,
234 lw_callback post_activate_cb,
235 lw_callback highlight_cb)
237 widget_info* info = (widget_info*) xmalloc (sizeof (widget_info));
238 info->type = safe_strdup (type);
239 info->name = safe_strdup (name);
240 info->id = id;
241 info->val = copy_widget_value_tree (val, STRUCTURAL_CHANGE);
242 info->busy = False;
243 info->pre_activate_cb = pre_activate_cb;
244 info->selection_cb = selection_cb;
245 info->post_activate_cb = post_activate_cb;
246 info->highlight_cb = highlight_cb;
247 info->instances = NULL;
249 info->next = all_widget_info;
250 all_widget_info = info;
252 return info;
255 static void
256 free_widget_info (widget_info *info)
258 safe_free_str (info->type);
259 safe_free_str (info->name);
260 free_widget_value_tree (info->val);
261 memset ((void*)info, 0xDEADBEEF, sizeof (widget_info));
262 xfree (info);
265 static void
266 mark_widget_destroyed (Widget widget, XtPointer closure, XtPointer call_data)
268 widget_instance* instance = (widget_instance*)closure;
270 /* be very conservative */
271 if (instance->widget == widget)
272 instance->widget = NULL;
275 static widget_instance *
276 allocate_widget_instance (widget_info* info, Widget parent, Boolean pop_up_p)
278 widget_instance* instance =
279 (widget_instance*) xmalloc (sizeof (widget_instance));
280 memset (instance, 0, sizeof *instance);
281 instance->parent = parent;
282 instance->pop_up_p = pop_up_p;
283 instance->info = info;
284 instance->next = info->instances;
285 info->instances = instance;
287 instantiate_widget_instance (instance);
289 XtAddCallback (instance->widget, XtNdestroyCallback,
290 mark_widget_destroyed, (XtPointer)instance);
291 return instance;
294 static void
295 free_widget_instance (widget_instance *instance)
297 memset ((void*)instance, 0xDEADBEEF, sizeof (widget_instance));
298 xfree (instance);
301 static widget_info *
302 get_widget_info (LWLIB_ID id, Boolean remove_p)
304 widget_info* info;
305 widget_info* prev;
306 for (prev = NULL, info = all_widget_info;
307 info;
308 prev = info, info = info->next)
309 if (info->id == id)
311 if (remove_p)
313 if (prev)
314 prev->next = info->next;
315 else
316 all_widget_info = info->next;
318 return info;
320 return NULL;
323 /* Internal function used by the library dependent implementation to get the
324 widget_value for a given widget in an instance */
325 widget_info *
326 lw_get_widget_info (LWLIB_ID id)
328 return get_widget_info (id, 0);
331 static widget_instance *
332 get_widget_instance (Widget widget, Boolean remove_p)
334 widget_info* info;
335 widget_instance* instance;
336 widget_instance* prev;
337 for (info = all_widget_info; info; info = info->next)
338 for (prev = NULL, instance = info->instances;
339 instance;
340 prev = instance, instance = instance->next)
341 if (instance->widget == widget)
343 if (remove_p)
345 if (prev)
346 prev->next = instance->next;
347 else
348 info->instances = instance->next;
350 return instance;
352 return (widget_instance *) 0;
355 /* Value is a pointer to the widget_instance corresponding to
356 WIDGET, or null if WIDGET is not a lwlib widget. */
358 widget_instance *
359 lw_get_widget_instance (Widget widget)
361 return get_widget_instance (widget, False);
364 static widget_instance*
365 find_instance (LWLIB_ID id, Widget parent, Boolean pop_up_p)
367 widget_info* info = get_widget_info (id, False);
368 widget_instance* instance;
370 if (info)
371 for (instance = info->instances; instance; instance = instance->next)
372 if (instance->parent == parent && instance->pop_up_p == pop_up_p)
373 return instance;
375 return NULL;
379 /* utility function for widget_value */
380 static Boolean
381 safe_strcmp (const char *s1, const char *s2)
383 if (!!s1 ^ !!s2) return True;
384 return (s1 && s2) ? strcmp (s1, s2) : s1 ? False : !!s2;
388 #if 0
389 # define EXPLAIN(name, oc, nc, desc, a1, a2) \
390 printf ("Change: \"%s\"\tmax(%s=%d,%s=%d)\t%s %d %d\n", \
391 name, \
392 (oc == NO_CHANGE ? "none" : \
393 (oc == INVISIBLE_CHANGE ? "invisible" : \
394 (oc == VISIBLE_CHANGE ? "visible" : \
395 (oc == STRUCTURAL_CHANGE ? "structural" : "???")))), \
396 oc, \
397 (nc == NO_CHANGE ? "none" : \
398 (nc == INVISIBLE_CHANGE ? "invisible" : \
399 (nc == VISIBLE_CHANGE ? "visible" : \
400 (nc == STRUCTURAL_CHANGE ? "structural" : "???")))), \
401 nc, desc, a1, a2)
402 #else
403 # define EXPLAIN(name, oc, nc, desc, a1, a2) ((void) 0)
404 #endif
407 static widget_value *
408 merge_widget_value (widget_value *val1,
409 widget_value *val2,
410 int level,
411 int *change_p)
413 change_type change, this_one_change;
414 widget_value* merged_next;
415 widget_value* merged_contents;
417 if (!val1)
419 if (val2)
421 *change_p = 1;
422 return copy_widget_value_tree (val2, STRUCTURAL_CHANGE);
424 else
425 return NULL;
427 if (!val2)
429 *change_p = 1;
430 free_widget_value_tree (val1);
431 return NULL;
434 change = NO_CHANGE;
436 if (safe_strcmp (val1->name, val2->name))
438 EXPLAIN (val1->name, change, STRUCTURAL_CHANGE, "name change",
439 val1->name, val2->name);
440 change = max (change, STRUCTURAL_CHANGE);
441 safe_free_str (val1->name);
442 val1->name = safe_strdup (val2->name);
444 if (safe_strcmp (val1->value, val2->value))
446 EXPLAIN (val1->name, change, VISIBLE_CHANGE, "value change",
447 val1->value, val2->value);
448 change = max (change, VISIBLE_CHANGE);
449 safe_free_str (val1->value);
450 val1->value = safe_strdup (val2->value);
452 if (safe_strcmp (val1->key, val2->key))
454 EXPLAIN (val1->name, change, VISIBLE_CHANGE, "key change",
455 val1->key, val2->key);
456 change = max (change, VISIBLE_CHANGE);
457 safe_free_str (val1->key);
458 val1->key = safe_strdup (val2->key);
460 if (! EQ (val1->help, val2->help))
462 EXPLAIN (val1->name, change, VISIBLE_CHANGE, "help change",
463 val1->help, val2->help);
464 change = max (change, VISIBLE_CHANGE);
465 val1->help = val2->help;
467 if (val1->enabled != val2->enabled)
469 EXPLAIN (val1->name, change, VISIBLE_CHANGE, "enablement change",
470 val1->enabled, val2->enabled);
471 change = max (change, VISIBLE_CHANGE);
472 val1->enabled = val2->enabled;
474 if (val1->button_type != val2->button_type)
476 EXPLAIN (val1->name, change, VISIBLE_CHANGE, "button type change",
477 val1->button_type, val2->button_type);
478 change = max (change, VISIBLE_CHANGE);
479 val1->button_type = val2->button_type;
481 if (val1->selected != val2->selected)
483 EXPLAIN (val1->name, change, VISIBLE_CHANGE, "selection change",
484 val1->selected, val2->selected);
485 change = max (change, VISIBLE_CHANGE);
486 val1->selected = val2->selected;
488 if (val1->call_data != val2->call_data)
490 EXPLAIN (val1->name, change, INVISIBLE_CHANGE, "call-data change",
491 val1->call_data, val2->call_data);
492 change = max (change, INVISIBLE_CHANGE);
493 val1->call_data = val2->call_data;
496 if (level > 0)
498 merged_contents =
499 merge_widget_value (val1->contents, val2->contents, level - 1,
500 change_p);
502 if (val1->contents && !merged_contents)
504 /* This used to say INVISIBLE_CHANGE,
505 but it is visible and vitally important when
506 the contents of the menu bar itself are entirely deleted.
508 But maybe it doesn't matter. This fails to fix the bug. */
509 EXPLAIN (val1->name, change, STRUCTURAL_CHANGE, "(contents gone)",
510 0, 0);
511 change = max (change, STRUCTURAL_CHANGE);
513 else if (merged_contents && merged_contents->change != NO_CHANGE)
515 EXPLAIN (val1->name, change, INVISIBLE_CHANGE, "(contents change)",
516 0, 0);
517 change = max (change, INVISIBLE_CHANGE);
518 #if 0 /* This was replaced by the August 9 1996 change in lwlib-Xm.c. */
519 #ifdef USE_MOTIF
520 change = max (merged_contents->change, change);
521 #endif
522 #endif
525 val1->contents = merged_contents;
528 this_one_change = change;
530 merged_next = merge_widget_value (val1->next, val2->next, level, change_p);
532 if (val1->next && !merged_next)
534 EXPLAIN (val1->name, change, STRUCTURAL_CHANGE, "(following gone)",
535 0, 0);
536 change = max (change, STRUCTURAL_CHANGE);
538 else if (merged_next)
540 if (merged_next->change)
541 EXPLAIN (val1->name, change, merged_next->change, "(following change)",
542 0, 0);
543 change = max (change, merged_next->change);
546 val1->next = merged_next;
548 val1->this_one_change = this_one_change;
549 val1->change = change;
551 if (change > NO_CHANGE && val1->toolkit_data)
553 *change_p = 1;
554 if (val1->free_toolkit_data)
555 XtFree (val1->toolkit_data);
556 val1->toolkit_data = NULL;
559 return val1;
563 /* modifying the widgets */
564 static Widget
565 name_to_widget (widget_instance *instance, const char *name)
567 Widget widget = NULL;
569 if (!instance->widget)
570 return NULL;
572 if (!strcmp (XtName (instance->widget), name))
573 widget = instance->widget;
574 else
576 int length = strlen (name) + 2;
577 char* real_name = (char *) xmalloc (length);
578 real_name [0] = '*';
579 strcpy (real_name + 1, name);
581 widget = XtNameToWidget (instance->widget, real_name);
583 xfree (real_name);
585 return widget;
588 static void
589 set_one_value (widget_instance* instance, widget_value* val, Boolean deep_p)
591 Widget widget = name_to_widget (instance, val->name);
593 if (widget)
595 #if defined (USE_LUCID)
596 if (lw_lucid_widget_p (instance->widget))
597 xlw_update_one_widget (instance, widget, val, deep_p);
598 #endif
599 #if defined (USE_MOTIF)
600 if (lw_motif_widget_p (instance->widget))
601 xm_update_one_widget (instance, widget, val, deep_p);
602 #endif
603 #if defined (USE_XAW)
604 if (lw_xaw_widget_p (instance->widget))
605 xaw_update_one_widget (instance, widget, val, deep_p);
606 #endif
610 static void
611 update_one_widget_instance (widget_instance* instance, Boolean deep_p)
613 widget_value *val;
615 if (!instance->widget)
616 /* the widget was destroyed */
617 return;
619 for (val = instance->info->val; val; val = val->next)
620 if (val->change != NO_CHANGE)
621 set_one_value (instance, val, deep_p);
624 static void
625 update_all_widget_values (widget_info* info, Boolean deep_p)
627 widget_instance* instance;
628 widget_value* val;
630 for (instance = info->instances; instance; instance = instance->next)
631 update_one_widget_instance (instance, deep_p);
633 for (val = info->val; val; val = val->next)
634 val->change = NO_CHANGE;
638 lw_modify_all_widgets (LWLIB_ID id, widget_value* val, Boolean deep_p)
640 widget_info* info = get_widget_info (id, False);
641 widget_value* new_val;
642 widget_value* next_new_val;
643 widget_value* cur;
644 widget_value* prev;
645 widget_value* next;
646 int found;
647 int change_p = 0;
649 if (!info)
650 return 0;
652 for (new_val = val; new_val; new_val = new_val->next)
654 next_new_val = new_val->next;
655 new_val->next = NULL;
656 found = False;
657 for (prev = NULL, cur = info->val; cur; prev = cur, cur = cur->next)
658 if (!strcmp (cur->name, new_val->name))
660 found = True;
661 next = cur->next;
662 cur->next = NULL;
663 cur = merge_widget_value (cur, new_val, deep_p ? 1000 : 1,
664 &change_p);
665 if (prev)
666 prev->next = cur ? cur : next;
667 else
668 info->val = cur ? cur : next;
669 if (cur)
670 cur->next = next;
671 break;
673 if (!found)
675 /* Could not find it, add it */
676 if (prev)
677 prev->next = copy_widget_value_tree (new_val, STRUCTURAL_CHANGE);
678 else
679 info->val = copy_widget_value_tree (new_val, STRUCTURAL_CHANGE);
680 change_p = 1;
682 new_val->next = next_new_val;
685 update_all_widget_values (info, deep_p);
686 return change_p;
690 /* creating the widgets */
692 static void
693 initialize_widget_instance (widget_instance *instance)
695 widget_value* val;
697 for (val = instance->info->val; val; val = val->next)
698 val->change = STRUCTURAL_CHANGE;
700 update_one_widget_instance (instance, True);
702 for (val = instance->info->val; val; val = val->next)
703 val->change = NO_CHANGE;
707 static widget_creation_function
708 find_in_table (const char *type, const widget_creation_entry *table)
710 const widget_creation_entry* cur;
711 for (cur = table; cur->type; cur++)
712 if (!c_strcasecmp (type, cur->type))
713 return cur->function;
714 return NULL;
717 static Boolean
718 dialog_spec_p (const char *name)
720 /* return True if name matches [EILPQeilpq][1-9][Bb] or
721 [EILPQeilpq][1-9][Bb][Rr][1-9] */
722 if (!name)
723 return False;
725 switch (name [0])
727 case 'E': case 'I': case 'L': case 'P': case 'Q':
728 case 'e': case 'i': case 'l': case 'p': case 'q':
729 if (name [1] >= '0' && name [1] <= '9')
731 if (name [2] != 'B' && name [2] != 'b')
732 return False;
733 if (!name [3])
734 return True;
735 if ((name [3] == 'T' || name [3] == 't') && !name [4])
736 return True;
737 if ((name [3] == 'R' || name [3] == 'r')
738 && name [4] >= '0' && name [4] <= '9' && !name [5])
739 return True;
740 return False;
742 else
743 return False;
745 default:
746 return False;
750 static void
751 instantiate_widget_instance (widget_instance *instance)
753 widget_creation_function function = NULL;
755 #if defined (USE_LUCID)
756 if (!function)
757 function = find_in_table (instance->info->type, xlw_creation_table);
758 #endif
759 #if defined(USE_MOTIF)
760 if (!function)
761 function = find_in_table (instance->info->type, xm_creation_table);
762 #endif
763 #if defined (USE_XAW)
764 if (!function)
765 function = find_in_table (instance->info->type, xaw_creation_table);
766 #endif
768 if (!function)
770 if (dialog_spec_p (instance->info->type))
772 #if defined (USE_LUCID)
773 /* not yet */
774 #endif
775 #if defined(USE_MOTIF)
776 if (!function)
777 function = xm_create_dialog;
778 #endif
779 #if defined (USE_XAW)
780 if (!function)
781 function = xaw_create_dialog;
782 #endif
786 if (!function)
788 printf ("No creation function for widget type %s\n",
789 instance->info->type);
790 abort ();
793 instance->widget = (*function) (instance);
795 if (!instance->widget)
796 abort ();
798 /* XtRealizeWidget (instance->widget);*/
801 void
802 lw_register_widget (const char* type,
803 const char* name,
804 LWLIB_ID id,
805 widget_value* val,
806 lw_callback pre_activate_cb,
807 lw_callback selection_cb,
808 lw_callback post_activate_cb,
809 lw_callback highlight_cb)
811 if (!get_widget_info (id, False))
812 allocate_widget_info (type, name, id, val, pre_activate_cb, selection_cb,
813 post_activate_cb, highlight_cb);
816 Widget
817 lw_get_widget (LWLIB_ID id, Widget parent, Boolean pop_up_p)
819 widget_instance* instance;
821 instance = find_instance (id, parent, pop_up_p);
822 return instance ? instance->widget : NULL;
825 Widget
826 lw_make_widget (LWLIB_ID id, Widget parent, Boolean pop_up_p)
828 widget_instance* instance;
829 widget_info* info;
831 instance = find_instance (id, parent, pop_up_p);
832 if (!instance)
834 info = get_widget_info (id, False);
835 if (!info)
836 return NULL;
837 instance = allocate_widget_instance (info, parent, pop_up_p);
838 initialize_widget_instance (instance);
840 if (!instance->widget)
841 abort ();
842 return instance->widget;
845 Widget
846 lw_create_widget (const char* type, const char* name, LWLIB_ID id, widget_value* val,
847 Widget parent, Boolean pop_up_p,
848 lw_callback pre_activate_cb, lw_callback selection_cb,
849 lw_callback post_activate_cb, lw_callback highlight_cb)
851 lw_register_widget (type, name, id, val, pre_activate_cb, selection_cb,
852 post_activate_cb, highlight_cb);
853 return lw_make_widget (id, parent, pop_up_p);
857 /* destroying the widgets */
858 static void
859 destroy_one_instance (widget_instance *instance)
861 /* Remove the destroy callback on the widget; that callback will try to
862 dereference the instance object (to set its widget slot to 0, since the
863 widget is dead.) Since the instance is now dead, we don't have to worry
864 about the fact that its widget is dead too.
866 This happens in the Phase2Destroy of the widget, so this callback would
867 not have been run until arbitrarily long after the instance was freed.
869 if (instance->widget)
870 XtRemoveCallback (instance->widget, XtNdestroyCallback,
871 mark_widget_destroyed, (XtPointer)instance);
873 if (instance->widget)
875 /* The else are pretty tricky here, including the empty statement
876 at the end because it would be very bad to destroy a widget
877 twice. */
878 #if defined (USE_LUCID)
879 if (lw_lucid_widget_p (instance->widget))
880 xlw_destroy_instance (instance);
881 else
882 #endif
883 #if defined (USE_MOTIF)
884 if (lw_motif_widget_p (instance->widget))
885 xm_destroy_instance (instance);
886 else
887 #endif
888 #if defined (USE_XAW)
889 if (lw_xaw_widget_p (instance->widget))
890 xaw_destroy_instance (instance);
891 else
892 #endif
894 /* Empty compound statement to terminate if-then-else chain. */
898 free_widget_instance (instance);
901 void
902 lw_destroy_widget (Widget w)
904 widget_instance* instance = get_widget_instance (w, True);
906 if (instance)
908 widget_info *info = instance->info;
909 /* instance has already been removed from the list; free it */
910 destroy_one_instance (instance);
911 /* if there are no instances left, free the info too */
912 if (!info->instances)
913 lw_destroy_all_widgets (info->id);
917 void
918 lw_destroy_all_widgets (LWLIB_ID id)
920 widget_info* info = get_widget_info (id, True);
921 widget_instance* instance;
922 widget_instance* next;
924 if (info)
926 for (instance = info->instances; instance; )
928 next = instance->next;
929 destroy_one_instance (instance);
930 instance = next;
932 free_widget_info (info);
936 void
937 lw_destroy_everything (void)
939 while (all_widget_info)
940 lw_destroy_all_widgets (all_widget_info->id);
943 void
944 lw_destroy_all_pop_ups (void)
946 widget_info* info;
947 widget_info* next;
948 widget_instance* instance;
950 for (info = all_widget_info; info; info = next)
952 next = info->next;
953 instance = info->instances;
954 if (instance && instance->pop_up_p)
955 lw_destroy_all_widgets (info->id);
959 #ifdef USE_MOTIF
960 extern Widget first_child (Widget); /* garbage */
961 #endif
963 Widget
964 lw_raise_all_pop_up_widgets (void)
966 widget_info* info;
967 widget_instance* instance;
968 Widget result = NULL;
970 for (info = all_widget_info; info; info = info->next)
971 for (instance = info->instances; instance; instance = instance->next)
972 if (instance->pop_up_p)
974 Widget widget = instance->widget;
975 if (widget)
977 if (XtIsManaged (widget)
978 #ifdef USE_MOTIF
979 /* What a complete load of crap!!!!
980 When a dialogShell is on the screen, it is not managed!
982 || (lw_motif_widget_p (instance->widget) &&
983 XtIsManaged (first_child (widget)))
984 #endif
987 if (!result)
988 result = widget;
989 XMapRaised (XtDisplay (widget), XtWindow (widget));
993 return result;
996 static void
997 lw_pop_all_widgets (LWLIB_ID id, Boolean up)
999 widget_info* info = get_widget_info (id, False);
1000 widget_instance* instance;
1002 if (info)
1003 for (instance = info->instances; instance; instance = instance->next)
1004 if (instance->pop_up_p && instance->widget)
1006 #if defined (USE_LUCID)
1007 if (lw_lucid_widget_p (instance->widget))
1009 XtRealizeWidget (instance->widget);
1010 xlw_pop_instance (instance, up);
1012 #endif
1013 #if defined (USE_MOTIF)
1014 if (lw_motif_widget_p (instance->widget))
1016 XtRealizeWidget (instance->widget);
1017 xm_pop_instance (instance, up);
1019 #endif
1020 #if defined (USE_XAW)
1021 if (lw_xaw_widget_p (instance->widget))
1023 XtRealizeWidget (XtParent (instance->widget));
1024 XtRealizeWidget (instance->widget);
1025 xaw_pop_instance (instance, up);
1027 #endif
1031 void
1032 lw_pop_up_all_widgets (LWLIB_ID id)
1034 lw_pop_all_widgets (id, True);
1037 void
1038 lw_pop_down_all_widgets (LWLIB_ID id)
1040 lw_pop_all_widgets (id, False);
1043 void
1044 lw_popup_menu (Widget widget, XEvent *event)
1046 #if defined (USE_LUCID)
1047 if (lw_lucid_widget_p (widget))
1048 xlw_popup_menu (widget, event);
1049 #endif
1050 #if defined (USE_MOTIF)
1051 if (lw_motif_widget_p (widget))
1052 xm_popup_menu (widget, event);
1053 #endif
1054 #if defined (USE_XAW)
1055 if (lw_xaw_widget_p (widget))
1056 xaw_popup_menu (widget, event);
1057 #endif
1060 \f/* get the values back */
1061 static Boolean
1062 get_one_value (widget_instance *instance, widget_value *val)
1064 Widget widget = name_to_widget (instance, val->name);
1066 if (widget)
1068 #if defined (USE_LUCID)
1069 if (lw_lucid_widget_p (instance->widget))
1070 xlw_update_one_value (instance, widget, val);
1071 #endif
1072 #if defined (USE_MOTIF)
1073 if (lw_motif_widget_p (instance->widget))
1074 xm_update_one_value (instance, widget, val);
1075 #endif
1076 #if defined (USE_XAW)
1077 if (lw_xaw_widget_p (instance->widget))
1078 xaw_update_one_value (instance, widget, val);
1079 #endif
1080 return True;
1082 else
1083 return False;
1086 Boolean
1087 lw_get_some_values (LWLIB_ID id, widget_value *val_out)
1089 widget_info* info = get_widget_info (id, False);
1090 widget_instance* instance;
1091 widget_value* val;
1092 Boolean result = False;
1094 if (!info)
1095 return False;
1097 instance = info->instances;
1098 if (!instance)
1099 return False;
1101 for (val = val_out; val; val = val->next)
1102 if (get_one_value (instance, val))
1103 result = True;
1105 return result;
1108 widget_value*
1109 lw_get_all_values (LWLIB_ID id)
1111 widget_info* info = get_widget_info (id, False);
1112 widget_value* val = info->val;
1113 if (lw_get_some_values (id, val))
1114 return val;
1115 else
1116 return NULL;
1119 /* internal function used by the library dependent implementation to get the
1120 widget_value for a given widget in an instance */
1121 widget_value*
1122 lw_get_widget_value_for_widget (widget_instance *instance, Widget w)
1124 char* name = XtName (w);
1125 widget_value* cur;
1126 for (cur = instance->info->val; cur; cur = cur->next)
1127 if (!strcmp (cur->name, name))
1128 return cur;
1129 return NULL;
1132 \f/* update other instances value when one thing changed */
1134 /* To forbid recursive calls */
1135 static Boolean lwlib_updating;
1137 /* This function can be used as an XtCallback for the widgets that get
1138 modified to update other instances of the widgets. Closure should be the
1139 widget_instance. */
1140 void
1141 lw_internal_update_other_instances (Widget widget,
1142 XtPointer closure,
1143 XtPointer call_data)
1145 widget_instance* instance = (widget_instance*)closure;
1146 char* name = XtName (widget);
1147 widget_info* info;
1148 widget_instance* cur;
1149 widget_value* val;
1151 /* Avoid possibly infinite recursion. */
1152 if (lwlib_updating)
1153 return;
1155 /* protect against the widget being destroyed */
1156 if (XtWidgetBeingDestroyedP (widget))
1157 return;
1159 /* Return immediately if there are no other instances */
1160 info = instance->info;
1161 if (!info->instances->next)
1162 return;
1164 lwlib_updating = True;
1166 for (val = info->val; val && strcmp (val->name, name); val = val->next);
1168 if (val && get_one_value (instance, val))
1169 for (cur = info->instances; cur; cur = cur->next)
1170 if (cur != instance)
1171 set_one_value (cur, val, True);
1173 lwlib_updating = False;
1177 \f/* get the id */
1179 LWLIB_ID
1180 lw_get_widget_id (Widget w)
1182 widget_instance* instance = get_widget_instance (w, False);
1184 return instance ? instance->info->id : 0;
1187 \f/* set the keyboard focus */
1188 void
1189 lw_set_keyboard_focus (Widget parent, Widget w)
1191 #if defined (USE_MOTIF)
1192 xm_set_keyboard_focus (parent, w);
1193 #else
1194 XtSetKeyboardFocus (parent, w);
1195 #endif
1198 \f/* Show busy */
1199 static void
1200 show_one_widget_busy (Widget w, Boolean flag)
1202 Pixel foreground = 0;
1203 Pixel background = 1;
1204 Widget widget_to_invert = XtNameToWidget (w, "*sheet");
1205 if (!widget_to_invert)
1206 widget_to_invert = w;
1208 XtVaGetValues (widget_to_invert,
1209 XtNforeground, &foreground,
1210 XtNbackground, &background,
1211 NULL);
1212 XtVaSetValues (widget_to_invert,
1213 XtNforeground, background,
1214 XtNbackground, foreground,
1215 NULL);
1218 void
1219 lw_show_busy (Widget w, Boolean busy)
1221 widget_instance* instance = get_widget_instance (w, False);
1222 widget_info* info;
1223 widget_instance* next;
1225 if (instance)
1227 info = instance->info;
1228 if (info->busy != busy)
1230 for (next = info->instances; next; next = next->next)
1231 if (next->widget)
1232 show_one_widget_busy (next->widget, busy);
1233 info->busy = busy;
1238 /* This hack exists because Lucid/Athena need to execute the strange
1239 function below to support geometry management. */
1240 void
1241 lw_refigure_widget (Widget w, Boolean doit)
1243 #if defined (USE_XAW)
1244 XawPanedSetRefigureMode (w, doit);
1245 #endif
1246 #if defined (USE_MOTIF)
1247 if (doit)
1248 XtManageChild (w);
1249 else
1250 XtUnmanageChild (w);
1251 #endif
1254 /* Toolkit independent way of determining if an event window is in the
1255 menubar. */
1256 Boolean
1257 lw_window_is_in_menubar (Window win, Widget menubar_widget)
1259 return menubar_widget
1260 #if defined (USE_LUCID)
1261 && XtWindow (menubar_widget) == win;
1262 #endif
1263 #if defined (USE_MOTIF)
1264 && ((XtWindow (menubar_widget) == win)
1265 || (XtWindowToWidget (XtDisplay (menubar_widget), win)
1266 && (XtParent (XtWindowToWidget (XtDisplay (menubar_widget), win))
1267 == menubar_widget)));
1268 #endif
1271 /* Motif hack to set the main window areas. */
1272 void
1273 lw_set_main_areas (Widget parent, Widget menubar, Widget work_area)
1275 #if defined (USE_MOTIF)
1276 xm_set_main_areas (parent, menubar, work_area);
1277 #endif
1280 /* Manage resizing for Motif. This disables resizing when the menubar
1281 is about to be modified. */
1282 void
1283 lw_allow_resizing (Widget w, Boolean flag)
1285 #if defined (USE_MOTIF)
1286 xm_manage_resizing (w, flag);
1287 #endif
1291 /* Value is non-zero if LABEL is a menu separator. If it is, *TYPE is
1292 set to an appropriate enumerator of type enum menu_separator.
1293 MOTIF_P non-zero means map separator types not supported by Motif
1294 to similar ones that are supported. */
1297 lw_separator_p (const char *label, enum menu_separator *type, int motif_p)
1299 int separator_p = 0;
1301 if (strlen (label) >= 3
1302 && memcmp (label, "--:", 3) == 0)
1304 static struct separator_table
1306 const char *name;
1307 enum menu_separator type;
1309 separator_names[] =
1311 {"space", SEPARATOR_NO_LINE},
1312 {"noLine", SEPARATOR_NO_LINE},
1313 {"singleLine", SEPARATOR_SINGLE_LINE},
1314 {"doubleLine", SEPARATOR_DOUBLE_LINE},
1315 {"singleDashedLine", SEPARATOR_SINGLE_DASHED_LINE},
1316 {"doubleDashedLine", SEPARATOR_DOUBLE_DASHED_LINE},
1317 {"shadowEtchedIn", SEPARATOR_SHADOW_ETCHED_IN},
1318 {"shadowEtchedOut", SEPARATOR_SHADOW_ETCHED_OUT},
1319 {"shadowEtchedInDash", SEPARATOR_SHADOW_ETCHED_IN_DASH},
1320 {"shadowEtchedOutDash", SEPARATOR_SHADOW_ETCHED_OUT_DASH},
1321 {"shadowDoubleEtchedIn", SEPARATOR_SHADOW_DOUBLE_ETCHED_IN},
1322 {"shadowDoubleEtchedOut", SEPARATOR_SHADOW_DOUBLE_ETCHED_OUT},
1323 {"shadowDoubleEtchedInDash", SEPARATOR_SHADOW_DOUBLE_ETCHED_IN_DASH},
1324 {"shadowDoubleEtchedOutDash", SEPARATOR_SHADOW_DOUBLE_ETCHED_OUT_DASH},
1325 {0,0}
1328 int i;
1330 label += 3;
1331 for (i = 0; separator_names[i].name; ++i)
1332 if (strcmp (label, separator_names[i].name) == 0)
1334 separator_p = 1;
1335 *type = separator_names[i].type;
1337 /* If separator type is not supported under Motif,
1338 use a similar one. */
1339 if (motif_p && *type >= SEPARATOR_SHADOW_DOUBLE_ETCHED_IN)
1340 *type -= 4;
1341 break;
1344 else if (strlen (label) > 3
1345 && memcmp (label, "--", 2) == 0
1346 && label[2] != '-')
1348 /* Alternative, more Emacs-style names. */
1349 static struct separator_table
1351 const char *name;
1352 enum menu_separator type;
1354 separator_names[] =
1356 {"space", SEPARATOR_NO_LINE},
1357 {"no-line", SEPARATOR_NO_LINE},
1358 {"single-line", SEPARATOR_SINGLE_LINE},
1359 {"double-line", SEPARATOR_DOUBLE_LINE},
1360 {"single-dashed-line", SEPARATOR_SINGLE_DASHED_LINE},
1361 {"double-dashed-line", SEPARATOR_DOUBLE_DASHED_LINE},
1362 {"shadow-etched-in", SEPARATOR_SHADOW_ETCHED_IN},
1363 {"shadow-etched-out", SEPARATOR_SHADOW_ETCHED_OUT},
1364 {"shadow-etched-in-dash", SEPARATOR_SHADOW_ETCHED_IN_DASH},
1365 {"shadow-etched-out-dash", SEPARATOR_SHADOW_ETCHED_OUT_DASH},
1366 {"shadow-double-etched-in", SEPARATOR_SHADOW_DOUBLE_ETCHED_IN},
1367 {"shadow-double-etched-out", SEPARATOR_SHADOW_DOUBLE_ETCHED_OUT},
1368 {"shadow-double-etched-in-dash", SEPARATOR_SHADOW_DOUBLE_ETCHED_IN_DASH},
1369 {"shadow-double-etched-out-dash",SEPARATOR_SHADOW_DOUBLE_ETCHED_OUT_DASH},
1370 {0,0}
1373 int i;
1375 label += 2;
1376 for (i = 0; separator_names[i].name; ++i)
1377 if (strcmp (label, separator_names[i].name) == 0)
1379 separator_p = 1;
1380 *type = separator_names[i].type;
1382 /* If separator type is not supported under Motif,
1383 use a similar one. */
1384 if (motif_p && *type >= SEPARATOR_SHADOW_DOUBLE_ETCHED_IN)
1385 *type -= 4;
1386 break;
1389 else
1391 /* Old-style separator, maybe. It's a separator if it contains
1392 only dashes. */
1393 while (*label == '-')
1394 ++label;
1395 separator_p = *label == 0;
1396 *type = SEPARATOR_SHADOW_ETCHED_IN;
1399 return separator_p;