Merge branch 'master' into comment-cache
[emacs.git] / lwlib / lwlib.c
blob18a46109eb4148a81692b5829ea24aee66e76d2a
1 /* A general interface to the widgets of different toolkits.
3 Copyright (C) 1992, 1993 Lucid, Inc.
4 Copyright (C) 1994-1996, 1999-2017 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 <stdlib.h>
30 #include "lwlib-int.h"
31 #include "lwlib-utils.h"
32 #include <X11/StringDefs.h>
34 #if defined (USE_LUCID)
35 #include "lwlib-Xlw.h"
36 #endif
37 #if defined (USE_MOTIF)
38 #include "lwlib-Xm.h"
39 #else /* not USE_MOTIF */
40 #if defined (USE_LUCID)
41 #define USE_XAW
42 #endif /* not USE_MOTIF && USE_LUCID */
43 #endif
44 #if defined (USE_XAW)
45 #ifdef HAVE_XAW3D
46 #include <X11/Xaw3d/Paned.h>
47 #else /* !HAVE_XAW3D */
48 #include <X11/Xaw/Paned.h>
49 #endif /* HAVE_XAW3D */
50 #include "lwlib-Xaw.h"
51 #endif
53 #if !defined (USE_LUCID) && !defined (USE_MOTIF)
54 #error At least one of USE_LUCID or USE_MOTIF must be defined.
55 #endif
57 #ifndef max
58 #define max(x, y) ((x) > (y) ? (x) : (y))
59 #endif
61 /* List of all widgets managed by the library. */
62 static widget_info*
63 all_widget_info = NULL;
65 #ifdef USE_MOTIF
66 const char *lwlib_toolkit_type = "motif";
67 #else
68 const char *lwlib_toolkit_type = "lucid";
69 #endif
71 static widget_value *merge_widget_value (widget_value *,
72 widget_value *,
73 int, int *);
74 static void instantiate_widget_instance (widget_instance *);
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);
103 static void
104 free_widget_value_tree (widget_value *wv)
106 if (!wv)
107 return;
109 xfree (wv->name);
110 xfree (wv->value);
111 xfree (wv->key);
113 wv->name = wv->value = wv->key = (char *) 0xDEADBEEF;
115 if (wv->toolkit_data && wv->free_toolkit_data)
117 XtFree (wv->toolkit_data);
118 wv->toolkit_data = (void *) 0xDEADBEEF;
121 if (wv->contents && (wv->contents != (widget_value*)1))
123 free_widget_value_tree (wv->contents);
124 wv->contents = (widget_value *) 0xDEADBEEF;
126 if (wv->next)
128 free_widget_value_tree (wv->next);
129 wv->next = (widget_value *) 0xDEADBEEF;
131 xfree (wv);
134 static widget_value *
135 copy_widget_value_tree (widget_value *val, change_type change)
137 widget_value* copy;
139 if (!val)
140 return NULL;
141 if (val == (widget_value *) 1)
142 return val;
144 copy = xmalloc (sizeof (widget_value));
145 copy->lname = copy->lkey = Qnil;
146 copy->name = xstrdup (val->name);
147 copy->value = val->value ? xstrdup (val->value) : NULL;
148 copy->key = val->key ? xstrdup (val->key) : NULL;
149 copy->help = val->help;
150 copy->enabled = val->enabled;
151 copy->button_type = val->button_type;
152 copy->selected = val->selected;
153 copy->edited = False;
154 copy->change = change;
155 copy->this_one_change = change;
156 copy->contents = copy_widget_value_tree (val->contents, change);
157 copy->call_data = val->call_data;
158 copy->next = copy_widget_value_tree (val->next, change);
159 copy->toolkit_data = NULL;
160 copy->free_toolkit_data = False;
161 return copy;
164 static widget_info *
165 allocate_widget_info (const char* type,
166 const char* name,
167 LWLIB_ID id,
168 widget_value* val,
169 lw_callback pre_activate_cb,
170 lw_callback selection_cb,
171 lw_callback post_activate_cb,
172 lw_callback highlight_cb)
174 widget_info* info = (widget_info*) xmalloc (sizeof (widget_info));
175 info->type = xstrdup (type);
176 info->name = xstrdup (name);
177 info->id = id;
178 info->val = copy_widget_value_tree (val, STRUCTURAL_CHANGE);
179 info->busy = False;
180 info->pre_activate_cb = pre_activate_cb;
181 info->selection_cb = selection_cb;
182 info->post_activate_cb = post_activate_cb;
183 info->highlight_cb = highlight_cb;
184 info->instances = NULL;
186 info->next = all_widget_info;
187 all_widget_info = info;
189 return info;
192 static void
193 free_widget_info (widget_info *info)
195 xfree (info->type);
196 xfree (info->name);
197 free_widget_value_tree (info->val);
198 memset ((void*)info, 0xDEADBEEF, sizeof (widget_info));
199 xfree (info);
202 static void
203 mark_widget_destroyed (Widget widget, XtPointer closure, XtPointer call_data)
205 widget_instance* instance = (widget_instance*)closure;
207 /* be very conservative */
208 if (instance->widget == widget)
209 instance->widget = NULL;
212 static widget_instance *
213 allocate_widget_instance (widget_info* info, Widget parent, Boolean pop_up_p)
215 widget_instance* instance =
216 (widget_instance*) xmalloc (sizeof (widget_instance));
217 memset (instance, 0, sizeof *instance);
218 instance->parent = parent;
219 instance->pop_up_p = pop_up_p;
220 instance->info = info;
221 instance->next = info->instances;
222 info->instances = instance;
224 instantiate_widget_instance (instance);
226 XtAddCallback (instance->widget, XtNdestroyCallback,
227 mark_widget_destroyed, (XtPointer)instance);
228 return instance;
231 static void
232 free_widget_instance (widget_instance *instance)
234 memset ((void*)instance, 0xDEADBEEF, sizeof (widget_instance));
235 xfree (instance);
238 static widget_info *
239 get_widget_info (LWLIB_ID id, Boolean remove_p)
241 widget_info* info;
242 widget_info* prev;
243 for (prev = NULL, info = all_widget_info;
244 info;
245 prev = info, info = info->next)
246 if (info->id == id)
248 if (remove_p)
250 if (prev)
251 prev->next = info->next;
252 else
253 all_widget_info = info->next;
255 return info;
257 return NULL;
260 /* Internal function used by the library dependent implementation to get the
261 widget_value for a given widget in an instance */
262 widget_info *
263 lw_get_widget_info (LWLIB_ID id)
265 return get_widget_info (id, 0);
268 static widget_instance *
269 get_widget_instance (Widget widget, Boolean remove_p)
271 widget_info* info;
272 widget_instance* instance;
273 widget_instance* prev;
274 for (info = all_widget_info; info; info = info->next)
275 for (prev = NULL, instance = info->instances;
276 instance;
277 prev = instance, instance = instance->next)
278 if (instance->widget == widget)
280 if (remove_p)
282 if (prev)
283 prev->next = instance->next;
284 else
285 info->instances = instance->next;
287 return instance;
289 return (widget_instance *) 0;
292 /* Value is a pointer to the widget_instance corresponding to
293 WIDGET, or null if WIDGET is not a lwlib widget. */
295 widget_instance *
296 lw_get_widget_instance (Widget widget)
298 return get_widget_instance (widget, False);
301 static widget_instance*
302 find_instance (LWLIB_ID id, Widget parent, Boolean pop_up_p)
304 widget_info* info = get_widget_info (id, False);
305 widget_instance* instance;
307 if (info)
308 for (instance = info->instances; instance; instance = instance->next)
309 if (instance->parent == parent && instance->pop_up_p == pop_up_p)
310 return instance;
312 return NULL;
316 /* utility function for widget_value */
317 static Boolean
318 safe_strcmp (const char *s1, const char *s2)
320 if (!!s1 ^ !!s2) return True;
321 return (s1 && s2) ? strcmp (s1, s2) : s1 ? False : !!s2;
325 #if 0
326 # define EXPLAIN(name, oc, nc, desc, a1, a2) \
327 printf ("Change: \"%s\"\tmax(%s=%d,%s=%d)\t%s %d %d\n", \
328 name, \
329 (oc == NO_CHANGE ? "none" : \
330 (oc == INVISIBLE_CHANGE ? "invisible" : \
331 (oc == VISIBLE_CHANGE ? "visible" : \
332 (oc == STRUCTURAL_CHANGE ? "structural" : "???")))), \
333 oc, \
334 (nc == NO_CHANGE ? "none" : \
335 (nc == INVISIBLE_CHANGE ? "invisible" : \
336 (nc == VISIBLE_CHANGE ? "visible" : \
337 (nc == STRUCTURAL_CHANGE ? "structural" : "???")))), \
338 nc, desc, a1, a2)
339 #else
340 # define EXPLAIN(name, oc, nc, desc, a1, a2) ((void) 0)
341 #endif
344 static widget_value *
345 merge_widget_value (widget_value *val1,
346 widget_value *val2,
347 int level,
348 int *change_p)
350 change_type change, this_one_change;
351 widget_value* merged_next;
352 widget_value* merged_contents;
354 if (!val1)
356 if (val2)
358 *change_p = 1;
359 return copy_widget_value_tree (val2, STRUCTURAL_CHANGE);
361 else
362 return NULL;
364 if (!val2)
366 *change_p = 1;
367 free_widget_value_tree (val1);
368 return NULL;
371 change = NO_CHANGE;
373 if (safe_strcmp (val1->name, val2->name))
375 EXPLAIN (val1->name, change, STRUCTURAL_CHANGE, "name change",
376 val1->name, val2->name);
377 change = max (change, STRUCTURAL_CHANGE);
378 dupstring (&val1->name, val2->name);
380 if (safe_strcmp (val1->value, val2->value))
382 EXPLAIN (val1->name, change, VISIBLE_CHANGE, "value change",
383 val1->value, val2->value);
384 change = max (change, VISIBLE_CHANGE);
385 dupstring (&val1->value, val2->value);
387 if (safe_strcmp (val1->key, val2->key))
389 EXPLAIN (val1->name, change, VISIBLE_CHANGE, "key change",
390 val1->key, val2->key);
391 change = max (change, VISIBLE_CHANGE);
392 dupstring (&val1->key, val2->key);
394 if (! EQ (val1->help, val2->help))
396 EXPLAIN (val1->name, change, VISIBLE_CHANGE, "help change",
397 val1->help, val2->help);
398 change = max (change, VISIBLE_CHANGE);
399 val1->help = val2->help;
401 if (val1->enabled != val2->enabled)
403 EXPLAIN (val1->name, change, VISIBLE_CHANGE, "enablement change",
404 val1->enabled, val2->enabled);
405 change = max (change, VISIBLE_CHANGE);
406 val1->enabled = val2->enabled;
408 if (val1->button_type != val2->button_type)
410 EXPLAIN (val1->name, change, VISIBLE_CHANGE, "button type change",
411 val1->button_type, val2->button_type);
412 change = max (change, VISIBLE_CHANGE);
413 val1->button_type = val2->button_type;
415 if (val1->selected != val2->selected)
417 EXPLAIN (val1->name, change, VISIBLE_CHANGE, "selection change",
418 val1->selected, val2->selected);
419 change = max (change, VISIBLE_CHANGE);
420 val1->selected = val2->selected;
422 if (val1->call_data != val2->call_data)
424 EXPLAIN (val1->name, change, INVISIBLE_CHANGE, "call-data change",
425 val1->call_data, val2->call_data);
426 change = max (change, INVISIBLE_CHANGE);
427 val1->call_data = val2->call_data;
430 if (level > 0)
432 merged_contents =
433 merge_widget_value (val1->contents, val2->contents, level - 1,
434 change_p);
436 if (val1->contents && !merged_contents)
438 /* This used to say INVISIBLE_CHANGE,
439 but it is visible and vitally important when
440 the contents of the menu bar itself are entirely deleted.
442 But maybe it doesn't matter. This fails to fix the bug. */
443 EXPLAIN (val1->name, change, STRUCTURAL_CHANGE, "(contents gone)",
444 0, 0);
445 change = max (change, STRUCTURAL_CHANGE);
447 else if (merged_contents && merged_contents->change != NO_CHANGE)
449 EXPLAIN (val1->name, change, INVISIBLE_CHANGE, "(contents change)",
450 0, 0);
451 change = max (change, INVISIBLE_CHANGE);
452 #if 0 /* This was replaced by the August 9 1996 change in lwlib-Xm.c. */
453 #ifdef USE_MOTIF
454 change = max (merged_contents->change, change);
455 #endif
456 #endif
459 val1->contents = merged_contents;
462 this_one_change = change;
464 merged_next = merge_widget_value (val1->next, val2->next, level, change_p);
466 if (val1->next && !merged_next)
468 EXPLAIN (val1->name, change, STRUCTURAL_CHANGE, "(following gone)",
469 0, 0);
470 change = max (change, STRUCTURAL_CHANGE);
472 else if (merged_next)
474 if (merged_next->change)
475 EXPLAIN (val1->name, change, merged_next->change, "(following change)",
476 0, 0);
477 change = max (change, merged_next->change);
480 val1->next = merged_next;
482 val1->this_one_change = this_one_change;
483 val1->change = change;
485 if (change > NO_CHANGE && val1->toolkit_data)
487 *change_p = 1;
488 if (val1->free_toolkit_data)
489 XtFree (val1->toolkit_data);
490 val1->toolkit_data = NULL;
493 return val1;
497 /* modifying the widgets */
498 static Widget
499 name_to_widget (widget_instance *instance, const char *name)
501 Widget widget = NULL;
503 if (!instance->widget)
504 return NULL;
506 if (!strcmp (XtName (instance->widget), name))
507 widget = instance->widget;
508 else
510 int length = strlen (name) + 2;
511 char* real_name = (char *) xmalloc (length);
512 real_name [0] = '*';
513 strcpy (real_name + 1, name);
515 widget = XtNameToWidget (instance->widget, real_name);
517 xfree (real_name);
519 return widget;
522 static void
523 set_one_value (widget_instance* instance, widget_value* val, Boolean deep_p)
525 Widget widget = name_to_widget (instance, val->name);
527 if (widget)
529 #if defined (USE_LUCID)
530 if (lw_lucid_widget_p (instance->widget))
531 xlw_update_one_widget (instance, widget, val, deep_p);
532 #endif
533 #if defined (USE_MOTIF)
534 if (lw_motif_widget_p (instance->widget))
535 xm_update_one_widget (instance, widget, val, deep_p);
536 #endif
537 #if defined (USE_XAW)
538 if (lw_xaw_widget_p (instance->widget))
539 xaw_update_one_widget (instance, widget, val, deep_p);
540 #endif
544 static void
545 update_one_widget_instance (widget_instance* instance, Boolean deep_p)
547 widget_value *val;
549 if (!instance->widget)
550 /* the widget was destroyed */
551 return;
553 for (val = instance->info->val; val; val = val->next)
554 if (val->change != NO_CHANGE)
555 set_one_value (instance, val, deep_p);
558 static void
559 update_all_widget_values (widget_info* info, Boolean deep_p)
561 widget_instance* instance;
562 widget_value* val;
564 for (instance = info->instances; instance; instance = instance->next)
565 update_one_widget_instance (instance, deep_p);
567 for (val = info->val; val; val = val->next)
568 val->change = NO_CHANGE;
572 lw_modify_all_widgets (LWLIB_ID id, widget_value* val, Boolean deep_p)
574 widget_info* info = get_widget_info (id, False);
575 widget_value* new_val;
576 widget_value* next_new_val;
577 widget_value* cur;
578 widget_value* prev;
579 widget_value* next;
580 int found;
581 int change_p = 0;
583 if (!info)
584 return 0;
586 for (new_val = val; new_val; new_val = new_val->next)
588 next_new_val = new_val->next;
589 new_val->next = NULL;
590 found = False;
591 for (prev = NULL, cur = info->val; cur; prev = cur, cur = cur->next)
592 if (!strcmp (cur->name, new_val->name))
594 found = True;
595 next = cur->next;
596 cur->next = NULL;
597 cur = merge_widget_value (cur, new_val, deep_p ? 1000 : 1,
598 &change_p);
599 if (prev)
600 prev->next = cur ? cur : next;
601 else
602 info->val = cur ? cur : next;
603 if (cur)
604 cur->next = next;
605 break;
607 if (!found)
609 /* Could not find it, add it */
610 if (prev)
611 prev->next = copy_widget_value_tree (new_val, STRUCTURAL_CHANGE);
612 else
613 info->val = copy_widget_value_tree (new_val, STRUCTURAL_CHANGE);
614 change_p = 1;
616 new_val->next = next_new_val;
619 update_all_widget_values (info, deep_p);
620 return change_p;
624 /* creating the widgets */
626 static void
627 initialize_widget_instance (widget_instance *instance)
629 widget_value* val;
631 for (val = instance->info->val; val; val = val->next)
632 val->change = STRUCTURAL_CHANGE;
634 update_one_widget_instance (instance, True);
636 for (val = instance->info->val; val; val = val->next)
637 val->change = NO_CHANGE;
641 static widget_creation_function
642 find_in_table (const char *type, const widget_creation_entry *table)
644 const widget_creation_entry* cur;
645 for (cur = table; cur->type; cur++)
646 if (!c_strcasecmp (type, cur->type))
647 return cur->function;
648 return NULL;
651 static Boolean
652 dialog_spec_p (const char *name)
654 /* return True if name matches [EILPQeilpq][1-9][Bb] or
655 [EILPQeilpq][1-9][Bb][Rr][1-9] */
656 if (!name)
657 return False;
659 switch (name [0])
661 case 'E': case 'I': case 'L': case 'P': case 'Q':
662 case 'e': case 'i': case 'l': case 'p': case 'q':
663 if (name [1] >= '0' && name [1] <= '9')
665 if (name [2] != 'B' && name [2] != 'b')
666 return False;
667 if (!name [3])
668 return True;
669 if ((name [3] == 'T' || name [3] == 't') && !name [4])
670 return True;
671 if ((name [3] == 'R' || name [3] == 'r')
672 && name [4] >= '0' && name [4] <= '9' && !name [5])
673 return True;
674 return False;
676 else
677 return False;
679 default:
680 return False;
684 static void
685 instantiate_widget_instance (widget_instance *instance)
687 widget_creation_function function = NULL;
689 #if defined (USE_LUCID)
690 if (!function)
691 function = find_in_table (instance->info->type, xlw_creation_table);
692 #endif
693 #if defined(USE_MOTIF)
694 if (!function)
695 function = find_in_table (instance->info->type, xm_creation_table);
696 #endif
697 #if defined (USE_XAW)
698 if (!function)
699 function = find_in_table (instance->info->type, xaw_creation_table);
700 #endif
702 if (!function)
704 if (dialog_spec_p (instance->info->type))
706 #if defined (USE_LUCID)
707 /* not yet */
708 #endif
709 #if defined(USE_MOTIF)
710 if (!function)
711 function = xm_create_dialog;
712 #endif
713 #if defined (USE_XAW)
714 if (!function)
715 function = xaw_create_dialog;
716 #endif
720 if (!function)
722 printf ("No creation function for widget type %s\n",
723 instance->info->type);
724 abort ();
727 instance->widget = (*function) (instance);
729 if (!instance->widget)
730 abort ();
732 /* XtRealizeWidget (instance->widget);*/
735 void
736 lw_register_widget (const char* type,
737 const char* name,
738 LWLIB_ID id,
739 widget_value* val,
740 lw_callback pre_activate_cb,
741 lw_callback selection_cb,
742 lw_callback post_activate_cb,
743 lw_callback highlight_cb)
745 if (!get_widget_info (id, False))
746 allocate_widget_info (type, name, id, val, pre_activate_cb, selection_cb,
747 post_activate_cb, highlight_cb);
750 Widget
751 lw_get_widget (LWLIB_ID id, Widget parent, Boolean pop_up_p)
753 widget_instance* instance;
755 instance = find_instance (id, parent, pop_up_p);
756 return instance ? instance->widget : NULL;
759 Widget
760 lw_make_widget (LWLIB_ID id, Widget parent, Boolean pop_up_p)
762 widget_instance* instance;
763 widget_info* info;
765 instance = find_instance (id, parent, pop_up_p);
766 if (!instance)
768 info = get_widget_info (id, False);
769 if (!info)
770 return NULL;
771 instance = allocate_widget_instance (info, parent, pop_up_p);
772 initialize_widget_instance (instance);
774 if (!instance->widget)
775 abort ();
776 return instance->widget;
779 Widget
780 lw_create_widget (const char* type, const char* name, LWLIB_ID id, widget_value* val,
781 Widget parent, Boolean pop_up_p,
782 lw_callback pre_activate_cb, lw_callback selection_cb,
783 lw_callback post_activate_cb, lw_callback highlight_cb)
785 lw_register_widget (type, name, id, val, pre_activate_cb, selection_cb,
786 post_activate_cb, highlight_cb);
787 return lw_make_widget (id, parent, pop_up_p);
791 /* destroying the widgets */
792 static void
793 destroy_one_instance (widget_instance *instance)
795 /* Remove the destroy callback on the widget; that callback will try to
796 dereference the instance object (to set its widget slot to 0, since the
797 widget is dead.) Since the instance is now dead, we don't have to worry
798 about the fact that its widget is dead too.
800 This happens in the Phase2Destroy of the widget, so this callback would
801 not have been run until arbitrarily long after the instance was freed.
803 if (instance->widget)
804 XtRemoveCallback (instance->widget, XtNdestroyCallback,
805 mark_widget_destroyed, (XtPointer)instance);
807 if (instance->widget)
809 /* The else are pretty tricky here, including the empty statement
810 at the end because it would be very bad to destroy a widget
811 twice. */
812 #if defined (USE_LUCID)
813 if (lw_lucid_widget_p (instance->widget))
814 xlw_destroy_instance (instance);
815 else
816 #endif
817 #if defined (USE_MOTIF)
818 if (lw_motif_widget_p (instance->widget))
819 xm_destroy_instance (instance);
820 else
821 #endif
822 #if defined (USE_XAW)
823 if (lw_xaw_widget_p (instance->widget))
824 xaw_destroy_instance (instance);
825 else
826 #endif
828 /* Empty compound statement to terminate if-then-else chain. */
832 free_widget_instance (instance);
835 void
836 lw_destroy_widget (Widget w)
838 widget_instance* instance = get_widget_instance (w, True);
840 if (instance)
842 widget_info *info = instance->info;
843 /* instance has already been removed from the list; free it */
844 destroy_one_instance (instance);
845 /* if there are no instances left, free the info too */
846 if (!info->instances)
847 lw_destroy_all_widgets (info->id);
851 void
852 lw_destroy_all_widgets (LWLIB_ID id)
854 widget_info* info = get_widget_info (id, True);
855 widget_instance* instance;
856 widget_instance* next;
858 if (info)
860 for (instance = info->instances; instance; )
862 next = instance->next;
863 destroy_one_instance (instance);
864 instance = next;
866 free_widget_info (info);
870 void
871 lw_destroy_everything (void)
873 while (all_widget_info)
874 lw_destroy_all_widgets (all_widget_info->id);
877 void
878 lw_destroy_all_pop_ups (void)
880 widget_info* info;
881 widget_info* next;
882 widget_instance* instance;
884 for (info = all_widget_info; info; info = next)
886 next = info->next;
887 instance = info->instances;
888 if (instance && instance->pop_up_p)
889 lw_destroy_all_widgets (info->id);
893 #ifdef USE_MOTIF
894 extern Widget first_child (Widget); /* garbage */
895 #endif
897 Widget
898 lw_raise_all_pop_up_widgets (void)
900 widget_info* info;
901 widget_instance* instance;
902 Widget result = NULL;
904 for (info = all_widget_info; info; info = info->next)
905 for (instance = info->instances; instance; instance = instance->next)
906 if (instance->pop_up_p)
908 Widget widget = instance->widget;
909 if (widget)
911 if (XtIsManaged (widget)
912 #ifdef USE_MOTIF
913 /* What a complete load of crap!!!!
914 When a dialogShell is on the screen, it is not managed!
916 || (lw_motif_widget_p (instance->widget) &&
917 XtIsManaged (first_child (widget)))
918 #endif
921 if (!result)
922 result = widget;
923 XMapRaised (XtDisplay (widget), XtWindow (widget));
927 return result;
930 static void
931 lw_pop_all_widgets (LWLIB_ID id, Boolean up)
933 widget_info* info = get_widget_info (id, False);
934 widget_instance* instance;
936 if (info)
937 for (instance = info->instances; instance; instance = instance->next)
938 if (instance->pop_up_p && instance->widget)
940 #if defined (USE_LUCID)
941 if (lw_lucid_widget_p (instance->widget))
943 XtRealizeWidget (instance->widget);
944 xlw_pop_instance (instance, up);
946 #endif
947 #if defined (USE_MOTIF)
948 if (lw_motif_widget_p (instance->widget))
950 XtRealizeWidget (instance->widget);
951 xm_pop_instance (instance, up);
953 #endif
954 #if defined (USE_XAW)
955 if (lw_xaw_widget_p (instance->widget))
957 XtRealizeWidget (XtParent (instance->widget));
958 XtRealizeWidget (instance->widget);
959 xaw_pop_instance (instance, up);
961 #endif
965 void
966 lw_pop_up_all_widgets (LWLIB_ID id)
968 lw_pop_all_widgets (id, True);
971 void
972 lw_pop_down_all_widgets (LWLIB_ID id)
974 lw_pop_all_widgets (id, False);
977 void
978 lw_popup_menu (Widget widget, XEvent *event)
980 #if defined (USE_LUCID)
981 if (lw_lucid_widget_p (widget))
982 xlw_popup_menu (widget, event);
983 #endif
984 #if defined (USE_MOTIF)
985 if (lw_motif_widget_p (widget))
986 xm_popup_menu (widget, event);
987 #endif
988 #if defined (USE_XAW)
989 if (lw_xaw_widget_p (widget))
990 xaw_popup_menu (widget, event);
991 #endif
994 \f/* get the values back */
995 static Boolean
996 get_one_value (widget_instance *instance, widget_value *val)
998 Widget widget = name_to_widget (instance, val->name);
1000 if (widget)
1002 #if defined (USE_LUCID)
1003 if (lw_lucid_widget_p (instance->widget))
1004 xlw_update_one_value (instance, widget, val);
1005 #endif
1006 #if defined (USE_MOTIF)
1007 if (lw_motif_widget_p (instance->widget))
1008 xm_update_one_value (instance, widget, val);
1009 #endif
1010 #if defined (USE_XAW)
1011 if (lw_xaw_widget_p (instance->widget))
1012 xaw_update_one_value (instance, widget, val);
1013 #endif
1014 return True;
1016 else
1017 return False;
1020 Boolean
1021 lw_get_some_values (LWLIB_ID id, widget_value *val_out)
1023 widget_info* info = get_widget_info (id, False);
1024 widget_instance* instance;
1025 widget_value* val;
1026 Boolean result = False;
1028 if (!info)
1029 return False;
1031 instance = info->instances;
1032 if (!instance)
1033 return False;
1035 for (val = val_out; val; val = val->next)
1036 if (get_one_value (instance, val))
1037 result = True;
1039 return result;
1042 widget_value*
1043 lw_get_all_values (LWLIB_ID id)
1045 widget_info* info = get_widget_info (id, False);
1046 if (info)
1048 widget_value* val = info->val;
1049 if (lw_get_some_values (id, val))
1050 return val;
1052 return NULL;
1055 /* internal function used by the library dependent implementation to get the
1056 widget_value for a given widget in an instance */
1057 widget_value*
1058 lw_get_widget_value_for_widget (widget_instance *instance, Widget w)
1060 char* name = XtName (w);
1061 widget_value* cur;
1062 for (cur = instance->info->val; cur; cur = cur->next)
1063 if (!strcmp (cur->name, name))
1064 return cur;
1065 return NULL;
1068 \f/* update other instances value when one thing changed */
1070 /* To forbid recursive calls */
1071 static Boolean lwlib_updating;
1073 /* This function can be used as an XtCallback for the widgets that get
1074 modified to update other instances of the widgets. Closure should be the
1075 widget_instance. */
1076 void
1077 lw_internal_update_other_instances (Widget widget,
1078 XtPointer closure,
1079 XtPointer call_data)
1081 widget_instance* instance = (widget_instance*)closure;
1082 char* name = XtName (widget);
1083 widget_info* info;
1084 widget_instance* cur;
1085 widget_value* val;
1087 /* Avoid possibly infinite recursion. */
1088 if (lwlib_updating)
1089 return;
1091 /* protect against the widget being destroyed */
1092 if (XtWidgetBeingDestroyedP (widget))
1093 return;
1095 /* Return immediately if there are no other instances */
1096 info = instance->info;
1097 if (!info->instances->next)
1098 return;
1100 lwlib_updating = True;
1102 for (val = info->val; val && strcmp (val->name, name); val = val->next);
1104 if (val && get_one_value (instance, val))
1105 for (cur = info->instances; cur; cur = cur->next)
1106 if (cur != instance)
1107 set_one_value (cur, val, True);
1109 lwlib_updating = False;
1113 \f/* get the id */
1115 LWLIB_ID
1116 lw_get_widget_id (Widget w)
1118 widget_instance* instance = get_widget_instance (w, False);
1120 return instance ? instance->info->id : 0;
1123 \f/* set the keyboard focus */
1124 void
1125 lw_set_keyboard_focus (Widget parent, Widget w)
1127 #if defined (USE_MOTIF)
1128 xm_set_keyboard_focus (parent, w);
1129 #else
1130 XtSetKeyboardFocus (parent, w);
1131 #endif
1134 \f/* Show busy */
1135 static void
1136 show_one_widget_busy (Widget w, Boolean flag)
1138 Pixel foreground = 0;
1139 Pixel background = 1;
1140 Widget widget_to_invert = XtNameToWidget (w, "*sheet");
1141 if (!widget_to_invert)
1142 widget_to_invert = w;
1144 XtVaGetValues (widget_to_invert,
1145 XtNforeground, &foreground,
1146 XtNbackground, &background,
1147 NULL);
1148 XtVaSetValues (widget_to_invert,
1149 XtNforeground, background,
1150 XtNbackground, foreground,
1151 NULL);
1154 void
1155 lw_show_busy (Widget w, Boolean busy)
1157 widget_instance* instance = get_widget_instance (w, False);
1158 widget_info* info;
1159 widget_instance* next;
1161 if (instance)
1163 info = instance->info;
1164 if (info->busy != busy)
1166 for (next = info->instances; next; next = next->next)
1167 if (next->widget)
1168 show_one_widget_busy (next->widget, busy);
1169 info->busy = busy;
1174 /* This hack exists because Lucid/Athena need to execute the strange
1175 function below to support geometry management. */
1176 void
1177 lw_refigure_widget (Widget w, Boolean doit)
1179 #if defined (USE_XAW)
1180 XawPanedSetRefigureMode (w, doit);
1181 #endif
1182 #if defined (USE_MOTIF)
1183 if (doit)
1184 XtManageChild (w);
1185 else
1186 XtUnmanageChild (w);
1187 #endif
1190 /* Toolkit independent way of determining if an event window is in the
1191 menubar. */
1192 Boolean
1193 lw_window_is_in_menubar (Window win, Widget menubar_widget)
1195 return menubar_widget
1196 #if defined (USE_LUCID)
1197 && XtWindow (menubar_widget) == win;
1198 #endif
1199 #if defined (USE_MOTIF)
1200 && ((XtWindow (menubar_widget) == win)
1201 || (XtWindowToWidget (XtDisplay (menubar_widget), win)
1202 && (XtParent (XtWindowToWidget (XtDisplay (menubar_widget), win))
1203 == menubar_widget)));
1204 #endif
1207 /* Motif hack to set the main window areas. */
1208 void
1209 lw_set_main_areas (Widget parent, Widget menubar, Widget work_area)
1211 #if defined (USE_MOTIF)
1212 xm_set_main_areas (parent, menubar, work_area);
1213 #endif
1216 /* Manage resizing for Motif. This disables resizing when the menubar
1217 is about to be modified. */
1218 void
1219 lw_allow_resizing (Widget w, Boolean flag)
1221 #if defined (USE_MOTIF)
1222 xm_manage_resizing (w, flag);
1223 #endif
1227 /* Value is non-zero if LABEL is a menu separator. If it is, *TYPE is
1228 set to an appropriate enumerator of type enum menu_separator.
1229 MOTIF_P non-zero means map separator types not supported by Motif
1230 to similar ones that are supported. */
1233 lw_separator_p (const char *label, enum menu_separator *type, int motif_p)
1235 int separator_p = 0;
1237 if (strlen (label) >= 3
1238 && memcmp (label, "--:", 3) == 0)
1240 static struct separator_table
1242 const char *name;
1243 enum menu_separator type;
1245 separator_names[] =
1247 {"space", SEPARATOR_NO_LINE},
1248 {"noLine", SEPARATOR_NO_LINE},
1249 {"singleLine", SEPARATOR_SINGLE_LINE},
1250 {"doubleLine", SEPARATOR_DOUBLE_LINE},
1251 {"singleDashedLine", SEPARATOR_SINGLE_DASHED_LINE},
1252 {"doubleDashedLine", SEPARATOR_DOUBLE_DASHED_LINE},
1253 {"shadowEtchedIn", SEPARATOR_SHADOW_ETCHED_IN},
1254 {"shadowEtchedOut", SEPARATOR_SHADOW_ETCHED_OUT},
1255 {"shadowEtchedInDash", SEPARATOR_SHADOW_ETCHED_IN_DASH},
1256 {"shadowEtchedOutDash", SEPARATOR_SHADOW_ETCHED_OUT_DASH},
1257 {"shadowDoubleEtchedIn", SEPARATOR_SHADOW_DOUBLE_ETCHED_IN},
1258 {"shadowDoubleEtchedOut", SEPARATOR_SHADOW_DOUBLE_ETCHED_OUT},
1259 {"shadowDoubleEtchedInDash", SEPARATOR_SHADOW_DOUBLE_ETCHED_IN_DASH},
1260 {"shadowDoubleEtchedOutDash", SEPARATOR_SHADOW_DOUBLE_ETCHED_OUT_DASH},
1261 {0,0}
1264 int i;
1266 label += 3;
1267 for (i = 0; separator_names[i].name; ++i)
1268 if (strcmp (label, separator_names[i].name) == 0)
1270 separator_p = 1;
1271 *type = separator_names[i].type;
1273 /* If separator type is not supported under Motif,
1274 use a similar one. */
1275 if (motif_p && *type >= SEPARATOR_SHADOW_DOUBLE_ETCHED_IN)
1276 *type -= 4;
1277 break;
1280 else if (strlen (label) > 3
1281 && memcmp (label, "--", 2) == 0
1282 && label[2] != '-')
1284 /* Alternative, more Emacs-style names. */
1285 static struct separator_table
1287 const char *name;
1288 enum menu_separator type;
1290 separator_names[] =
1292 {"space", SEPARATOR_NO_LINE},
1293 {"no-line", SEPARATOR_NO_LINE},
1294 {"single-line", SEPARATOR_SINGLE_LINE},
1295 {"double-line", SEPARATOR_DOUBLE_LINE},
1296 {"single-dashed-line", SEPARATOR_SINGLE_DASHED_LINE},
1297 {"double-dashed-line", SEPARATOR_DOUBLE_DASHED_LINE},
1298 {"shadow-etched-in", SEPARATOR_SHADOW_ETCHED_IN},
1299 {"shadow-etched-out", SEPARATOR_SHADOW_ETCHED_OUT},
1300 {"shadow-etched-in-dash", SEPARATOR_SHADOW_ETCHED_IN_DASH},
1301 {"shadow-etched-out-dash", SEPARATOR_SHADOW_ETCHED_OUT_DASH},
1302 {"shadow-double-etched-in", SEPARATOR_SHADOW_DOUBLE_ETCHED_IN},
1303 {"shadow-double-etched-out", SEPARATOR_SHADOW_DOUBLE_ETCHED_OUT},
1304 {"shadow-double-etched-in-dash", SEPARATOR_SHADOW_DOUBLE_ETCHED_IN_DASH},
1305 {"shadow-double-etched-out-dash",SEPARATOR_SHADOW_DOUBLE_ETCHED_OUT_DASH},
1306 {0,0}
1309 int i;
1311 label += 2;
1312 for (i = 0; separator_names[i].name; ++i)
1313 if (strcmp (label, separator_names[i].name) == 0)
1315 separator_p = 1;
1316 *type = separator_names[i].type;
1318 /* If separator type is not supported under Motif,
1319 use a similar one. */
1320 if (motif_p && *type >= SEPARATOR_SHADOW_DOUBLE_ETCHED_IN)
1321 *type -= 4;
1322 break;
1325 else
1327 /* Old-style separator, maybe. It's a separator if it contains
1328 only dashes. */
1329 while (*label == '-')
1330 ++label;
1331 separator_p = *label == 0;
1332 *type = SEPARATOR_SHADOW_ETCHED_IN;
1335 return separator_p;