Backport Tramp changes from trunk.
[emacs.git] / lwlib / lwlib.c
blobf3e80160ebf5e7ffc720774f02c2755860aa7bb9
1 /* A general interface to the widgets of different toolkits.
3 Copyright (C) 1992, 1993 Lucid, Inc.
4 Copyright (C) 1994-1996, 1999-2014 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. If not, see <http://www.gnu.org/licenses/>. */
21 #include <config.h>
23 #include <setjmp.h>
24 #include <lisp.h>
25 #include <c-strcase.h>
27 #include <sys/types.h>
28 #include <stdio.h>
29 #include "lwlib-int.h"
30 #include "lwlib-utils.h"
31 #include <X11/StringDefs.h>
33 #if defined (USE_LUCID)
34 #include "lwlib-Xlw.h"
35 #endif
36 #if defined (USE_MOTIF)
37 #include "lwlib-Xm.h"
38 #else /* not USE_MOTIF */
39 #if defined (USE_LUCID)
40 #define USE_XAW
41 #endif /* not USE_MOTIF && USE_LUCID */
42 #endif
43 #if defined (USE_XAW)
44 #ifdef HAVE_XAW3D
45 #include <X11/Xaw3d/Paned.h>
46 #else /* !HAVE_XAW3D */
47 #include <X11/Xaw/Paned.h>
48 #endif /* HAVE_XAW3D */
49 #include "lwlib-Xaw.h"
50 #endif
52 #if !defined (USE_LUCID) && !defined (USE_MOTIF)
53 #error At least one of USE_LUCID or USE_MOTIF must be defined.
54 #endif
56 #ifndef max
57 #define max(x, y) ((x) > (y) ? (x) : (y))
58 #endif
60 /* List of all widgets managed by the library. */
61 static widget_info*
62 all_widget_info = NULL;
64 #ifdef USE_MOTIF
65 const char *lwlib_toolkit_type = "motif";
66 #else
67 const char *lwlib_toolkit_type = "lucid";
68 #endif
70 static widget_value *merge_widget_value (widget_value *,
71 widget_value *,
72 int, int *);
73 static void instantiate_widget_instance (widget_instance *);
74 static void safe_free_str (char *);
75 static void free_widget_value_tree (widget_value *);
76 static widget_value *copy_widget_value_tree (widget_value *,
77 change_type);
78 static widget_info *allocate_widget_info (const char *, const char *, LWLIB_ID,
79 widget_value *,
80 lw_callback, lw_callback,
81 lw_callback, lw_callback);
82 static void free_widget_info (widget_info *);
83 static void mark_widget_destroyed (Widget, XtPointer, XtPointer);
84 static widget_instance *allocate_widget_instance (widget_info *,
85 Widget, Boolean);
86 static void free_widget_instance (widget_instance *);
87 static widget_info *get_widget_info (LWLIB_ID, Boolean);
88 static widget_instance *get_widget_instance (Widget, Boolean);
89 static widget_instance *find_instance (LWLIB_ID, Widget, Boolean);
90 static Boolean safe_strcmp (const char *, const char *);
91 static Widget name_to_widget (widget_instance *, const char *);
92 static void set_one_value (widget_instance *, widget_value *, Boolean);
93 static void update_one_widget_instance (widget_instance *, Boolean);
94 static void update_all_widget_values (widget_info *, Boolean);
95 static void initialize_widget_instance (widget_instance *);
96 static widget_creation_function find_in_table (const char *, const widget_creation_entry *);
97 static Boolean dialog_spec_p (const char *);
98 static void destroy_one_instance (widget_instance *);
99 static void lw_pop_all_widgets (LWLIB_ID, Boolean);
100 static Boolean get_one_value (widget_instance *, widget_value *);
101 static void show_one_widget_busy (Widget, Boolean);
102 \f/* utility functions for widget_instance and widget_info */
103 char *
104 safe_strdup (const char *s)
106 return s ? xstrdup (s) : 0;
109 static void
110 safe_free_str (char *s)
112 xfree (s);
115 static widget_value *widget_value_free_list = 0;
116 static int malloc_cpt = 0;
118 widget_value *
119 malloc_widget_value (void)
121 widget_value *wv;
122 if (widget_value_free_list)
124 wv = widget_value_free_list;
125 widget_value_free_list = wv->free_list;
126 wv->free_list = 0;
128 else
130 wv = (widget_value *) xmalloc (sizeof (widget_value));
131 malloc_cpt++;
133 memset ((void*) wv, 0, sizeof (widget_value));
134 return wv;
137 /* this is analogous to free(). It frees only what was allocated
138 by malloc_widget_value(), and no substructures.
140 void
141 free_widget_value (widget_value *wv)
143 if (wv->free_list)
144 abort ();
146 if (malloc_cpt > 25)
148 /* When the number of already allocated cells is too big,
149 We free it. */
150 xfree (wv);
151 malloc_cpt--;
153 else
155 wv->free_list = widget_value_free_list;
156 widget_value_free_list = wv;
160 static void
161 free_widget_value_tree (widget_value *wv)
163 if (!wv)
164 return;
166 xfree (wv->name);
167 xfree (wv->value);
168 xfree (wv->key);
170 wv->name = wv->value = wv->key = (char *) 0xDEADBEEF;
172 if (wv->toolkit_data && wv->free_toolkit_data)
174 XtFree (wv->toolkit_data);
175 wv->toolkit_data = (void *) 0xDEADBEEF;
178 if (wv->contents && (wv->contents != (widget_value*)1))
180 free_widget_value_tree (wv->contents);
181 wv->contents = (widget_value *) 0xDEADBEEF;
183 if (wv->next)
185 free_widget_value_tree (wv->next);
186 wv->next = (widget_value *) 0xDEADBEEF;
188 free_widget_value (wv);
191 static widget_value *
192 copy_widget_value_tree (widget_value *val, change_type change)
194 widget_value* copy;
196 if (!val)
197 return NULL;
198 if (val == (widget_value *) 1)
199 return val;
201 copy = malloc_widget_value ();
202 copy->name = safe_strdup (val->name);
203 copy->value = safe_strdup (val->value);
204 copy->key = safe_strdup (val->key);
205 copy->help = val->help;
206 copy->enabled = val->enabled;
207 copy->button_type = val->button_type;
208 copy->selected = val->selected;
209 copy->edited = False;
210 copy->change = change;
211 copy->this_one_change = change;
212 copy->contents = copy_widget_value_tree (val->contents, change);
213 copy->call_data = val->call_data;
214 copy->next = copy_widget_value_tree (val->next, change);
215 copy->toolkit_data = NULL;
216 copy->free_toolkit_data = False;
217 return copy;
220 static widget_info *
221 allocate_widget_info (const char* type,
222 const char* name,
223 LWLIB_ID id,
224 widget_value* val,
225 lw_callback pre_activate_cb,
226 lw_callback selection_cb,
227 lw_callback post_activate_cb,
228 lw_callback highlight_cb)
230 widget_info* info = (widget_info*) xmalloc (sizeof (widget_info));
231 info->type = safe_strdup (type);
232 info->name = safe_strdup (name);
233 info->id = id;
234 info->val = copy_widget_value_tree (val, STRUCTURAL_CHANGE);
235 info->busy = False;
236 info->pre_activate_cb = pre_activate_cb;
237 info->selection_cb = selection_cb;
238 info->post_activate_cb = post_activate_cb;
239 info->highlight_cb = highlight_cb;
240 info->instances = NULL;
242 info->next = all_widget_info;
243 all_widget_info = info;
245 return info;
248 static void
249 free_widget_info (widget_info *info)
251 safe_free_str (info->type);
252 safe_free_str (info->name);
253 free_widget_value_tree (info->val);
254 memset ((void*)info, 0xDEADBEEF, sizeof (widget_info));
255 xfree (info);
258 static void
259 mark_widget_destroyed (Widget widget, XtPointer closure, XtPointer call_data)
261 widget_instance* instance = (widget_instance*)closure;
263 /* be very conservative */
264 if (instance->widget == widget)
265 instance->widget = NULL;
268 static widget_instance *
269 allocate_widget_instance (widget_info* info, Widget parent, Boolean pop_up_p)
271 widget_instance* instance =
272 (widget_instance*) xmalloc (sizeof (widget_instance));
273 memset (instance, 0, sizeof *instance);
274 instance->parent = parent;
275 instance->pop_up_p = pop_up_p;
276 instance->info = info;
277 instance->next = info->instances;
278 info->instances = instance;
280 instantiate_widget_instance (instance);
282 XtAddCallback (instance->widget, XtNdestroyCallback,
283 mark_widget_destroyed, (XtPointer)instance);
284 return instance;
287 static void
288 free_widget_instance (widget_instance *instance)
290 memset ((void*)instance, 0xDEADBEEF, sizeof (widget_instance));
291 xfree (instance);
294 static widget_info *
295 get_widget_info (LWLIB_ID id, Boolean remove_p)
297 widget_info* info;
298 widget_info* prev;
299 for (prev = NULL, info = all_widget_info;
300 info;
301 prev = info, info = info->next)
302 if (info->id == id)
304 if (remove_p)
306 if (prev)
307 prev->next = info->next;
308 else
309 all_widget_info = info->next;
311 return info;
313 return NULL;
316 /* Internal function used by the library dependent implementation to get the
317 widget_value for a given widget in an instance */
318 widget_info *
319 lw_get_widget_info (LWLIB_ID id)
321 return get_widget_info (id, 0);
324 static widget_instance *
325 get_widget_instance (Widget widget, Boolean remove_p)
327 widget_info* info;
328 widget_instance* instance;
329 widget_instance* prev;
330 for (info = all_widget_info; info; info = info->next)
331 for (prev = NULL, instance = info->instances;
332 instance;
333 prev = instance, instance = instance->next)
334 if (instance->widget == widget)
336 if (remove_p)
338 if (prev)
339 prev->next = instance->next;
340 else
341 info->instances = instance->next;
343 return instance;
345 return (widget_instance *) 0;
348 /* Value is a pointer to the widget_instance corresponding to
349 WIDGET, or null if WIDGET is not a lwlib widget. */
351 widget_instance *
352 lw_get_widget_instance (Widget widget)
354 return get_widget_instance (widget, False);
357 static widget_instance*
358 find_instance (LWLIB_ID id, Widget parent, Boolean pop_up_p)
360 widget_info* info = get_widget_info (id, False);
361 widget_instance* instance;
363 if (info)
364 for (instance = info->instances; instance; instance = instance->next)
365 if (instance->parent == parent && instance->pop_up_p == pop_up_p)
366 return instance;
368 return NULL;
372 /* utility function for widget_value */
373 static Boolean
374 safe_strcmp (const char *s1, const char *s2)
376 if (!!s1 ^ !!s2) return True;
377 return (s1 && s2) ? strcmp (s1, s2) : s1 ? False : !!s2;
381 #if 0
382 # define EXPLAIN(name, oc, nc, desc, a1, a2) \
383 printf ("Change: \"%s\"\tmax(%s=%d,%s=%d)\t%s %d %d\n", \
384 name, \
385 (oc == NO_CHANGE ? "none" : \
386 (oc == INVISIBLE_CHANGE ? "invisible" : \
387 (oc == VISIBLE_CHANGE ? "visible" : \
388 (oc == STRUCTURAL_CHANGE ? "structural" : "???")))), \
389 oc, \
390 (nc == NO_CHANGE ? "none" : \
391 (nc == INVISIBLE_CHANGE ? "invisible" : \
392 (nc == VISIBLE_CHANGE ? "visible" : \
393 (nc == STRUCTURAL_CHANGE ? "structural" : "???")))), \
394 nc, desc, a1, a2)
395 #else
396 # define EXPLAIN(name, oc, nc, desc, a1, a2) ((void) 0)
397 #endif
400 static widget_value *
401 merge_widget_value (widget_value *val1,
402 widget_value *val2,
403 int level,
404 int *change_p)
406 change_type change, this_one_change;
407 widget_value* merged_next;
408 widget_value* merged_contents;
410 if (!val1)
412 if (val2)
414 *change_p = 1;
415 return copy_widget_value_tree (val2, STRUCTURAL_CHANGE);
417 else
418 return NULL;
420 if (!val2)
422 *change_p = 1;
423 free_widget_value_tree (val1);
424 return NULL;
427 change = NO_CHANGE;
429 if (safe_strcmp (val1->name, val2->name))
431 EXPLAIN (val1->name, change, STRUCTURAL_CHANGE, "name change",
432 val1->name, val2->name);
433 change = max (change, STRUCTURAL_CHANGE);
434 safe_free_str (val1->name);
435 val1->name = safe_strdup (val2->name);
437 if (safe_strcmp (val1->value, val2->value))
439 EXPLAIN (val1->name, change, VISIBLE_CHANGE, "value change",
440 val1->value, val2->value);
441 change = max (change, VISIBLE_CHANGE);
442 safe_free_str (val1->value);
443 val1->value = safe_strdup (val2->value);
445 if (safe_strcmp (val1->key, val2->key))
447 EXPLAIN (val1->name, change, VISIBLE_CHANGE, "key change",
448 val1->key, val2->key);
449 change = max (change, VISIBLE_CHANGE);
450 safe_free_str (val1->key);
451 val1->key = safe_strdup (val2->key);
453 if (! EQ (val1->help, val2->help))
455 EXPLAIN (val1->name, change, VISIBLE_CHANGE, "help change",
456 val1->help, val2->help);
457 change = max (change, VISIBLE_CHANGE);
458 val1->help = val2->help;
460 if (val1->enabled != val2->enabled)
462 EXPLAIN (val1->name, change, VISIBLE_CHANGE, "enablement change",
463 val1->enabled, val2->enabled);
464 change = max (change, VISIBLE_CHANGE);
465 val1->enabled = val2->enabled;
467 if (val1->button_type != val2->button_type)
469 EXPLAIN (val1->name, change, VISIBLE_CHANGE, "button type change",
470 val1->button_type, val2->button_type);
471 change = max (change, VISIBLE_CHANGE);
472 val1->button_type = val2->button_type;
474 if (val1->selected != val2->selected)
476 EXPLAIN (val1->name, change, VISIBLE_CHANGE, "selection change",
477 val1->selected, val2->selected);
478 change = max (change, VISIBLE_CHANGE);
479 val1->selected = val2->selected;
481 if (val1->call_data != val2->call_data)
483 EXPLAIN (val1->name, change, INVISIBLE_CHANGE, "call-data change",
484 val1->call_data, val2->call_data);
485 change = max (change, INVISIBLE_CHANGE);
486 val1->call_data = val2->call_data;
489 if (level > 0)
491 merged_contents =
492 merge_widget_value (val1->contents, val2->contents, level - 1,
493 change_p);
495 if (val1->contents && !merged_contents)
497 /* This used to say INVISIBLE_CHANGE,
498 but it is visible and vitally important when
499 the contents of the menu bar itself are entirely deleted.
501 But maybe it doesn't matter. This fails to fix the bug. */
502 EXPLAIN (val1->name, change, STRUCTURAL_CHANGE, "(contents gone)",
503 0, 0);
504 change = max (change, STRUCTURAL_CHANGE);
506 else if (merged_contents && merged_contents->change != NO_CHANGE)
508 EXPLAIN (val1->name, change, INVISIBLE_CHANGE, "(contents change)",
509 0, 0);
510 change = max (change, INVISIBLE_CHANGE);
511 #if 0 /* This was replaced by the August 9 1996 change in lwlib-Xm.c. */
512 #ifdef USE_MOTIF
513 change = max (merged_contents->change, change);
514 #endif
515 #endif
518 val1->contents = merged_contents;
521 this_one_change = change;
523 merged_next = merge_widget_value (val1->next, val2->next, level, change_p);
525 if (val1->next && !merged_next)
527 EXPLAIN (val1->name, change, STRUCTURAL_CHANGE, "(following gone)",
528 0, 0);
529 change = max (change, STRUCTURAL_CHANGE);
531 else if (merged_next)
533 if (merged_next->change)
534 EXPLAIN (val1->name, change, merged_next->change, "(following change)",
535 0, 0);
536 change = max (change, merged_next->change);
539 val1->next = merged_next;
541 val1->this_one_change = this_one_change;
542 val1->change = change;
544 if (change > NO_CHANGE && val1->toolkit_data)
546 *change_p = 1;
547 if (val1->free_toolkit_data)
548 XtFree (val1->toolkit_data);
549 val1->toolkit_data = NULL;
552 return val1;
556 /* modifying the widgets */
557 static Widget
558 name_to_widget (widget_instance *instance, const char *name)
560 Widget widget = NULL;
562 if (!instance->widget)
563 return NULL;
565 if (!strcmp (XtName (instance->widget), name))
566 widget = instance->widget;
567 else
569 int length = strlen (name) + 2;
570 char* real_name = (char *) xmalloc (length);
571 real_name [0] = '*';
572 strcpy (real_name + 1, name);
574 widget = XtNameToWidget (instance->widget, real_name);
576 xfree (real_name);
578 return widget;
581 static void
582 set_one_value (widget_instance* instance, widget_value* val, Boolean deep_p)
584 Widget widget = name_to_widget (instance, val->name);
586 if (widget)
588 #if defined (USE_LUCID)
589 if (lw_lucid_widget_p (instance->widget))
590 xlw_update_one_widget (instance, widget, val, deep_p);
591 #endif
592 #if defined (USE_MOTIF)
593 if (lw_motif_widget_p (instance->widget))
594 xm_update_one_widget (instance, widget, val, deep_p);
595 #endif
596 #if defined (USE_XAW)
597 if (lw_xaw_widget_p (instance->widget))
598 xaw_update_one_widget (instance, widget, val, deep_p);
599 #endif
603 static void
604 update_one_widget_instance (widget_instance* instance, Boolean deep_p)
606 widget_value *val;
608 if (!instance->widget)
609 /* the widget was destroyed */
610 return;
612 for (val = instance->info->val; val; val = val->next)
613 if (val->change != NO_CHANGE)
614 set_one_value (instance, val, deep_p);
617 static void
618 update_all_widget_values (widget_info* info, Boolean deep_p)
620 widget_instance* instance;
621 widget_value* val;
623 for (instance = info->instances; instance; instance = instance->next)
624 update_one_widget_instance (instance, deep_p);
626 for (val = info->val; val; val = val->next)
627 val->change = NO_CHANGE;
631 lw_modify_all_widgets (LWLIB_ID id, widget_value* val, Boolean deep_p)
633 widget_info* info = get_widget_info (id, False);
634 widget_value* new_val;
635 widget_value* next_new_val;
636 widget_value* cur;
637 widget_value* prev;
638 widget_value* next;
639 int found;
640 int change_p = 0;
642 if (!info)
643 return 0;
645 for (new_val = val; new_val; new_val = new_val->next)
647 next_new_val = new_val->next;
648 new_val->next = NULL;
649 found = False;
650 for (prev = NULL, cur = info->val; cur; prev = cur, cur = cur->next)
651 if (!strcmp (cur->name, new_val->name))
653 found = True;
654 next = cur->next;
655 cur->next = NULL;
656 cur = merge_widget_value (cur, new_val, deep_p ? 1000 : 1,
657 &change_p);
658 if (prev)
659 prev->next = cur ? cur : next;
660 else
661 info->val = cur ? cur : next;
662 if (cur)
663 cur->next = next;
664 break;
666 if (!found)
668 /* Could not find it, add it */
669 if (prev)
670 prev->next = copy_widget_value_tree (new_val, STRUCTURAL_CHANGE);
671 else
672 info->val = copy_widget_value_tree (new_val, STRUCTURAL_CHANGE);
673 change_p = 1;
675 new_val->next = next_new_val;
678 update_all_widget_values (info, deep_p);
679 return change_p;
683 /* creating the widgets */
685 static void
686 initialize_widget_instance (widget_instance *instance)
688 widget_value* val;
690 for (val = instance->info->val; val; val = val->next)
691 val->change = STRUCTURAL_CHANGE;
693 update_one_widget_instance (instance, True);
695 for (val = instance->info->val; val; val = val->next)
696 val->change = NO_CHANGE;
700 static widget_creation_function
701 find_in_table (const char *type, const widget_creation_entry *table)
703 const widget_creation_entry* cur;
704 for (cur = table; cur->type; cur++)
705 if (!c_strcasecmp (type, cur->type))
706 return cur->function;
707 return NULL;
710 static Boolean
711 dialog_spec_p (const char *name)
713 /* return True if name matches [EILPQeilpq][1-9][Bb] or
714 [EILPQeilpq][1-9][Bb][Rr][1-9] */
715 if (!name)
716 return False;
718 switch (name [0])
720 case 'E': case 'I': case 'L': case 'P': case 'Q':
721 case 'e': case 'i': case 'l': case 'p': case 'q':
722 if (name [1] >= '0' && name [1] <= '9')
724 if (name [2] != 'B' && name [2] != 'b')
725 return False;
726 if (!name [3])
727 return True;
728 if ((name [3] == 'T' || name [3] == 't') && !name [4])
729 return True;
730 if ((name [3] == 'R' || name [3] == 'r')
731 && name [4] >= '0' && name [4] <= '9' && !name [5])
732 return True;
733 return False;
735 else
736 return False;
738 default:
739 return False;
743 static void
744 instantiate_widget_instance (widget_instance *instance)
746 widget_creation_function function = NULL;
748 #if defined (USE_LUCID)
749 if (!function)
750 function = find_in_table (instance->info->type, xlw_creation_table);
751 #endif
752 #if defined(USE_MOTIF)
753 if (!function)
754 function = find_in_table (instance->info->type, xm_creation_table);
755 #endif
756 #if defined (USE_XAW)
757 if (!function)
758 function = find_in_table (instance->info->type, xaw_creation_table);
759 #endif
761 if (!function)
763 if (dialog_spec_p (instance->info->type))
765 #if defined (USE_LUCID)
766 /* not yet */
767 #endif
768 #if defined(USE_MOTIF)
769 if (!function)
770 function = xm_create_dialog;
771 #endif
772 #if defined (USE_XAW)
773 if (!function)
774 function = xaw_create_dialog;
775 #endif
779 if (!function)
781 printf ("No creation function for widget type %s\n",
782 instance->info->type);
783 abort ();
786 instance->widget = (*function) (instance);
788 if (!instance->widget)
789 abort ();
791 /* XtRealizeWidget (instance->widget);*/
794 void
795 lw_register_widget (const char* type,
796 const char* name,
797 LWLIB_ID id,
798 widget_value* val,
799 lw_callback pre_activate_cb,
800 lw_callback selection_cb,
801 lw_callback post_activate_cb,
802 lw_callback highlight_cb)
804 if (!get_widget_info (id, False))
805 allocate_widget_info (type, name, id, val, pre_activate_cb, selection_cb,
806 post_activate_cb, highlight_cb);
809 Widget
810 lw_get_widget (LWLIB_ID id, Widget parent, Boolean pop_up_p)
812 widget_instance* instance;
814 instance = find_instance (id, parent, pop_up_p);
815 return instance ? instance->widget : NULL;
818 Widget
819 lw_make_widget (LWLIB_ID id, Widget parent, Boolean pop_up_p)
821 widget_instance* instance;
822 widget_info* info;
824 instance = find_instance (id, parent, pop_up_p);
825 if (!instance)
827 info = get_widget_info (id, False);
828 if (!info)
829 return NULL;
830 instance = allocate_widget_instance (info, parent, pop_up_p);
831 initialize_widget_instance (instance);
833 if (!instance->widget)
834 abort ();
835 return instance->widget;
838 Widget
839 lw_create_widget (const char* type, const char* name, LWLIB_ID id, widget_value* val,
840 Widget parent, Boolean pop_up_p,
841 lw_callback pre_activate_cb, lw_callback selection_cb,
842 lw_callback post_activate_cb, lw_callback highlight_cb)
844 lw_register_widget (type, name, id, val, pre_activate_cb, selection_cb,
845 post_activate_cb, highlight_cb);
846 return lw_make_widget (id, parent, pop_up_p);
850 /* destroying the widgets */
851 static void
852 destroy_one_instance (widget_instance *instance)
854 /* Remove the destroy callback on the widget; that callback will try to
855 dereference the instance object (to set its widget slot to 0, since the
856 widget is dead.) Since the instance is now dead, we don't have to worry
857 about the fact that its widget is dead too.
859 This happens in the Phase2Destroy of the widget, so this callback would
860 not have been run until arbitrarily long after the instance was freed.
862 if (instance->widget)
863 XtRemoveCallback (instance->widget, XtNdestroyCallback,
864 mark_widget_destroyed, (XtPointer)instance);
866 if (instance->widget)
868 /* The else are pretty tricky here, including the empty statement
869 at the end because it would be very bad to destroy a widget
870 twice. */
871 #if defined (USE_LUCID)
872 if (lw_lucid_widget_p (instance->widget))
873 xlw_destroy_instance (instance);
874 else
875 #endif
876 #if defined (USE_MOTIF)
877 if (lw_motif_widget_p (instance->widget))
878 xm_destroy_instance (instance);
879 else
880 #endif
881 #if defined (USE_XAW)
882 if (lw_xaw_widget_p (instance->widget))
883 xaw_destroy_instance (instance);
884 else
885 #endif
887 /* Empty compound statement to terminate if-then-else chain. */
891 free_widget_instance (instance);
894 void
895 lw_destroy_widget (Widget w)
897 widget_instance* instance = get_widget_instance (w, True);
899 if (instance)
901 widget_info *info = instance->info;
902 /* instance has already been removed from the list; free it */
903 destroy_one_instance (instance);
904 /* if there are no instances left, free the info too */
905 if (!info->instances)
906 lw_destroy_all_widgets (info->id);
910 void
911 lw_destroy_all_widgets (LWLIB_ID id)
913 widget_info* info = get_widget_info (id, True);
914 widget_instance* instance;
915 widget_instance* next;
917 if (info)
919 for (instance = info->instances; instance; )
921 next = instance->next;
922 destroy_one_instance (instance);
923 instance = next;
925 free_widget_info (info);
929 void
930 lw_destroy_everything (void)
932 while (all_widget_info)
933 lw_destroy_all_widgets (all_widget_info->id);
936 void
937 lw_destroy_all_pop_ups (void)
939 widget_info* info;
940 widget_info* next;
941 widget_instance* instance;
943 for (info = all_widget_info; info; info = next)
945 next = info->next;
946 instance = info->instances;
947 if (instance && instance->pop_up_p)
948 lw_destroy_all_widgets (info->id);
952 #ifdef USE_MOTIF
953 extern Widget first_child (Widget); /* garbage */
954 #endif
956 Widget
957 lw_raise_all_pop_up_widgets (void)
959 widget_info* info;
960 widget_instance* instance;
961 Widget result = NULL;
963 for (info = all_widget_info; info; info = info->next)
964 for (instance = info->instances; instance; instance = instance->next)
965 if (instance->pop_up_p)
967 Widget widget = instance->widget;
968 if (widget)
970 if (XtIsManaged (widget)
971 #ifdef USE_MOTIF
972 /* What a complete load of crap!!!!
973 When a dialogShell is on the screen, it is not managed!
975 || (lw_motif_widget_p (instance->widget) &&
976 XtIsManaged (first_child (widget)))
977 #endif
980 if (!result)
981 result = widget;
982 XMapRaised (XtDisplay (widget), XtWindow (widget));
986 return result;
989 static void
990 lw_pop_all_widgets (LWLIB_ID id, Boolean up)
992 widget_info* info = get_widget_info (id, False);
993 widget_instance* instance;
995 if (info)
996 for (instance = info->instances; instance; instance = instance->next)
997 if (instance->pop_up_p && instance->widget)
999 #if defined (USE_LUCID)
1000 if (lw_lucid_widget_p (instance->widget))
1002 XtRealizeWidget (instance->widget);
1003 xlw_pop_instance (instance, up);
1005 #endif
1006 #if defined (USE_MOTIF)
1007 if (lw_motif_widget_p (instance->widget))
1009 XtRealizeWidget (instance->widget);
1010 xm_pop_instance (instance, up);
1012 #endif
1013 #if defined (USE_XAW)
1014 if (lw_xaw_widget_p (instance->widget))
1016 XtRealizeWidget (XtParent (instance->widget));
1017 XtRealizeWidget (instance->widget);
1018 xaw_pop_instance (instance, up);
1020 #endif
1024 void
1025 lw_pop_up_all_widgets (LWLIB_ID id)
1027 lw_pop_all_widgets (id, True);
1030 void
1031 lw_pop_down_all_widgets (LWLIB_ID id)
1033 lw_pop_all_widgets (id, False);
1036 void
1037 lw_popup_menu (Widget widget, XEvent *event)
1039 #if defined (USE_LUCID)
1040 if (lw_lucid_widget_p (widget))
1041 xlw_popup_menu (widget, event);
1042 #endif
1043 #if defined (USE_MOTIF)
1044 if (lw_motif_widget_p (widget))
1045 xm_popup_menu (widget, event);
1046 #endif
1047 #if defined (USE_XAW)
1048 if (lw_xaw_widget_p (widget))
1049 xaw_popup_menu (widget, event);
1050 #endif
1053 \f/* get the values back */
1054 static Boolean
1055 get_one_value (widget_instance *instance, widget_value *val)
1057 Widget widget = name_to_widget (instance, val->name);
1059 if (widget)
1061 #if defined (USE_LUCID)
1062 if (lw_lucid_widget_p (instance->widget))
1063 xlw_update_one_value (instance, widget, val);
1064 #endif
1065 #if defined (USE_MOTIF)
1066 if (lw_motif_widget_p (instance->widget))
1067 xm_update_one_value (instance, widget, val);
1068 #endif
1069 #if defined (USE_XAW)
1070 if (lw_xaw_widget_p (instance->widget))
1071 xaw_update_one_value (instance, widget, val);
1072 #endif
1073 return True;
1075 else
1076 return False;
1079 Boolean
1080 lw_get_some_values (LWLIB_ID id, widget_value *val_out)
1082 widget_info* info = get_widget_info (id, False);
1083 widget_instance* instance;
1084 widget_value* val;
1085 Boolean result = False;
1087 if (!info)
1088 return False;
1090 instance = info->instances;
1091 if (!instance)
1092 return False;
1094 for (val = val_out; val; val = val->next)
1095 if (get_one_value (instance, val))
1096 result = True;
1098 return result;
1101 widget_value*
1102 lw_get_all_values (LWLIB_ID id)
1104 widget_info* info = get_widget_info (id, False);
1105 widget_value* val = info->val;
1106 if (lw_get_some_values (id, val))
1107 return val;
1108 else
1109 return NULL;
1112 /* internal function used by the library dependent implementation to get the
1113 widget_value for a given widget in an instance */
1114 widget_value*
1115 lw_get_widget_value_for_widget (widget_instance *instance, Widget w)
1117 char* name = XtName (w);
1118 widget_value* cur;
1119 for (cur = instance->info->val; cur; cur = cur->next)
1120 if (!strcmp (cur->name, name))
1121 return cur;
1122 return NULL;
1125 \f/* update other instances value when one thing changed */
1127 /* To forbid recursive calls */
1128 static Boolean lwlib_updating;
1130 /* This function can be used as an XtCallback for the widgets that get
1131 modified to update other instances of the widgets. Closure should be the
1132 widget_instance. */
1133 void
1134 lw_internal_update_other_instances (Widget widget,
1135 XtPointer closure,
1136 XtPointer call_data)
1138 widget_instance* instance = (widget_instance*)closure;
1139 char* name = XtName (widget);
1140 widget_info* info;
1141 widget_instance* cur;
1142 widget_value* val;
1144 /* Avoid possibly infinite recursion. */
1145 if (lwlib_updating)
1146 return;
1148 /* protect against the widget being destroyed */
1149 if (XtWidgetBeingDestroyedP (widget))
1150 return;
1152 /* Return immediately if there are no other instances */
1153 info = instance->info;
1154 if (!info->instances->next)
1155 return;
1157 lwlib_updating = True;
1159 for (val = info->val; val && strcmp (val->name, name); val = val->next);
1161 if (val && get_one_value (instance, val))
1162 for (cur = info->instances; cur; cur = cur->next)
1163 if (cur != instance)
1164 set_one_value (cur, val, True);
1166 lwlib_updating = False;
1170 \f/* get the id */
1172 LWLIB_ID
1173 lw_get_widget_id (Widget w)
1175 widget_instance* instance = get_widget_instance (w, False);
1177 return instance ? instance->info->id : 0;
1180 \f/* set the keyboard focus */
1181 void
1182 lw_set_keyboard_focus (Widget parent, Widget w)
1184 #if defined (USE_MOTIF)
1185 xm_set_keyboard_focus (parent, w);
1186 #else
1187 XtSetKeyboardFocus (parent, w);
1188 #endif
1191 \f/* Show busy */
1192 static void
1193 show_one_widget_busy (Widget w, Boolean flag)
1195 Pixel foreground = 0;
1196 Pixel background = 1;
1197 Widget widget_to_invert = XtNameToWidget (w, "*sheet");
1198 if (!widget_to_invert)
1199 widget_to_invert = w;
1201 XtVaGetValues (widget_to_invert,
1202 XtNforeground, &foreground,
1203 XtNbackground, &background,
1204 NULL);
1205 XtVaSetValues (widget_to_invert,
1206 XtNforeground, background,
1207 XtNbackground, foreground,
1208 NULL);
1211 void
1212 lw_show_busy (Widget w, Boolean busy)
1214 widget_instance* instance = get_widget_instance (w, False);
1215 widget_info* info;
1216 widget_instance* next;
1218 if (instance)
1220 info = instance->info;
1221 if (info->busy != busy)
1223 for (next = info->instances; next; next = next->next)
1224 if (next->widget)
1225 show_one_widget_busy (next->widget, busy);
1226 info->busy = busy;
1231 /* This hack exists because Lucid/Athena need to execute the strange
1232 function below to support geometry management. */
1233 void
1234 lw_refigure_widget (Widget w, Boolean doit)
1236 #if defined (USE_XAW)
1237 XawPanedSetRefigureMode (w, doit);
1238 #endif
1239 #if defined (USE_MOTIF)
1240 if (doit)
1241 XtManageChild (w);
1242 else
1243 XtUnmanageChild (w);
1244 #endif
1247 /* Toolkit independent way of determining if an event window is in the
1248 menubar. */
1249 Boolean
1250 lw_window_is_in_menubar (Window win, Widget menubar_widget)
1252 return menubar_widget
1253 #if defined (USE_LUCID)
1254 && XtWindow (menubar_widget) == win;
1255 #endif
1256 #if defined (USE_MOTIF)
1257 && ((XtWindow (menubar_widget) == win)
1258 || (XtWindowToWidget (XtDisplay (menubar_widget), win)
1259 && (XtParent (XtWindowToWidget (XtDisplay (menubar_widget), win))
1260 == menubar_widget)));
1261 #endif
1264 /* Motif hack to set the main window areas. */
1265 void
1266 lw_set_main_areas (Widget parent, Widget menubar, Widget work_area)
1268 #if defined (USE_MOTIF)
1269 xm_set_main_areas (parent, menubar, work_area);
1270 #endif
1273 /* Manage resizing for Motif. This disables resizing when the menubar
1274 is about to be modified. */
1275 void
1276 lw_allow_resizing (Widget w, Boolean flag)
1278 #if defined (USE_MOTIF)
1279 xm_manage_resizing (w, flag);
1280 #endif
1284 /* Value is non-zero if LABEL is a menu separator. If it is, *TYPE is
1285 set to an appropriate enumerator of type enum menu_separator.
1286 MOTIF_P non-zero means map separator types not supported by Motif
1287 to similar ones that are supported. */
1290 lw_separator_p (const char *label, enum menu_separator *type, int motif_p)
1292 int separator_p = 0;
1294 if (strlen (label) >= 3
1295 && memcmp (label, "--:", 3) == 0)
1297 static struct separator_table
1299 const char *name;
1300 enum menu_separator type;
1302 separator_names[] =
1304 {"space", SEPARATOR_NO_LINE},
1305 {"noLine", SEPARATOR_NO_LINE},
1306 {"singleLine", SEPARATOR_SINGLE_LINE},
1307 {"doubleLine", SEPARATOR_DOUBLE_LINE},
1308 {"singleDashedLine", SEPARATOR_SINGLE_DASHED_LINE},
1309 {"doubleDashedLine", SEPARATOR_DOUBLE_DASHED_LINE},
1310 {"shadowEtchedIn", SEPARATOR_SHADOW_ETCHED_IN},
1311 {"shadowEtchedOut", SEPARATOR_SHADOW_ETCHED_OUT},
1312 {"shadowEtchedInDash", SEPARATOR_SHADOW_ETCHED_IN_DASH},
1313 {"shadowEtchedOutDash", SEPARATOR_SHADOW_ETCHED_OUT_DASH},
1314 {"shadowDoubleEtchedIn", SEPARATOR_SHADOW_DOUBLE_ETCHED_IN},
1315 {"shadowDoubleEtchedOut", SEPARATOR_SHADOW_DOUBLE_ETCHED_OUT},
1316 {"shadowDoubleEtchedInDash", SEPARATOR_SHADOW_DOUBLE_ETCHED_IN_DASH},
1317 {"shadowDoubleEtchedOutDash", SEPARATOR_SHADOW_DOUBLE_ETCHED_OUT_DASH},
1318 {0,0}
1321 int i;
1323 label += 3;
1324 for (i = 0; separator_names[i].name; ++i)
1325 if (strcmp (label, separator_names[i].name) == 0)
1327 separator_p = 1;
1328 *type = separator_names[i].type;
1330 /* If separator type is not supported under Motif,
1331 use a similar one. */
1332 if (motif_p && *type >= SEPARATOR_SHADOW_DOUBLE_ETCHED_IN)
1333 *type -= 4;
1334 break;
1337 else if (strlen (label) > 3
1338 && memcmp (label, "--", 2) == 0
1339 && label[2] != '-')
1341 /* Alternative, more Emacs-style names. */
1342 static struct separator_table
1344 const char *name;
1345 enum menu_separator type;
1347 separator_names[] =
1349 {"space", SEPARATOR_NO_LINE},
1350 {"no-line", SEPARATOR_NO_LINE},
1351 {"single-line", SEPARATOR_SINGLE_LINE},
1352 {"double-line", SEPARATOR_DOUBLE_LINE},
1353 {"single-dashed-line", SEPARATOR_SINGLE_DASHED_LINE},
1354 {"double-dashed-line", SEPARATOR_DOUBLE_DASHED_LINE},
1355 {"shadow-etched-in", SEPARATOR_SHADOW_ETCHED_IN},
1356 {"shadow-etched-out", SEPARATOR_SHADOW_ETCHED_OUT},
1357 {"shadow-etched-in-dash", SEPARATOR_SHADOW_ETCHED_IN_DASH},
1358 {"shadow-etched-out-dash", SEPARATOR_SHADOW_ETCHED_OUT_DASH},
1359 {"shadow-double-etched-in", SEPARATOR_SHADOW_DOUBLE_ETCHED_IN},
1360 {"shadow-double-etched-out", SEPARATOR_SHADOW_DOUBLE_ETCHED_OUT},
1361 {"shadow-double-etched-in-dash", SEPARATOR_SHADOW_DOUBLE_ETCHED_IN_DASH},
1362 {"shadow-double-etched-out-dash",SEPARATOR_SHADOW_DOUBLE_ETCHED_OUT_DASH},
1363 {0,0}
1366 int i;
1368 label += 2;
1369 for (i = 0; separator_names[i].name; ++i)
1370 if (strcmp (label, separator_names[i].name) == 0)
1372 separator_p = 1;
1373 *type = separator_names[i].type;
1375 /* If separator type is not supported under Motif,
1376 use a similar one. */
1377 if (motif_p && *type >= SEPARATOR_SHADOW_DOUBLE_ETCHED_IN)
1378 *type -= 4;
1379 break;
1382 else
1384 /* Old-style separator, maybe. It's a separator if it contains
1385 only dashes. */
1386 while (*label == '-')
1387 ++label;
1388 separator_p = *label == 0;
1389 *type = SEPARATOR_SHADOW_ETCHED_IN;
1392 return separator_p;