* keyboard.c (parse_modifiers_uncached, parse_modifiers):
[emacs.git] / lwlib / lwlib.c
blob290ce091301c181af5ae63685776f7a55cb0f579
1 /* A general interface to the widgets of different toolkits.
3 Copyright (C) 1992, 1993 Lucid, Inc.
4 Copyright (C) 1994-1996, 1999-2011 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 #ifdef HAVE_CONFIG_H
24 #include <config.h>
25 #endif
27 #include <setjmp.h>
28 #include <lisp.h>
30 #include <sys/types.h>
31 #include <stdio.h>
32 #include <ctype.h>
33 #include "lwlib-int.h"
34 #include "lwlib-utils.h"
35 #include <X11/StringDefs.h>
37 #if defined (USE_LUCID)
38 #include "lwlib-Xlw.h"
39 #endif
40 #if defined (USE_MOTIF)
41 #include "lwlib-Xm.h"
42 #else /* not USE_MOTIF */
43 #if defined (USE_LUCID)
44 #define USE_XAW
45 #endif /* not USE_MOTIF && USE_LUCID */
46 #endif
47 #if defined (USE_XAW)
48 #ifdef HAVE_XAW3D
49 #include <X11/Xaw3d/Paned.h>
50 #else /* !HAVE_XAW3D */
51 #include <X11/Xaw/Paned.h>
52 #endif /* HAVE_XAW3D */
53 #include "lwlib-Xaw.h"
54 #endif
56 #if !defined (USE_LUCID) && !defined (USE_MOTIF)
57 #error At least one of USE_LUCID or USE_MOTIF must be defined.
58 #endif
60 #ifndef max
61 #define max(x, y) ((x) > (y) ? (x) : (y))
62 #endif
64 /* List of all widgets managed by the library. */
65 static widget_info*
66 all_widget_info = NULL;
68 #ifdef USE_MOTIF
69 const char *lwlib_toolkit_type = "motif";
70 #else
71 const char *lwlib_toolkit_type = "lucid";
72 #endif
74 static widget_value *merge_widget_value (widget_value *,
75 widget_value *,
76 int, int *);
77 static void instantiate_widget_instance (widget_instance *);
78 static int my_strcasecmp (const char *, const char *);
79 static void safe_free_str (char *);
80 static void free_widget_value_tree (widget_value *);
81 static widget_value *copy_widget_value_tree (widget_value *,
82 change_type);
83 static widget_info *allocate_widget_info (const char *, const char *, LWLIB_ID,
84 widget_value *,
85 lw_callback, lw_callback,
86 lw_callback, lw_callback);
87 static void free_widget_info (widget_info *);
88 static void mark_widget_destroyed (Widget, XtPointer, XtPointer);
89 static widget_instance *allocate_widget_instance (widget_info *,
90 Widget, Boolean);
91 static void free_widget_instance (widget_instance *);
92 static widget_info *get_widget_info (LWLIB_ID, Boolean);
93 static widget_instance *get_widget_instance (Widget, Boolean);
94 static widget_instance *find_instance (LWLIB_ID, Widget, Boolean);
95 static Boolean safe_strcmp (const char *, const char *);
96 static Widget name_to_widget (widget_instance *, const char *);
97 static void set_one_value (widget_instance *, widget_value *, Boolean);
98 static void update_one_widget_instance (widget_instance *, Boolean);
99 static void update_all_widget_values (widget_info *, Boolean);
100 static void initialize_widget_instance (widget_instance *);
101 static widget_creation_function find_in_table (const char *, const widget_creation_entry *);
102 static Boolean dialog_spec_p (const char *);
103 static void destroy_one_instance (widget_instance *);
104 static void lw_pop_all_widgets (LWLIB_ID, Boolean);
105 static Boolean get_one_value (widget_instance *, widget_value *);
106 static void show_one_widget_busy (Widget, Boolean);
107 \f/* utility functions for widget_instance and widget_info */
108 char *
109 safe_strdup (const char *s)
111 char *result;
112 if (! s) return 0;
113 result = (char *) xmalloc (strlen (s) + 1);
114 strcpy (result, s);
115 return result;
118 /* Like strcmp but ignore differences in case. */
120 static int
121 my_strcasecmp (const char *s1, const char *s2)
123 while (1)
125 int c1 = *s1++;
126 int c2 = *s2++;
127 if (isupper (c1))
128 c1 = tolower (c1);
129 if (isupper (c2))
130 c2 = tolower (c2);
131 if (c1 != c2)
132 return (c1 > c2 ? 1 : -1);
133 if (c1 == 0)
134 return 0;
138 static void
139 safe_free_str (char *s)
141 free (s);
144 static widget_value *widget_value_free_list = 0;
145 static int malloc_cpt = 0;
147 widget_value *
148 malloc_widget_value (void)
150 widget_value *wv;
151 if (widget_value_free_list)
153 wv = widget_value_free_list;
154 widget_value_free_list = wv->free_list;
155 wv->free_list = 0;
157 else
159 wv = (widget_value *) xmalloc (sizeof (widget_value));
160 malloc_cpt++;
162 memset ((void*) wv, 0, sizeof (widget_value));
163 return wv;
166 /* this is analogous to free(). It frees only what was allocated
167 by malloc_widget_value(), and no substructures.
169 void
170 free_widget_value (widget_value *wv)
172 if (wv->free_list)
173 abort ();
175 if (malloc_cpt > 25)
177 /* When the number of already allocated cells is too big,
178 We free it. */
179 free (wv);
180 malloc_cpt--;
182 else
184 wv->free_list = widget_value_free_list;
185 widget_value_free_list = wv;
189 static void
190 free_widget_value_tree (widget_value *wv)
192 if (!wv)
193 return;
195 free (wv->name);
196 free (wv->value);
197 free (wv->key);
199 wv->name = wv->value = wv->key = (char *) 0xDEADBEEF;
201 if (wv->toolkit_data && wv->free_toolkit_data)
203 XtFree (wv->toolkit_data);
204 wv->toolkit_data = (void *) 0xDEADBEEF;
207 if (wv->contents && (wv->contents != (widget_value*)1))
209 free_widget_value_tree (wv->contents);
210 wv->contents = (widget_value *) 0xDEADBEEF;
212 if (wv->next)
214 free_widget_value_tree (wv->next);
215 wv->next = (widget_value *) 0xDEADBEEF;
217 free_widget_value (wv);
220 static widget_value *
221 copy_widget_value_tree (widget_value *val, change_type change)
223 widget_value* copy;
225 if (!val)
226 return NULL;
227 if (val == (widget_value *) 1)
228 return val;
230 copy = malloc_widget_value ();
231 copy->name = safe_strdup (val->name);
232 copy->value = safe_strdup (val->value);
233 copy->key = safe_strdup (val->key);
234 copy->help = val->help;
235 copy->enabled = val->enabled;
236 copy->button_type = val->button_type;
237 copy->selected = val->selected;
238 copy->edited = False;
239 copy->change = change;
240 copy->this_one_change = change;
241 copy->contents = copy_widget_value_tree (val->contents, change);
242 copy->call_data = val->call_data;
243 copy->next = copy_widget_value_tree (val->next, change);
244 copy->toolkit_data = NULL;
245 copy->free_toolkit_data = False;
246 return copy;
249 static widget_info *
250 allocate_widget_info (const char* type,
251 const char* name,
252 LWLIB_ID id,
253 widget_value* val,
254 lw_callback pre_activate_cb,
255 lw_callback selection_cb,
256 lw_callback post_activate_cb,
257 lw_callback highlight_cb)
259 widget_info* info = (widget_info*) xmalloc (sizeof (widget_info));
260 info->type = safe_strdup (type);
261 info->name = safe_strdup (name);
262 info->id = id;
263 info->val = copy_widget_value_tree (val, STRUCTURAL_CHANGE);
264 info->busy = False;
265 info->pre_activate_cb = pre_activate_cb;
266 info->selection_cb = selection_cb;
267 info->post_activate_cb = post_activate_cb;
268 info->highlight_cb = highlight_cb;
269 info->instances = NULL;
271 info->next = all_widget_info;
272 all_widget_info = info;
274 return info;
277 static void
278 free_widget_info (widget_info *info)
280 safe_free_str (info->type);
281 safe_free_str (info->name);
282 free_widget_value_tree (info->val);
283 memset ((void*)info, 0xDEADBEEF, sizeof (widget_info));
284 free (info);
287 static void
288 mark_widget_destroyed (Widget widget, XtPointer closure, XtPointer call_data)
290 widget_instance* instance = (widget_instance*)closure;
292 /* be very conservative */
293 if (instance->widget == widget)
294 instance->widget = NULL;
297 static widget_instance *
298 allocate_widget_instance (widget_info* info, Widget parent, Boolean pop_up_p)
300 widget_instance* instance =
301 (widget_instance*) xmalloc (sizeof (widget_instance));
302 memset (instance, 0, sizeof *instance);
303 instance->parent = parent;
304 instance->pop_up_p = pop_up_p;
305 instance->info = info;
306 instance->next = info->instances;
307 info->instances = instance;
309 instantiate_widget_instance (instance);
311 XtAddCallback (instance->widget, XtNdestroyCallback,
312 mark_widget_destroyed, (XtPointer)instance);
313 return instance;
316 static void
317 free_widget_instance (widget_instance *instance)
319 memset ((void*)instance, 0xDEADBEEF, sizeof (widget_instance));
320 free (instance);
323 static widget_info *
324 get_widget_info (LWLIB_ID id, Boolean remove_p)
326 widget_info* info;
327 widget_info* prev;
328 for (prev = NULL, info = all_widget_info;
329 info;
330 prev = info, info = info->next)
331 if (info->id == id)
333 if (remove_p)
335 if (prev)
336 prev->next = info->next;
337 else
338 all_widget_info = info->next;
340 return info;
342 return NULL;
345 /* Internal function used by the library dependent implementation to get the
346 widget_value for a given widget in an instance */
347 widget_info *
348 lw_get_widget_info (LWLIB_ID id)
350 return get_widget_info (id, 0);
353 static widget_instance *
354 get_widget_instance (Widget widget, Boolean remove_p)
356 widget_info* info;
357 widget_instance* instance;
358 widget_instance* prev;
359 for (info = all_widget_info; info; info = info->next)
360 for (prev = NULL, instance = info->instances;
361 instance;
362 prev = instance, instance = instance->next)
363 if (instance->widget == widget)
365 if (remove_p)
367 if (prev)
368 prev->next = instance->next;
369 else
370 info->instances = instance->next;
372 return instance;
374 return (widget_instance *) 0;
377 /* Value is a pointer to the widget_instance corresponding to
378 WIDGET, or null if WIDGET is not a lwlib widget. */
380 widget_instance *
381 lw_get_widget_instance (Widget widget)
383 return get_widget_instance (widget, False);
386 static widget_instance*
387 find_instance (LWLIB_ID id, Widget parent, Boolean pop_up_p)
389 widget_info* info = get_widget_info (id, False);
390 widget_instance* instance;
392 if (info)
393 for (instance = info->instances; instance; instance = instance->next)
394 if (instance->parent == parent && instance->pop_up_p == pop_up_p)
395 return instance;
397 return NULL;
401 /* utility function for widget_value */
402 static Boolean
403 safe_strcmp (const char *s1, const char *s2)
405 if (!!s1 ^ !!s2) return True;
406 return (s1 && s2) ? strcmp (s1, s2) : s1 ? False : !!s2;
410 #if 0
411 # define EXPLAIN(name, oc, nc, desc, a1, a2) \
412 printf ("Change: \"%s\"\tmax(%s=%d,%s=%d)\t%s %d %d\n", \
413 name, \
414 (oc == NO_CHANGE ? "none" : \
415 (oc == INVISIBLE_CHANGE ? "invisible" : \
416 (oc == VISIBLE_CHANGE ? "visible" : \
417 (oc == STRUCTURAL_CHANGE ? "structural" : "???")))), \
418 oc, \
419 (nc == NO_CHANGE ? "none" : \
420 (nc == INVISIBLE_CHANGE ? "invisible" : \
421 (nc == VISIBLE_CHANGE ? "visible" : \
422 (nc == STRUCTURAL_CHANGE ? "structural" : "???")))), \
423 nc, desc, a1, a2)
424 #else
425 # define EXPLAIN(name, oc, nc, desc, a1, a2)
426 #endif
429 static widget_value *
430 merge_widget_value (widget_value *val1,
431 widget_value *val2,
432 int level,
433 int *change_p)
435 change_type change, this_one_change;
436 widget_value* merged_next;
437 widget_value* merged_contents;
439 if (!val1)
441 if (val2)
443 *change_p = 1;
444 return copy_widget_value_tree (val2, STRUCTURAL_CHANGE);
446 else
447 return NULL;
449 if (!val2)
451 *change_p = 1;
452 free_widget_value_tree (val1);
453 return NULL;
456 change = NO_CHANGE;
458 if (safe_strcmp (val1->name, val2->name))
460 EXPLAIN (val1->name, change, STRUCTURAL_CHANGE, "name change",
461 val1->name, val2->name);
462 change = max (change, STRUCTURAL_CHANGE);
463 safe_free_str (val1->name);
464 val1->name = safe_strdup (val2->name);
466 if (safe_strcmp (val1->value, val2->value))
468 EXPLAIN (val1->name, change, VISIBLE_CHANGE, "value change",
469 val1->value, val2->value);
470 change = max (change, VISIBLE_CHANGE);
471 safe_free_str (val1->value);
472 val1->value = safe_strdup (val2->value);
474 if (safe_strcmp (val1->key, val2->key))
476 EXPLAIN (val1->name, change, VISIBLE_CHANGE, "key change",
477 val1->key, val2->key);
478 change = max (change, VISIBLE_CHANGE);
479 safe_free_str (val1->key);
480 val1->key = safe_strdup (val2->key);
482 if (! EQ (val1->help, val2->help))
484 EXPLAIN (val1->name, change, VISIBLE_CHANGE, "help change",
485 val1->help, val2->help);
486 change = max (change, VISIBLE_CHANGE);
487 val1->help = val2->help;
489 if (val1->enabled != val2->enabled)
491 EXPLAIN (val1->name, change, VISIBLE_CHANGE, "enablement change",
492 val1->enabled, val2->enabled);
493 change = max (change, VISIBLE_CHANGE);
494 val1->enabled = val2->enabled;
496 if (val1->button_type != val2->button_type)
498 EXPLAIN (val1->name, change, VISIBLE_CHANGE, "button type change",
499 val1->button_type, val2->button_type);
500 change = max (change, VISIBLE_CHANGE);
501 val1->button_type = val2->button_type;
503 if (val1->selected != val2->selected)
505 EXPLAIN (val1->name, change, VISIBLE_CHANGE, "selection change",
506 val1->selected, val2->selected);
507 change = max (change, VISIBLE_CHANGE);
508 val1->selected = val2->selected;
510 if (val1->call_data != val2->call_data)
512 EXPLAIN (val1->name, change, INVISIBLE_CHANGE, "call-data change",
513 val1->call_data, val2->call_data);
514 change = max (change, INVISIBLE_CHANGE);
515 val1->call_data = val2->call_data;
518 if (level > 0)
520 merged_contents =
521 merge_widget_value (val1->contents, val2->contents, level - 1,
522 change_p);
524 if (val1->contents && !merged_contents)
526 /* This used to say INVISIBLE_CHANGE,
527 but it is visible and vitally important when
528 the contents of the menu bar itself are entirely deleted.
530 But maybe it doesn't matter. This fails to fix the bug. */
531 EXPLAIN (val1->name, change, STRUCTURAL_CHANGE, "(contents gone)",
532 0, 0);
533 change = max (change, STRUCTURAL_CHANGE);
535 else if (merged_contents && merged_contents->change != NO_CHANGE)
537 EXPLAIN (val1->name, change, INVISIBLE_CHANGE, "(contents change)",
538 0, 0);
539 change = max (change, INVISIBLE_CHANGE);
540 #if 0 /* This was replaced by the August 9 1996 change in lwlib-Xm.c. */
541 #ifdef USE_MOTIF
542 change = max (merged_contents->change, change);
543 #endif
544 #endif
547 val1->contents = merged_contents;
550 this_one_change = change;
552 merged_next = merge_widget_value (val1->next, val2->next, level, change_p);
554 if (val1->next && !merged_next)
556 EXPLAIN (val1->name, change, STRUCTURAL_CHANGE, "(following gone)",
557 0, 0);
558 change = max (change, STRUCTURAL_CHANGE);
560 else if (merged_next)
562 if (merged_next->change)
563 EXPLAIN (val1->name, change, merged_next->change, "(following change)",
564 0, 0);
565 change = max (change, merged_next->change);
568 val1->next = merged_next;
570 val1->this_one_change = this_one_change;
571 val1->change = change;
573 if (change > NO_CHANGE && val1->toolkit_data)
575 *change_p = 1;
576 if (val1->free_toolkit_data)
577 XtFree (val1->toolkit_data);
578 val1->toolkit_data = NULL;
581 return val1;
585 /* modifying the widgets */
586 static Widget
587 name_to_widget (widget_instance *instance, const char *name)
589 Widget widget = NULL;
591 if (!instance->widget)
592 return NULL;
594 if (!strcmp (XtName (instance->widget), name))
595 widget = instance->widget;
596 else
598 int length = strlen (name) + 2;
599 char* real_name = (char *) xmalloc (length);
600 real_name [0] = '*';
601 strcpy (real_name + 1, name);
603 widget = XtNameToWidget (instance->widget, real_name);
605 free (real_name);
607 return widget;
610 static void
611 set_one_value (widget_instance* instance, widget_value* val, Boolean deep_p)
613 Widget widget = name_to_widget (instance, val->name);
615 if (widget)
617 #if defined (USE_LUCID)
618 if (lw_lucid_widget_p (instance->widget))
619 xlw_update_one_widget (instance, widget, val, deep_p);
620 #endif
621 #if defined (USE_MOTIF)
622 if (lw_motif_widget_p (instance->widget))
623 xm_update_one_widget (instance, widget, val, deep_p);
624 #endif
625 #if defined (USE_XAW)
626 if (lw_xaw_widget_p (instance->widget))
627 xaw_update_one_widget (instance, widget, val, deep_p);
628 #endif
632 static void
633 update_one_widget_instance (widget_instance* instance, Boolean deep_p)
635 widget_value *val;
637 if (!instance->widget)
638 /* the widget was destroyed */
639 return;
641 for (val = instance->info->val; val; val = val->next)
642 if (val->change != NO_CHANGE)
643 set_one_value (instance, val, deep_p);
646 static void
647 update_all_widget_values (widget_info* info, Boolean deep_p)
649 widget_instance* instance;
650 widget_value* val;
652 for (instance = info->instances; instance; instance = instance->next)
653 update_one_widget_instance (instance, deep_p);
655 for (val = info->val; val; val = val->next)
656 val->change = NO_CHANGE;
660 lw_modify_all_widgets (LWLIB_ID id, widget_value* val, Boolean deep_p)
662 widget_info* info = get_widget_info (id, False);
663 widget_value* new_val;
664 widget_value* next_new_val;
665 widget_value* cur;
666 widget_value* prev;
667 widget_value* next;
668 int found;
669 int change_p = 0;
671 if (!info)
672 return 0;
674 for (new_val = val; new_val; new_val = new_val->next)
676 next_new_val = new_val->next;
677 new_val->next = NULL;
678 found = False;
679 for (prev = NULL, cur = info->val; cur; prev = cur, cur = cur->next)
680 if (!strcmp (cur->name, new_val->name))
682 found = True;
683 next = cur->next;
684 cur->next = NULL;
685 cur = merge_widget_value (cur, new_val, deep_p ? 1000 : 1,
686 &change_p);
687 if (prev)
688 prev->next = cur ? cur : next;
689 else
690 info->val = cur ? cur : next;
691 if (cur)
692 cur->next = next;
693 break;
695 if (!found)
697 /* Could not find it, add it */
698 if (prev)
699 prev->next = copy_widget_value_tree (new_val, STRUCTURAL_CHANGE);
700 else
701 info->val = copy_widget_value_tree (new_val, STRUCTURAL_CHANGE);
702 change_p = 1;
704 new_val->next = next_new_val;
707 update_all_widget_values (info, deep_p);
708 return change_p;
712 /* creating the widgets */
714 static void
715 initialize_widget_instance (widget_instance *instance)
717 widget_value* val;
719 for (val = instance->info->val; val; val = val->next)
720 val->change = STRUCTURAL_CHANGE;
722 update_one_widget_instance (instance, True);
724 for (val = instance->info->val; val; val = val->next)
725 val->change = NO_CHANGE;
729 static widget_creation_function
730 find_in_table (const char *type, const widget_creation_entry *table)
732 const widget_creation_entry* cur;
733 for (cur = table; cur->type; cur++)
734 if (!my_strcasecmp (type, cur->type))
735 return cur->function;
736 return NULL;
739 static Boolean
740 dialog_spec_p (const char *name)
742 /* return True if name matches [EILPQeilpq][1-9][Bb] or
743 [EILPQeilpq][1-9][Bb][Rr][1-9] */
744 if (!name)
745 return False;
747 switch (name [0])
749 case 'E': case 'I': case 'L': case 'P': case 'Q':
750 case 'e': case 'i': case 'l': case 'p': case 'q':
751 if (name [1] >= '0' && name [1] <= '9')
753 if (name [2] != 'B' && name [2] != 'b')
754 return False;
755 if (!name [3])
756 return True;
757 if ((name [3] == 'T' || name [3] == 't') && !name [4])
758 return True;
759 if ((name [3] == 'R' || name [3] == 'r')
760 && name [4] >= '0' && name [4] <= '9' && !name [5])
761 return True;
762 return False;
764 else
765 return False;
767 default:
768 return False;
772 static void
773 instantiate_widget_instance (widget_instance *instance)
775 widget_creation_function function = NULL;
777 #if defined (USE_LUCID)
778 if (!function)
779 function = find_in_table (instance->info->type, xlw_creation_table);
780 #endif
781 #if defined(USE_MOTIF)
782 if (!function)
783 function = find_in_table (instance->info->type, xm_creation_table);
784 #endif
785 #if defined (USE_XAW)
786 if (!function)
787 function = find_in_table (instance->info->type, xaw_creation_table);
788 #endif
790 if (!function)
792 if (dialog_spec_p (instance->info->type))
794 #if defined (USE_LUCID)
795 /* not yet */
796 #endif
797 #if defined(USE_MOTIF)
798 if (!function)
799 function = xm_create_dialog;
800 #endif
801 #if defined (USE_XAW)
802 if (!function)
803 function = xaw_create_dialog;
804 #endif
808 if (!function)
810 printf ("No creation function for widget type %s\n",
811 instance->info->type);
812 abort ();
815 instance->widget = (*function) (instance);
817 if (!instance->widget)
818 abort ();
820 /* XtRealizeWidget (instance->widget);*/
823 void
824 lw_register_widget (const char* type,
825 const char* name,
826 LWLIB_ID id,
827 widget_value* val,
828 lw_callback pre_activate_cb,
829 lw_callback selection_cb,
830 lw_callback post_activate_cb,
831 lw_callback highlight_cb)
833 if (!get_widget_info (id, False))
834 allocate_widget_info (type, name, id, val, pre_activate_cb, selection_cb,
835 post_activate_cb, highlight_cb);
838 Widget
839 lw_get_widget (LWLIB_ID id, Widget parent, Boolean pop_up_p)
841 widget_instance* instance;
843 instance = find_instance (id, parent, pop_up_p);
844 return instance ? instance->widget : NULL;
847 Widget
848 lw_make_widget (LWLIB_ID id, Widget parent, Boolean pop_up_p)
850 widget_instance* instance;
851 widget_info* info;
853 instance = find_instance (id, parent, pop_up_p);
854 if (!instance)
856 info = get_widget_info (id, False);
857 if (!info)
858 return NULL;
859 instance = allocate_widget_instance (info, parent, pop_up_p);
860 initialize_widget_instance (instance);
862 if (!instance->widget)
863 abort ();
864 return instance->widget;
867 Widget
868 lw_create_widget (const char* type, const char* name, LWLIB_ID id, widget_value* val,
869 Widget parent, Boolean pop_up_p,
870 lw_callback pre_activate_cb, lw_callback selection_cb,
871 lw_callback post_activate_cb, lw_callback highlight_cb)
873 lw_register_widget (type, name, id, val, pre_activate_cb, selection_cb,
874 post_activate_cb, highlight_cb);
875 return lw_make_widget (id, parent, pop_up_p);
879 /* destroying the widgets */
880 static void
881 destroy_one_instance (widget_instance *instance)
883 /* Remove the destroy callback on the widget; that callback will try to
884 dereference the instance object (to set its widget slot to 0, since the
885 widget is dead.) Since the instance is now dead, we don't have to worry
886 about the fact that its widget is dead too.
888 This happens in the Phase2Destroy of the widget, so this callback would
889 not have been run until arbitrarily long after the instance was freed.
891 if (instance->widget)
892 XtRemoveCallback (instance->widget, XtNdestroyCallback,
893 mark_widget_destroyed, (XtPointer)instance);
895 if (instance->widget)
897 /* The else are pretty tricky here, including the empty statement
898 at the end because it would be very bad to destroy a widget
899 twice. */
900 #if defined (USE_LUCID)
901 if (lw_lucid_widget_p (instance->widget))
902 xlw_destroy_instance (instance);
903 else
904 #endif
905 #if defined (USE_MOTIF)
906 if (lw_motif_widget_p (instance->widget))
907 xm_destroy_instance (instance);
908 else
909 #endif
910 #if defined (USE_XAW)
911 if (lw_xaw_widget_p (instance->widget))
912 xaw_destroy_instance (instance);
913 else
914 #endif
915 /* do not remove the empty statement */
919 free_widget_instance (instance);
922 void
923 lw_destroy_widget (Widget w)
925 widget_instance* instance = get_widget_instance (w, True);
927 if (instance)
929 widget_info *info = instance->info;
930 /* instance has already been removed from the list; free it */
931 destroy_one_instance (instance);
932 /* if there are no instances left, free the info too */
933 if (!info->instances)
934 lw_destroy_all_widgets (info->id);
938 void
939 lw_destroy_all_widgets (LWLIB_ID id)
941 widget_info* info = get_widget_info (id, True);
942 widget_instance* instance;
943 widget_instance* next;
945 if (info)
947 for (instance = info->instances; instance; )
949 next = instance->next;
950 destroy_one_instance (instance);
951 instance = next;
953 free_widget_info (info);
957 void
958 lw_destroy_everything (void)
960 while (all_widget_info)
961 lw_destroy_all_widgets (all_widget_info->id);
964 void
965 lw_destroy_all_pop_ups (void)
967 widget_info* info;
968 widget_info* next;
969 widget_instance* instance;
971 for (info = all_widget_info; info; info = next)
973 next = info->next;
974 instance = info->instances;
975 if (instance && instance->pop_up_p)
976 lw_destroy_all_widgets (info->id);
980 #ifdef USE_MOTIF
981 extern Widget first_child (/* Widget */); /* garbage */
982 #endif
984 Widget
985 lw_raise_all_pop_up_widgets (void)
987 widget_info* info;
988 widget_instance* instance;
989 Widget result = NULL;
991 for (info = all_widget_info; info; info = info->next)
992 for (instance = info->instances; instance; instance = instance->next)
993 if (instance->pop_up_p)
995 Widget widget = instance->widget;
996 if (widget)
998 if (XtIsManaged (widget)
999 #ifdef USE_MOTIF
1000 /* What a complete load of crap!!!!
1001 When a dialogShell is on the screen, it is not managed!
1003 || (lw_motif_widget_p (instance->widget) &&
1004 XtIsManaged (first_child (widget)))
1005 #endif
1008 if (!result)
1009 result = widget;
1010 XMapRaised (XtDisplay (widget), XtWindow (widget));
1014 return result;
1017 static void
1018 lw_pop_all_widgets (LWLIB_ID id, Boolean up)
1020 widget_info* info = get_widget_info (id, False);
1021 widget_instance* instance;
1023 if (info)
1024 for (instance = info->instances; instance; instance = instance->next)
1025 if (instance->pop_up_p && instance->widget)
1027 #if defined (USE_LUCID)
1028 if (lw_lucid_widget_p (instance->widget))
1030 XtRealizeWidget (instance->widget);
1031 xlw_pop_instance (instance, up);
1033 #endif
1034 #if defined (USE_MOTIF)
1035 if (lw_motif_widget_p (instance->widget))
1037 XtRealizeWidget (instance->widget);
1038 xm_pop_instance (instance, up);
1040 #endif
1041 #if defined (USE_XAW)
1042 if (lw_xaw_widget_p (instance->widget))
1044 XtRealizeWidget (XtParent (instance->widget));
1045 XtRealizeWidget (instance->widget);
1046 xaw_pop_instance (instance, up);
1048 #endif
1052 void
1053 lw_pop_up_all_widgets (LWLIB_ID id)
1055 lw_pop_all_widgets (id, True);
1058 void
1059 lw_pop_down_all_widgets (LWLIB_ID id)
1061 lw_pop_all_widgets (id, False);
1064 void
1065 lw_popup_menu (Widget widget, XEvent *event)
1067 #if defined (USE_LUCID)
1068 if (lw_lucid_widget_p (widget))
1069 xlw_popup_menu (widget, event);
1070 #endif
1071 #if defined (USE_MOTIF)
1072 if (lw_motif_widget_p (widget))
1073 xm_popup_menu (widget, event);
1074 #endif
1075 #if defined (USE_XAW)
1076 if (lw_xaw_widget_p (widget))
1077 xaw_popup_menu (widget, event);
1078 #endif
1081 \f/* get the values back */
1082 static Boolean
1083 get_one_value (widget_instance *instance, widget_value *val)
1085 Widget widget = name_to_widget (instance, val->name);
1087 if (widget)
1089 #if defined (USE_LUCID)
1090 if (lw_lucid_widget_p (instance->widget))
1091 xlw_update_one_value (instance, widget, val);
1092 #endif
1093 #if defined (USE_MOTIF)
1094 if (lw_motif_widget_p (instance->widget))
1095 xm_update_one_value (instance, widget, val);
1096 #endif
1097 #if defined (USE_XAW)
1098 if (lw_xaw_widget_p (instance->widget))
1099 xaw_update_one_value (instance, widget, val);
1100 #endif
1101 return True;
1103 else
1104 return False;
1107 Boolean
1108 lw_get_some_values (LWLIB_ID id, widget_value *val_out)
1110 widget_info* info = get_widget_info (id, False);
1111 widget_instance* instance;
1112 widget_value* val;
1113 Boolean result = False;
1115 if (!info)
1116 return False;
1118 instance = info->instances;
1119 if (!instance)
1120 return False;
1122 for (val = val_out; val; val = val->next)
1123 if (get_one_value (instance, val))
1124 result = True;
1126 return result;
1129 widget_value*
1130 lw_get_all_values (LWLIB_ID id)
1132 widget_info* info = get_widget_info (id, False);
1133 widget_value* val = info->val;
1134 if (lw_get_some_values (id, val))
1135 return val;
1136 else
1137 return NULL;
1140 /* internal function used by the library dependent implementation to get the
1141 widget_value for a given widget in an instance */
1142 widget_value*
1143 lw_get_widget_value_for_widget (widget_instance *instance, Widget w)
1145 char* name = XtName (w);
1146 widget_value* cur;
1147 for (cur = instance->info->val; cur; cur = cur->next)
1148 if (!strcmp (cur->name, name))
1149 return cur;
1150 return NULL;
1153 \f/* update other instances value when one thing changed */
1155 /* To forbid recursive calls */
1156 static Boolean lwlib_updating;
1158 /* This function can be used as a an XtCallback for the widgets that get
1159 modified to update other instances of the widgets. Closure should be the
1160 widget_instance. */
1161 void
1162 lw_internal_update_other_instances (Widget widget,
1163 XtPointer closure,
1164 XtPointer call_data)
1166 widget_instance* instance = (widget_instance*)closure;
1167 char* name = XtName (widget);
1168 widget_info* info;
1169 widget_instance* cur;
1170 widget_value* val;
1172 /* Avoid possibly infinite recursion. */
1173 if (lwlib_updating)
1174 return;
1176 /* protect against the widget being destroyed */
1177 if (XtWidgetBeingDestroyedP (widget))
1178 return;
1180 /* Return immediately if there are no other instances */
1181 info = instance->info;
1182 if (!info->instances->next)
1183 return;
1185 lwlib_updating = True;
1187 for (val = info->val; val && strcmp (val->name, name); val = val->next);
1189 if (val && get_one_value (instance, val))
1190 for (cur = info->instances; cur; cur = cur->next)
1191 if (cur != instance)
1192 set_one_value (cur, val, True);
1194 lwlib_updating = False;
1198 \f/* get the id */
1200 LWLIB_ID
1201 lw_get_widget_id (Widget w)
1203 widget_instance* instance = get_widget_instance (w, False);
1205 return instance ? instance->info->id : 0;
1208 \f/* set the keyboard focus */
1209 void
1210 lw_set_keyboard_focus (Widget parent, Widget w)
1212 #if defined (USE_MOTIF)
1213 xm_set_keyboard_focus (parent, w);
1214 #else
1215 XtSetKeyboardFocus (parent, w);
1216 #endif
1219 \f/* Show busy */
1220 static void
1221 show_one_widget_busy (Widget w, Boolean flag)
1223 Pixel foreground = 0;
1224 Pixel background = 1;
1225 Widget widget_to_invert = XtNameToWidget (w, "*sheet");
1226 if (!widget_to_invert)
1227 widget_to_invert = w;
1229 XtVaGetValues (widget_to_invert,
1230 XtNforeground, &foreground,
1231 XtNbackground, &background,
1232 NULL);
1233 XtVaSetValues (widget_to_invert,
1234 XtNforeground, background,
1235 XtNbackground, foreground,
1236 NULL);
1239 void
1240 lw_show_busy (Widget w, Boolean busy)
1242 widget_instance* instance = get_widget_instance (w, False);
1243 widget_info* info;
1244 widget_instance* next;
1246 if (instance)
1248 info = instance->info;
1249 if (info->busy != busy)
1251 for (next = info->instances; next; next = next->next)
1252 if (next->widget)
1253 show_one_widget_busy (next->widget, busy);
1254 info->busy = busy;
1259 /* This hack exists because Lucid/Athena need to execute the strange
1260 function below to support geometry management. */
1261 void
1262 lw_refigure_widget (Widget w, Boolean doit)
1264 #if defined (USE_XAW)
1265 XawPanedSetRefigureMode (w, doit);
1266 #endif
1267 #if defined (USE_MOTIF)
1268 if (doit)
1269 XtManageChild (w);
1270 else
1271 XtUnmanageChild (w);
1272 #endif
1275 /* Toolkit independent way of determining if an event window is in the
1276 menubar. */
1277 Boolean
1278 lw_window_is_in_menubar (Window win, Widget menubar_widget)
1280 return menubar_widget
1281 #if defined (USE_LUCID)
1282 && XtWindow (menubar_widget) == win;
1283 #endif
1284 #if defined (USE_MOTIF)
1285 && ((XtWindow (menubar_widget) == win)
1286 || (XtWindowToWidget (XtDisplay (menubar_widget), win)
1287 && (XtParent (XtWindowToWidget (XtDisplay (menubar_widget), win))
1288 == menubar_widget)));
1289 #endif
1292 /* Motif hack to set the main window areas. */
1293 void
1294 lw_set_main_areas (Widget parent, Widget menubar, Widget work_area)
1296 #if defined (USE_MOTIF)
1297 xm_set_main_areas (parent, menubar, work_area);
1298 #endif
1301 /* Manage resizing for Motif. This disables resizing when the menubar
1302 is about to be modified. */
1303 void
1304 lw_allow_resizing (Widget w, Boolean flag)
1306 #if defined (USE_MOTIF)
1307 xm_manage_resizing (w, flag);
1308 #endif
1312 /* Value is non-zero if LABEL is a menu separator. If it is, *TYPE is
1313 set to an appropriate enumerator of type enum menu_separator.
1314 MOTIF_P non-zero means map separator types not supported by Motif
1315 to similar ones that are supported. */
1318 lw_separator_p (const char *label, enum menu_separator *type, int motif_p)
1320 int separator_p = 0;
1322 if (strlen (label) >= 3
1323 && memcmp (label, "--:", 3) == 0)
1325 static struct separator_table
1327 const char *name;
1328 enum menu_separator type;
1330 separator_names[] =
1332 {"space", SEPARATOR_NO_LINE},
1333 {"noLine", SEPARATOR_NO_LINE},
1334 {"singleLine", SEPARATOR_SINGLE_LINE},
1335 {"doubleLine", SEPARATOR_DOUBLE_LINE},
1336 {"singleDashedLine", SEPARATOR_SINGLE_DASHED_LINE},
1337 {"doubleDashedLine", SEPARATOR_DOUBLE_DASHED_LINE},
1338 {"shadowEtchedIn", SEPARATOR_SHADOW_ETCHED_IN},
1339 {"shadowEtchedOut", SEPARATOR_SHADOW_ETCHED_OUT},
1340 {"shadowEtchedInDash", SEPARATOR_SHADOW_ETCHED_IN_DASH},
1341 {"shadowEtchedOutDash", SEPARATOR_SHADOW_ETCHED_OUT_DASH},
1342 {"shadowDoubleEtchedIn", SEPARATOR_SHADOW_DOUBLE_ETCHED_IN},
1343 {"shadowDoubleEtchedOut", SEPARATOR_SHADOW_DOUBLE_ETCHED_OUT},
1344 {"shadowDoubleEtchedInDash", SEPARATOR_SHADOW_DOUBLE_ETCHED_IN_DASH},
1345 {"shadowDoubleEtchedOutDash", SEPARATOR_SHADOW_DOUBLE_ETCHED_OUT_DASH},
1346 {0,0}
1349 int i;
1351 label += 3;
1352 for (i = 0; separator_names[i].name; ++i)
1353 if (strcmp (label, separator_names[i].name) == 0)
1355 separator_p = 1;
1356 *type = separator_names[i].type;
1358 /* If separator type is not supported under Motif,
1359 use a similar one. */
1360 if (motif_p && *type >= SEPARATOR_SHADOW_DOUBLE_ETCHED_IN)
1361 *type -= 4;
1362 break;
1365 else if (strlen (label) > 3
1366 && memcmp (label, "--", 2) == 0
1367 && label[2] != '-')
1369 /* Alternative, more Emacs-style names. */
1370 static struct separator_table
1372 const char *name;
1373 enum menu_separator type;
1375 separator_names[] =
1377 {"space", SEPARATOR_NO_LINE},
1378 {"no-line", SEPARATOR_NO_LINE},
1379 {"single-line", SEPARATOR_SINGLE_LINE},
1380 {"double-line", SEPARATOR_DOUBLE_LINE},
1381 {"single-dashed-line", SEPARATOR_SINGLE_DASHED_LINE},
1382 {"double-dashed-line", SEPARATOR_DOUBLE_DASHED_LINE},
1383 {"shadow-etched-in", SEPARATOR_SHADOW_ETCHED_IN},
1384 {"shadow-etched-out", SEPARATOR_SHADOW_ETCHED_OUT},
1385 {"shadow-etched-in-dash", SEPARATOR_SHADOW_ETCHED_IN_DASH},
1386 {"shadow-etched-out-dash", SEPARATOR_SHADOW_ETCHED_OUT_DASH},
1387 {"shadow-double-etched-in", SEPARATOR_SHADOW_DOUBLE_ETCHED_IN},
1388 {"shadow-double-etched-out", SEPARATOR_SHADOW_DOUBLE_ETCHED_OUT},
1389 {"shadow-double-etched-in-dash", SEPARATOR_SHADOW_DOUBLE_ETCHED_IN_DASH},
1390 {"shadow-double-etched-out-dash",SEPARATOR_SHADOW_DOUBLE_ETCHED_OUT_DASH},
1391 {0,0}
1394 int i;
1396 label += 2;
1397 for (i = 0; separator_names[i].name; ++i)
1398 if (strcmp (label, separator_names[i].name) == 0)
1400 separator_p = 1;
1401 *type = separator_names[i].type;
1403 /* If separator type is not supported under Motif,
1404 use a similar one. */
1405 if (motif_p && *type >= SEPARATOR_SHADOW_DOUBLE_ETCHED_IN)
1406 *type -= 4;
1407 break;
1410 else
1412 /* Old-style separator, maybe. It's a separator if it contains
1413 only dashes. */
1414 while (*label == '-')
1415 ++label;
1416 separator_p = *label == 0;
1417 *type = SEPARATOR_SHADOW_ETCHED_IN;
1420 return separator_p;