Rearrange an entry (test commit to bzr++ssh).
[emacs.git] / lwlib / lwlib.c
blob1f434e5b611f5f66907a727abf57ee41344f1c77
1 /* A general interface to the widgets of different toolkits.
2 Copyright (C) 1992, 1993 Lucid, Inc.
3 Copyright (C) 1994, 1995, 1996, 1999, 2000, 2001, 2002, 2003, 2004,
4 2005, 2006, 2007, 2008, 2009, 2010 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 "../src/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 *) malloc (strlen (s) + 1);
114 if (! result)
115 return 0;
116 strcpy (result, s);
117 return result;
120 /* Like strcmp but ignore differences in case. */
122 static int
123 my_strcasecmp (const char *s1, const char *s2)
125 while (1)
127 int c1 = *s1++;
128 int c2 = *s2++;
129 if (isupper (c1))
130 c1 = tolower (c1);
131 if (isupper (c2))
132 c2 = tolower (c2);
133 if (c1 != c2)
134 return (c1 > c2 ? 1 : -1);
135 if (c1 == 0)
136 return 0;
140 static void
141 safe_free_str (char *s)
143 free (s);
146 static widget_value *widget_value_free_list = 0;
147 static int malloc_cpt = 0;
149 widget_value *
150 malloc_widget_value (void)
152 widget_value *wv;
153 if (widget_value_free_list)
155 wv = widget_value_free_list;
156 widget_value_free_list = wv->free_list;
157 wv->free_list = 0;
159 else
161 wv = (widget_value *) malloc (sizeof (widget_value));
162 malloc_cpt++;
164 memset ((void*) wv, 0, sizeof (widget_value));
165 return wv;
168 /* this is analogous to free(). It frees only what was allocated
169 by malloc_widget_value(), and no substructures.
171 void
172 free_widget_value (widget_value *wv)
174 if (wv->free_list)
175 abort ();
177 if (malloc_cpt > 25)
179 /* When the number of already allocated cells is too big,
180 We free it. */
181 free (wv);
182 malloc_cpt--;
184 else
186 wv->free_list = widget_value_free_list;
187 widget_value_free_list = wv;
191 static void
192 free_widget_value_tree (widget_value *wv)
194 if (!wv)
195 return;
197 free (wv->name);
198 free (wv->value);
199 free (wv->key);
201 wv->name = wv->value = wv->key = (char *) 0xDEADBEEF;
203 if (wv->toolkit_data && wv->free_toolkit_data)
205 XtFree (wv->toolkit_data);
206 wv->toolkit_data = (void *) 0xDEADBEEF;
209 if (wv->contents && (wv->contents != (widget_value*)1))
211 free_widget_value_tree (wv->contents);
212 wv->contents = (widget_value *) 0xDEADBEEF;
214 if (wv->next)
216 free_widget_value_tree (wv->next);
217 wv->next = (widget_value *) 0xDEADBEEF;
219 free_widget_value (wv);
222 static widget_value *
223 copy_widget_value_tree (widget_value *val, change_type change)
225 widget_value* copy;
227 if (!val)
228 return NULL;
229 if (val == (widget_value *) 1)
230 return val;
232 copy = malloc_widget_value ();
233 copy->name = safe_strdup (val->name);
234 copy->value = safe_strdup (val->value);
235 copy->key = safe_strdup (val->key);
236 copy->help = val->help;
237 copy->enabled = val->enabled;
238 copy->button_type = val->button_type;
239 copy->selected = val->selected;
240 copy->edited = False;
241 copy->change = change;
242 copy->this_one_change = change;
243 copy->contents = copy_widget_value_tree (val->contents, change);
244 copy->call_data = val->call_data;
245 copy->next = copy_widget_value_tree (val->next, change);
246 copy->toolkit_data = NULL;
247 copy->free_toolkit_data = False;
248 return copy;
251 static widget_info *
252 allocate_widget_info (const char* type,
253 const char* name,
254 LWLIB_ID id,
255 widget_value* val,
256 lw_callback pre_activate_cb,
257 lw_callback selection_cb,
258 lw_callback post_activate_cb,
259 lw_callback highlight_cb)
261 widget_info* info = (widget_info*)malloc (sizeof (widget_info));
262 info->type = safe_strdup (type);
263 info->name = safe_strdup (name);
264 info->id = id;
265 info->val = copy_widget_value_tree (val, STRUCTURAL_CHANGE);
266 info->busy = False;
267 info->pre_activate_cb = pre_activate_cb;
268 info->selection_cb = selection_cb;
269 info->post_activate_cb = post_activate_cb;
270 info->highlight_cb = highlight_cb;
271 info->instances = NULL;
273 info->next = all_widget_info;
274 all_widget_info = info;
276 return info;
279 static void
280 free_widget_info (widget_info *info)
282 safe_free_str (info->type);
283 safe_free_str (info->name);
284 free_widget_value_tree (info->val);
285 memset ((void*)info, 0xDEADBEEF, sizeof (widget_info));
286 free (info);
289 static void
290 mark_widget_destroyed (Widget widget, XtPointer closure, XtPointer call_data)
292 widget_instance* instance = (widget_instance*)closure;
294 /* be very conservative */
295 if (instance->widget == widget)
296 instance->widget = NULL;
299 static widget_instance *
300 allocate_widget_instance (widget_info* info, Widget parent, Boolean pop_up_p)
302 widget_instance* instance =
303 (widget_instance*)malloc (sizeof (widget_instance));
304 memset (instance, 0, sizeof *instance);
305 instance->parent = parent;
306 instance->pop_up_p = pop_up_p;
307 instance->info = info;
308 instance->next = info->instances;
309 info->instances = instance;
311 instantiate_widget_instance (instance);
313 XtAddCallback (instance->widget, XtNdestroyCallback,
314 mark_widget_destroyed, (XtPointer)instance);
315 return instance;
318 static void
319 free_widget_instance (widget_instance *instance)
321 memset ((void*)instance, 0xDEADBEEF, sizeof (widget_instance));
322 free (instance);
325 static widget_info *
326 get_widget_info (LWLIB_ID id, Boolean remove_p)
328 widget_info* info;
329 widget_info* prev;
330 for (prev = NULL, info = all_widget_info;
331 info;
332 prev = info, info = info->next)
333 if (info->id == id)
335 if (remove_p)
337 if (prev)
338 prev->next = info->next;
339 else
340 all_widget_info = info->next;
342 return info;
344 return NULL;
347 /* Internal function used by the library dependent implementation to get the
348 widget_value for a given widget in an instance */
349 widget_info *
350 lw_get_widget_info (LWLIB_ID id)
352 return get_widget_info (id, 0);
355 static widget_instance *
356 get_widget_instance (Widget widget, Boolean remove_p)
358 widget_info* info;
359 widget_instance* instance;
360 widget_instance* prev;
361 for (info = all_widget_info; info; info = info->next)
362 for (prev = NULL, instance = info->instances;
363 instance;
364 prev = instance, instance = instance->next)
365 if (instance->widget == widget)
367 if (remove_p)
369 if (prev)
370 prev->next = instance->next;
371 else
372 info->instances = instance->next;
374 return instance;
376 return (widget_instance *) 0;
379 /* Value is a pointer to the widget_instance corresponding to
380 WIDGET, or null if WIDGET is not a lwlib widget. */
382 widget_instance *
383 lw_get_widget_instance (Widget widget)
385 return get_widget_instance (widget, False);
388 static widget_instance*
389 find_instance (LWLIB_ID id, Widget parent, Boolean pop_up_p)
391 widget_info* info = get_widget_info (id, False);
392 widget_instance* instance;
394 if (info)
395 for (instance = info->instances; instance; instance = instance->next)
396 if (instance->parent == parent && instance->pop_up_p == pop_up_p)
397 return instance;
399 return NULL;
403 /* utility function for widget_value */
404 static Boolean
405 safe_strcmp (const char *s1, const char *s2)
407 if (!!s1 ^ !!s2) return True;
408 return (s1 && s2) ? strcmp (s1, s2) : s1 ? False : !!s2;
412 #if 0
413 # define EXPLAIN(name, oc, nc, desc, a1, a2) \
414 printf ("Change: \"%s\"\tmax(%s=%d,%s=%d)\t%s %d %d\n", \
415 name, \
416 (oc == NO_CHANGE ? "none" : \
417 (oc == INVISIBLE_CHANGE ? "invisible" : \
418 (oc == VISIBLE_CHANGE ? "visible" : \
419 (oc == STRUCTURAL_CHANGE ? "structural" : "???")))), \
420 oc, \
421 (nc == NO_CHANGE ? "none" : \
422 (nc == INVISIBLE_CHANGE ? "invisible" : \
423 (nc == VISIBLE_CHANGE ? "visible" : \
424 (nc == STRUCTURAL_CHANGE ? "structural" : "???")))), \
425 nc, desc, a1, a2)
426 #else
427 # define EXPLAIN(name, oc, nc, desc, a1, a2)
428 #endif
431 static widget_value *
432 merge_widget_value (widget_value *val1,
433 widget_value *val2,
434 int level,
435 int *change_p)
437 change_type change, this_one_change;
438 widget_value* merged_next;
439 widget_value* merged_contents;
441 if (!val1)
443 if (val2)
445 *change_p = 1;
446 return copy_widget_value_tree (val2, STRUCTURAL_CHANGE);
448 else
449 return NULL;
451 if (!val2)
453 *change_p = 1;
454 free_widget_value_tree (val1);
455 return NULL;
458 change = NO_CHANGE;
460 if (safe_strcmp (val1->name, val2->name))
462 EXPLAIN (val1->name, change, STRUCTURAL_CHANGE, "name change",
463 val1->name, val2->name);
464 change = max (change, STRUCTURAL_CHANGE);
465 safe_free_str (val1->name);
466 val1->name = safe_strdup (val2->name);
468 if (safe_strcmp (val1->value, val2->value))
470 EXPLAIN (val1->name, change, VISIBLE_CHANGE, "value change",
471 val1->value, val2->value);
472 change = max (change, VISIBLE_CHANGE);
473 safe_free_str (val1->value);
474 val1->value = safe_strdup (val2->value);
476 if (safe_strcmp (val1->key, val2->key))
478 EXPLAIN (val1->name, change, VISIBLE_CHANGE, "key change",
479 val1->key, val2->key);
480 change = max (change, VISIBLE_CHANGE);
481 safe_free_str (val1->key);
482 val1->key = safe_strdup (val2->key);
484 if (! EQ (val1->help, val2->help))
486 EXPLAIN (val1->name, change, VISIBLE_CHANGE, "help change",
487 val1->help, val2->help);
488 change = max (change, VISIBLE_CHANGE);
489 val1->help = val2->help;
491 if (val1->enabled != val2->enabled)
493 EXPLAIN (val1->name, change, VISIBLE_CHANGE, "enablement change",
494 val1->enabled, val2->enabled);
495 change = max (change, VISIBLE_CHANGE);
496 val1->enabled = val2->enabled;
498 if (val1->button_type != val2->button_type)
500 EXPLAIN (val1->name, change, VISIBLE_CHANGE, "button type change",
501 val1->button_type, val2->button_type);
502 change = max (change, VISIBLE_CHANGE);
503 val1->button_type = val2->button_type;
505 if (val1->selected != val2->selected)
507 EXPLAIN (val1->name, change, VISIBLE_CHANGE, "selection change",
508 val1->selected, val2->selected);
509 change = max (change, VISIBLE_CHANGE);
510 val1->selected = val2->selected;
512 if (val1->call_data != val2->call_data)
514 EXPLAIN (val1->name, change, INVISIBLE_CHANGE, "call-data change",
515 val1->call_data, val2->call_data);
516 change = max (change, INVISIBLE_CHANGE);
517 val1->call_data = val2->call_data;
520 if (level > 0)
522 merged_contents =
523 merge_widget_value (val1->contents, val2->contents, level - 1,
524 change_p);
526 if (val1->contents && !merged_contents)
528 /* This used to say INVISIBLE_CHANGE,
529 but it is visible and vitally important when
530 the contents of the menu bar itself are entirely deleted.
532 But maybe it doesn't matter. This fails to fix the bug. */
533 EXPLAIN (val1->name, change, STRUCTURAL_CHANGE, "(contents gone)",
534 0, 0);
535 change = max (change, STRUCTURAL_CHANGE);
537 else if (merged_contents && merged_contents->change != NO_CHANGE)
539 EXPLAIN (val1->name, change, INVISIBLE_CHANGE, "(contents change)",
540 0, 0);
541 change = max (change, INVISIBLE_CHANGE);
542 #if 0 /* This was replaced by the August 9 1996 change in lwlib-Xm.c. */
543 #ifdef USE_MOTIF
544 change = max (merged_contents->change, change);
545 #endif
546 #endif
549 val1->contents = merged_contents;
552 this_one_change = change;
554 merged_next = merge_widget_value (val1->next, val2->next, level, change_p);
556 if (val1->next && !merged_next)
558 EXPLAIN (val1->name, change, STRUCTURAL_CHANGE, "(following gone)",
559 0, 0);
560 change = max (change, STRUCTURAL_CHANGE);
562 else if (merged_next)
564 if (merged_next->change)
565 EXPLAIN (val1->name, change, merged_next->change, "(following change)",
566 0, 0);
567 change = max (change, merged_next->change);
570 val1->next = merged_next;
572 val1->this_one_change = this_one_change;
573 val1->change = change;
575 if (change > NO_CHANGE && val1->toolkit_data)
577 *change_p = 1;
578 if (val1->free_toolkit_data)
579 XtFree (val1->toolkit_data);
580 val1->toolkit_data = NULL;
583 return val1;
587 /* modifying the widgets */
588 static Widget
589 name_to_widget (widget_instance *instance, const char *name)
591 Widget widget = NULL;
593 if (!instance->widget)
594 return NULL;
596 if (!strcmp (XtName (instance->widget), name))
597 widget = instance->widget;
598 else
600 int length = strlen (name) + 2;
601 char* real_name = (char *) xmalloc (length);
602 real_name [0] = '*';
603 strcpy (real_name + 1, name);
605 widget = XtNameToWidget (instance->widget, real_name);
607 free (real_name);
609 return widget;
612 static void
613 set_one_value (widget_instance* instance, widget_value* val, Boolean deep_p)
615 Widget widget = name_to_widget (instance, val->name);
617 if (widget)
619 #if defined (USE_LUCID)
620 if (lw_lucid_widget_p (instance->widget))
621 xlw_update_one_widget (instance, widget, val, deep_p);
622 #endif
623 #if defined (USE_MOTIF)
624 if (lw_motif_widget_p (instance->widget))
625 xm_update_one_widget (instance, widget, val, deep_p);
626 #endif
627 #if defined (USE_XAW)
628 if (lw_xaw_widget_p (instance->widget))
629 xaw_update_one_widget (instance, widget, val, deep_p);
630 #endif
634 static void
635 update_one_widget_instance (widget_instance* instance, Boolean deep_p)
637 widget_value *val;
639 if (!instance->widget)
640 /* the widget was destroyed */
641 return;
643 for (val = instance->info->val; val; val = val->next)
644 if (val->change != NO_CHANGE)
645 set_one_value (instance, val, deep_p);
648 static void
649 update_all_widget_values (widget_info* info, Boolean deep_p)
651 widget_instance* instance;
652 widget_value* val;
654 for (instance = info->instances; instance; instance = instance->next)
655 update_one_widget_instance (instance, deep_p);
657 for (val = info->val; val; val = val->next)
658 val->change = NO_CHANGE;
662 lw_modify_all_widgets (LWLIB_ID id, widget_value* val, Boolean deep_p)
664 widget_info* info = get_widget_info (id, False);
665 widget_value* new_val;
666 widget_value* next_new_val;
667 widget_value* cur;
668 widget_value* prev;
669 widget_value* next;
670 int found;
671 int change_p = 0;
673 if (!info)
674 return 0;
676 for (new_val = val; new_val; new_val = new_val->next)
678 next_new_val = new_val->next;
679 new_val->next = NULL;
680 found = False;
681 for (prev = NULL, cur = info->val; cur; prev = cur, cur = cur->next)
682 if (!strcmp (cur->name, new_val->name))
684 found = True;
685 next = cur->next;
686 cur->next = NULL;
687 cur = merge_widget_value (cur, new_val, deep_p ? 1000 : 1,
688 &change_p);
689 if (prev)
690 prev->next = cur ? cur : next;
691 else
692 info->val = cur ? cur : next;
693 if (cur)
694 cur->next = next;
695 break;
697 if (!found)
699 /* Could not find it, add it */
700 if (prev)
701 prev->next = copy_widget_value_tree (new_val, STRUCTURAL_CHANGE);
702 else
703 info->val = copy_widget_value_tree (new_val, STRUCTURAL_CHANGE);
704 change_p = 1;
706 new_val->next = next_new_val;
709 update_all_widget_values (info, deep_p);
710 return change_p;
714 /* creating the widgets */
716 static void
717 initialize_widget_instance (widget_instance *instance)
719 widget_value* val;
721 for (val = instance->info->val; val; val = val->next)
722 val->change = STRUCTURAL_CHANGE;
724 update_one_widget_instance (instance, True);
726 for (val = instance->info->val; val; val = val->next)
727 val->change = NO_CHANGE;
731 static widget_creation_function
732 find_in_table (const char *type, const widget_creation_entry *table)
734 const widget_creation_entry* cur;
735 for (cur = table; cur->type; cur++)
736 if (!my_strcasecmp (type, cur->type))
737 return cur->function;
738 return NULL;
741 static Boolean
742 dialog_spec_p (const char *name)
744 /* return True if name matches [EILPQeilpq][1-9][Bb] or
745 [EILPQeilpq][1-9][Bb][Rr][1-9] */
746 if (!name)
747 return False;
749 switch (name [0])
751 case 'E': case 'I': case 'L': case 'P': case 'Q':
752 case 'e': case 'i': case 'l': case 'p': case 'q':
753 if (name [1] >= '0' && name [1] <= '9')
755 if (name [2] != 'B' && name [2] != 'b')
756 return False;
757 if (!name [3])
758 return True;
759 if ((name [3] == 'T' || name [3] == 't') && !name [4])
760 return True;
761 if ((name [3] == 'R' || name [3] == 'r')
762 && name [4] >= '0' && name [4] <= '9' && !name [5])
763 return True;
764 return False;
766 else
767 return False;
769 default:
770 return False;
774 static void
775 instantiate_widget_instance (widget_instance *instance)
777 widget_creation_function function = NULL;
779 #if defined (USE_LUCID)
780 if (!function)
781 function = find_in_table (instance->info->type, xlw_creation_table);
782 #endif
783 #if defined(USE_MOTIF)
784 if (!function)
785 function = find_in_table (instance->info->type, xm_creation_table);
786 #endif
787 #if defined (USE_XAW)
788 if (!function)
789 function = find_in_table (instance->info->type, xaw_creation_table);
790 #endif
792 if (!function)
794 if (dialog_spec_p (instance->info->type))
796 #if defined (USE_LUCID)
797 /* not yet */
798 #endif
799 #if defined(USE_MOTIF)
800 if (!function)
801 function = xm_create_dialog;
802 #endif
803 #if defined (USE_XAW)
804 if (!function)
805 function = xaw_create_dialog;
806 #endif
810 if (!function)
812 printf ("No creation function for widget type %s\n",
813 instance->info->type);
814 abort ();
817 instance->widget = (*function) (instance);
819 if (!instance->widget)
820 abort ();
822 /* XtRealizeWidget (instance->widget);*/
825 void
826 lw_register_widget (const char* type,
827 const char* name,
828 LWLIB_ID id,
829 widget_value* val,
830 lw_callback pre_activate_cb,
831 lw_callback selection_cb,
832 lw_callback post_activate_cb,
833 lw_callback highlight_cb)
835 if (!get_widget_info (id, False))
836 allocate_widget_info (type, name, id, val, pre_activate_cb, selection_cb,
837 post_activate_cb, highlight_cb);
840 Widget
841 lw_get_widget (LWLIB_ID id, Widget parent, Boolean pop_up_p)
843 widget_instance* instance;
845 instance = find_instance (id, parent, pop_up_p);
846 return instance ? instance->widget : NULL;
849 Widget
850 lw_make_widget (LWLIB_ID id, Widget parent, Boolean pop_up_p)
852 widget_instance* instance;
853 widget_info* info;
855 instance = find_instance (id, parent, pop_up_p);
856 if (!instance)
858 info = get_widget_info (id, False);
859 if (!info)
860 return NULL;
861 instance = allocate_widget_instance (info, parent, pop_up_p);
862 initialize_widget_instance (instance);
864 if (!instance->widget)
865 abort ();
866 return instance->widget;
869 Widget
870 lw_create_widget (const char* type, const char* name, LWLIB_ID id, widget_value* val,
871 Widget parent, Boolean pop_up_p,
872 lw_callback pre_activate_cb, lw_callback selection_cb,
873 lw_callback post_activate_cb, lw_callback highlight_cb)
875 lw_register_widget (type, name, id, val, pre_activate_cb, selection_cb,
876 post_activate_cb, highlight_cb);
877 return lw_make_widget (id, parent, pop_up_p);
881 /* destroying the widgets */
882 static void
883 destroy_one_instance (widget_instance *instance)
885 /* Remove the destroy callback on the widget; that callback will try to
886 dereference the instance object (to set its widget slot to 0, since the
887 widget is dead.) Since the instance is now dead, we don't have to worry
888 about the fact that its widget is dead too.
890 This happens in the Phase2Destroy of the widget, so this callback would
891 not have been run until arbitrarily long after the instance was freed.
893 if (instance->widget)
894 XtRemoveCallback (instance->widget, XtNdestroyCallback,
895 mark_widget_destroyed, (XtPointer)instance);
897 if (instance->widget)
899 /* The else are pretty tricky here, including the empty statement
900 at the end because it would be very bad to destroy a widget
901 twice. */
902 #if defined (USE_LUCID)
903 if (lw_lucid_widget_p (instance->widget))
904 xlw_destroy_instance (instance);
905 else
906 #endif
907 #if defined (USE_MOTIF)
908 if (lw_motif_widget_p (instance->widget))
909 xm_destroy_instance (instance);
910 else
911 #endif
912 #if defined (USE_XAW)
913 if (lw_xaw_widget_p (instance->widget))
914 xaw_destroy_instance (instance);
915 else
916 #endif
917 /* do not remove the empty statement */
921 free_widget_instance (instance);
924 void
925 lw_destroy_widget (Widget w)
927 widget_instance* instance = get_widget_instance (w, True);
929 if (instance)
931 widget_info *info = instance->info;
932 /* instance has already been removed from the list; free it */
933 destroy_one_instance (instance);
934 /* if there are no instances left, free the info too */
935 if (!info->instances)
936 lw_destroy_all_widgets (info->id);
940 void
941 lw_destroy_all_widgets (LWLIB_ID id)
943 widget_info* info = get_widget_info (id, True);
944 widget_instance* instance;
945 widget_instance* next;
947 if (info)
949 for (instance = info->instances; instance; )
951 next = instance->next;
952 destroy_one_instance (instance);
953 instance = next;
955 free_widget_info (info);
959 void
960 lw_destroy_everything (void)
962 while (all_widget_info)
963 lw_destroy_all_widgets (all_widget_info->id);
966 void
967 lw_destroy_all_pop_ups (void)
969 widget_info* info;
970 widget_info* next;
971 widget_instance* instance;
973 for (info = all_widget_info; info; info = next)
975 next = info->next;
976 instance = info->instances;
977 if (instance && instance->pop_up_p)
978 lw_destroy_all_widgets (info->id);
982 #ifdef USE_MOTIF
983 extern Widget first_child (/* Widget */); /* garbage */
984 #endif
986 Widget
987 lw_raise_all_pop_up_widgets (void)
989 widget_info* info;
990 widget_instance* instance;
991 Widget result = NULL;
993 for (info = all_widget_info; info; info = info->next)
994 for (instance = info->instances; instance; instance = instance->next)
995 if (instance->pop_up_p)
997 Widget widget = instance->widget;
998 if (widget)
1000 if (XtIsManaged (widget)
1001 #ifdef USE_MOTIF
1002 /* What a complete load of crap!!!!
1003 When a dialogShell is on the screen, it is not managed!
1005 || (lw_motif_widget_p (instance->widget) &&
1006 XtIsManaged (first_child (widget)))
1007 #endif
1010 if (!result)
1011 result = widget;
1012 XMapRaised (XtDisplay (widget), XtWindow (widget));
1016 return result;
1019 static void
1020 lw_pop_all_widgets (LWLIB_ID id, Boolean up)
1022 widget_info* info = get_widget_info (id, False);
1023 widget_instance* instance;
1025 if (info)
1026 for (instance = info->instances; instance; instance = instance->next)
1027 if (instance->pop_up_p && instance->widget)
1029 #if defined (USE_LUCID)
1030 if (lw_lucid_widget_p (instance->widget))
1032 XtRealizeWidget (instance->widget);
1033 xlw_pop_instance (instance, up);
1035 #endif
1036 #if defined (USE_MOTIF)
1037 if (lw_motif_widget_p (instance->widget))
1039 XtRealizeWidget (instance->widget);
1040 xm_pop_instance (instance, up);
1042 #endif
1043 #if defined (USE_XAW)
1044 if (lw_xaw_widget_p (instance->widget))
1046 XtRealizeWidget (XtParent (instance->widget));
1047 XtRealizeWidget (instance->widget);
1048 xaw_pop_instance (instance, up);
1050 #endif
1054 void
1055 lw_pop_up_all_widgets (LWLIB_ID id)
1057 lw_pop_all_widgets (id, True);
1060 void
1061 lw_pop_down_all_widgets (LWLIB_ID id)
1063 lw_pop_all_widgets (id, False);
1066 void
1067 lw_popup_menu (Widget widget, XEvent *event)
1069 #if defined (USE_LUCID)
1070 if (lw_lucid_widget_p (widget))
1071 xlw_popup_menu (widget, event);
1072 #endif
1073 #if defined (USE_MOTIF)
1074 if (lw_motif_widget_p (widget))
1075 xm_popup_menu (widget, event);
1076 #endif
1077 #if defined (USE_XAW)
1078 if (lw_xaw_widget_p (widget))
1079 xaw_popup_menu (widget, event);
1080 #endif
1083 \f/* get the values back */
1084 static Boolean
1085 get_one_value (widget_instance *instance, widget_value *val)
1087 Widget widget = name_to_widget (instance, val->name);
1089 if (widget)
1091 #if defined (USE_LUCID)
1092 if (lw_lucid_widget_p (instance->widget))
1093 xlw_update_one_value (instance, widget, val);
1094 #endif
1095 #if defined (USE_MOTIF)
1096 if (lw_motif_widget_p (instance->widget))
1097 xm_update_one_value (instance, widget, val);
1098 #endif
1099 #if defined (USE_XAW)
1100 if (lw_xaw_widget_p (instance->widget))
1101 xaw_update_one_value (instance, widget, val);
1102 #endif
1103 return True;
1105 else
1106 return False;
1109 Boolean
1110 lw_get_some_values (LWLIB_ID id, widget_value *val_out)
1112 widget_info* info = get_widget_info (id, False);
1113 widget_instance* instance;
1114 widget_value* val;
1115 Boolean result = False;
1117 if (!info)
1118 return False;
1120 instance = info->instances;
1121 if (!instance)
1122 return False;
1124 for (val = val_out; val; val = val->next)
1125 if (get_one_value (instance, val))
1126 result = True;
1128 return result;
1131 widget_value*
1132 lw_get_all_values (LWLIB_ID id)
1134 widget_info* info = get_widget_info (id, False);
1135 widget_value* val = info->val;
1136 if (lw_get_some_values (id, val))
1137 return val;
1138 else
1139 return NULL;
1142 /* internal function used by the library dependent implementation to get the
1143 widget_value for a given widget in an instance */
1144 widget_value*
1145 lw_get_widget_value_for_widget (widget_instance *instance, Widget w)
1147 char* name = XtName (w);
1148 widget_value* cur;
1149 for (cur = instance->info->val; cur; cur = cur->next)
1150 if (!strcmp (cur->name, name))
1151 return cur;
1152 return NULL;
1155 \f/* update other instances value when one thing changed */
1157 /* To forbid recursive calls */
1158 static Boolean lwlib_updating;
1160 /* This function can be used as a an XtCallback for the widgets that get
1161 modified to update other instances of the widgets. Closure should be the
1162 widget_instance. */
1163 void
1164 lw_internal_update_other_instances (Widget widget,
1165 XtPointer closure,
1166 XtPointer call_data)
1168 widget_instance* instance = (widget_instance*)closure;
1169 char* name = XtName (widget);
1170 widget_info* info;
1171 widget_instance* cur;
1172 widget_value* val;
1174 /* Avoid possibly infinite recursion. */
1175 if (lwlib_updating)
1176 return;
1178 /* protect against the widget being destroyed */
1179 if (XtWidgetBeingDestroyedP (widget))
1180 return;
1182 /* Return immediately if there are no other instances */
1183 info = instance->info;
1184 if (!info->instances->next)
1185 return;
1187 lwlib_updating = True;
1189 for (val = info->val; val && strcmp (val->name, name); val = val->next);
1191 if (val && get_one_value (instance, val))
1192 for (cur = info->instances; cur; cur = cur->next)
1193 if (cur != instance)
1194 set_one_value (cur, val, True);
1196 lwlib_updating = False;
1200 \f/* get the id */
1202 LWLIB_ID
1203 lw_get_widget_id (Widget w)
1205 widget_instance* instance = get_widget_instance (w, False);
1207 return instance ? instance->info->id : 0;
1210 \f/* set the keyboard focus */
1211 void
1212 lw_set_keyboard_focus (Widget parent, Widget w)
1214 #if defined (USE_MOTIF)
1215 xm_set_keyboard_focus (parent, w);
1216 #else
1217 XtSetKeyboardFocus (parent, w);
1218 #endif
1221 \f/* Show busy */
1222 static void
1223 show_one_widget_busy (Widget w, Boolean flag)
1225 Pixel foreground = 0;
1226 Pixel background = 1;
1227 Widget widget_to_invert = XtNameToWidget (w, "*sheet");
1228 if (!widget_to_invert)
1229 widget_to_invert = w;
1231 XtVaGetValues (widget_to_invert,
1232 XtNforeground, &foreground,
1233 XtNbackground, &background,
1234 NULL);
1235 XtVaSetValues (widget_to_invert,
1236 XtNforeground, background,
1237 XtNbackground, foreground,
1238 NULL);
1241 void
1242 lw_show_busy (Widget w, Boolean busy)
1244 widget_instance* instance = get_widget_instance (w, False);
1245 widget_info* info;
1246 widget_instance* next;
1248 if (instance)
1250 info = instance->info;
1251 if (info->busy != busy)
1253 for (next = info->instances; next; next = next->next)
1254 if (next->widget)
1255 show_one_widget_busy (next->widget, busy);
1256 info->busy = busy;
1261 /* This hack exists because Lucid/Athena need to execute the strange
1262 function below to support geometry management. */
1263 void
1264 lw_refigure_widget (Widget w, Boolean doit)
1266 #if defined (USE_XAW)
1267 XawPanedSetRefigureMode (w, doit);
1268 #endif
1269 #if defined (USE_MOTIF)
1270 if (doit)
1271 XtManageChild (w);
1272 else
1273 XtUnmanageChild (w);
1274 #endif
1277 /* Toolkit independent way of determining if an event window is in the
1278 menubar. */
1279 Boolean
1280 lw_window_is_in_menubar (Window win, Widget menubar_widget)
1282 return menubar_widget
1283 #if defined (USE_LUCID)
1284 && XtWindow (menubar_widget) == win;
1285 #endif
1286 #if defined (USE_MOTIF)
1287 && ((XtWindow (menubar_widget) == win)
1288 || (XtWindowToWidget (XtDisplay (menubar_widget), win)
1289 && (XtParent (XtWindowToWidget (XtDisplay (menubar_widget), win))
1290 == menubar_widget)));
1291 #endif
1294 /* Motif hack to set the main window areas. */
1295 void
1296 lw_set_main_areas (Widget parent, Widget menubar, Widget work_area)
1298 #if defined (USE_MOTIF)
1299 xm_set_main_areas (parent, menubar, work_area);
1300 #endif
1303 /* Manage resizing for Motif. This disables resizing when the menubar
1304 is about to be modified. */
1305 void
1306 lw_allow_resizing (Widget w, Boolean flag)
1308 #if defined (USE_MOTIF)
1309 xm_manage_resizing (w, flag);
1310 #endif
1314 /* Value is non-zero if LABEL is a menu separator. If it is, *TYPE is
1315 set to an appropriate enumerator of type enum menu_separator.
1316 MOTIF_P non-zero means map separator types not supported by Motif
1317 to similar ones that are supported. */
1320 lw_separator_p (const char *label, enum menu_separator *type, int motif_p)
1322 int separator_p = 0;
1324 if (strlen (label) >= 3
1325 && memcmp (label, "--:", 3) == 0)
1327 static struct separator_table
1329 const char *name;
1330 enum menu_separator type;
1332 separator_names[] =
1334 {"space", SEPARATOR_NO_LINE},
1335 {"noLine", SEPARATOR_NO_LINE},
1336 {"singleLine", SEPARATOR_SINGLE_LINE},
1337 {"doubleLine", SEPARATOR_DOUBLE_LINE},
1338 {"singleDashedLine", SEPARATOR_SINGLE_DASHED_LINE},
1339 {"doubleDashedLine", SEPARATOR_DOUBLE_DASHED_LINE},
1340 {"shadowEtchedIn", SEPARATOR_SHADOW_ETCHED_IN},
1341 {"shadowEtchedOut", SEPARATOR_SHADOW_ETCHED_OUT},
1342 {"shadowEtchedInDash", SEPARATOR_SHADOW_ETCHED_IN_DASH},
1343 {"shadowEtchedOutDash", SEPARATOR_SHADOW_ETCHED_OUT_DASH},
1344 {"shadowDoubleEtchedIn", SEPARATOR_SHADOW_DOUBLE_ETCHED_IN},
1345 {"shadowDoubleEtchedOut", SEPARATOR_SHADOW_DOUBLE_ETCHED_OUT},
1346 {"shadowDoubleEtchedInDash", SEPARATOR_SHADOW_DOUBLE_ETCHED_IN_DASH},
1347 {"shadowDoubleEtchedOutDash", SEPARATOR_SHADOW_DOUBLE_ETCHED_OUT_DASH},
1348 {0,0}
1351 int i;
1353 label += 3;
1354 for (i = 0; separator_names[i].name; ++i)
1355 if (strcmp (label, separator_names[i].name) == 0)
1357 separator_p = 1;
1358 *type = separator_names[i].type;
1360 /* If separator type is not supported under Motif,
1361 use a similar one. */
1362 if (motif_p && *type >= SEPARATOR_SHADOW_DOUBLE_ETCHED_IN)
1363 *type -= 4;
1364 break;
1367 else if (strlen (label) > 3
1368 && memcmp (label, "--", 2) == 0
1369 && label[2] != '-')
1371 /* Alternative, more Emacs-style names. */
1372 static struct separator_table
1374 const char *name;
1375 enum menu_separator type;
1377 separator_names[] =
1379 {"space", SEPARATOR_NO_LINE},
1380 {"no-line", SEPARATOR_NO_LINE},
1381 {"single-line", SEPARATOR_SINGLE_LINE},
1382 {"double-line", SEPARATOR_DOUBLE_LINE},
1383 {"single-dashed-line", SEPARATOR_SINGLE_DASHED_LINE},
1384 {"double-dashed-line", SEPARATOR_DOUBLE_DASHED_LINE},
1385 {"shadow-etched-in", SEPARATOR_SHADOW_ETCHED_IN},
1386 {"shadow-etched-out", SEPARATOR_SHADOW_ETCHED_OUT},
1387 {"shadow-etched-in-dash", SEPARATOR_SHADOW_ETCHED_IN_DASH},
1388 {"shadow-etched-out-dash", SEPARATOR_SHADOW_ETCHED_OUT_DASH},
1389 {"shadow-double-etched-in", SEPARATOR_SHADOW_DOUBLE_ETCHED_IN},
1390 {"shadow-double-etched-out", SEPARATOR_SHADOW_DOUBLE_ETCHED_OUT},
1391 {"shadow-double-etched-in-dash", SEPARATOR_SHADOW_DOUBLE_ETCHED_IN_DASH},
1392 {"shadow-double-etched-out-dash",SEPARATOR_SHADOW_DOUBLE_ETCHED_OUT_DASH},
1393 {0,0}
1396 int i;
1398 label += 2;
1399 for (i = 0; separator_names[i].name; ++i)
1400 if (strcmp (label, separator_names[i].name) == 0)
1402 separator_p = 1;
1403 *type = separator_names[i].type;
1405 /* If separator type is not supported under Motif,
1406 use a similar one. */
1407 if (motif_p && *type >= SEPARATOR_SHADOW_DOUBLE_ETCHED_IN)
1408 *type -= 4;
1409 break;
1412 else
1414 /* Old-style separator, maybe. It's a separator if it contains
1415 only dashes. */
1416 while (*label == '-')
1417 ++label;
1418 separator_p = *label == 0;
1419 *type = SEPARATOR_SHADOW_ETCHED_IN;
1422 return separator_p;
1425 /* arch-tag: 3d730f36-a441-4a71-9971-48ef3b5a4d9f
1426 (do not change this comment) */