Replaced the recent ChangeLogs for cus-test.el by a summary.
[emacs.git] / lwlib / lwlib.c
blob43900a9b132e861b44d2f43900c8398e9237fe77
1 /* A general interface to the widgets of different toolkits.
2 Copyright (C) 1992, 1993 Lucid, Inc.
4 This file is part of the Lucid Widget Library.
6 The Lucid Widget Library is free software; you can redistribute it and/or
7 modify it under the terms of the GNU General Public License as published by
8 the Free Software Foundation; either version 2, or (at your option)
9 any later version.
11 The Lucid Widget Library is distributed in the hope that it will be useful,
12 but WITHOUT ANY WARRANTY; without even the implied warranty of
13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 GNU General Public License for more details.
16 You should have received a copy of the GNU General Public License
17 along with GNU Emacs; see the file COPYING. If not, write to
18 the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
19 Boston, MA 02111-1307, USA. */
21 #ifdef NeXT
22 #undef __STRICT_BSD__ /* ick */
23 #endif
25 #ifdef HAVE_CONFIG_H
26 #include <config.h>
27 #endif
29 #include "../src/lisp.h"
31 #include <sys/types.h>
32 #include <stdio.h>
33 #include <ctype.h>
34 #include "lwlib-int.h"
35 #include "lwlib-utils.h"
36 #include <X11/StringDefs.h>
38 #if defined (USE_LUCID)
39 #include "lwlib-Xlw.h"
40 #endif
41 #if defined (USE_MOTIF)
42 #include "lwlib-Xm.h"
43 #else /* not USE_MOTIF */
44 #if defined (USE_LUCID)
45 #define USE_XAW
46 #endif /* not USE_MOTIF && USE_LUCID */
47 #endif
48 #if defined (USE_OLIT)
49 #include "lwlib-Xol.h"
50 #endif
51 #if defined (USE_XAW)
52 #include <X11/Xaw/Paned.h>
53 #include "lwlib-Xaw.h"
54 #endif
56 #if !defined (USE_LUCID) && !defined (USE_MOTIF) && !defined (USE_OLIT)
57 ERROR! At least one of USE_LUCID, USE_MOTIF or USE_OLIT must be defined.
58 #endif
60 #if defined (USE_MOTIF) && defined (USE_OLIT)
61 ERROR! no more than one of USE_MOTIF and USE_OLIT may be defined.
62 #endif
64 #ifndef max
65 #define max(x, y) ((x) > (y) ? (x) : (y))
66 #endif
68 /* List of all widgets managed by the library. */
69 static widget_info*
70 all_widget_info = NULL;
72 #ifdef USE_MOTIF
73 char *lwlib_toolkit_type = "motif";
74 #else
75 char *lwlib_toolkit_type = "lucid";
76 #endif
78 static widget_value *merge_widget_value P_ ((widget_value *,
79 widget_value *,
80 int, int *));
81 static void instantiate_widget_instance P_ ((widget_instance *));
82 static int my_strcasecmp P_ ((char *, char *));
83 static void safe_free_str P_ ((char *));
84 static void free_widget_value_tree P_ ((widget_value *));
85 static widget_value *copy_widget_value_tree P_ ((widget_value *,
86 change_type));
87 static widget_info *allocate_widget_info P_ ((char *, char *, LWLIB_ID,
88 widget_value *,
89 lw_callback, lw_callback,
90 lw_callback, lw_callback));
91 static void free_widget_info P_ ((widget_info *));
92 static void mark_widget_destroyed P_ ((Widget, XtPointer, XtPointer));
93 static widget_instance *allocate_widget_instance P_ ((widget_info *,
94 Widget, Boolean));
95 static void free_widget_instance P_ ((widget_instance *));
96 static widget_info *get_widget_info P_ ((LWLIB_ID, Boolean));
97 static widget_instance *get_widget_instance P_ ((Widget, Boolean));
98 static widget_instance *find_instance P_ ((LWLIB_ID, Widget, Boolean));
99 static Boolean safe_strcmp P_ ((char *, char *));
100 static Widget name_to_widget P_ ((widget_instance *, char *));
101 static void set_one_value P_ ((widget_instance *, widget_value *, Boolean));
102 static void update_one_widget_instance P_ ((widget_instance *, Boolean));
103 static void update_all_widget_values P_ ((widget_info *, Boolean));
104 static void initialize_widget_instance P_ ((widget_instance *));
105 static widget_creation_function find_in_table P_ ((char *, widget_creation_entry *));
106 static Boolean dialog_spec_p P_ ((char *));
107 static void destroy_one_instance P_ ((widget_instance *));
108 static void lw_pop_all_widgets P_ ((LWLIB_ID, Boolean));
109 static Boolean get_one_value P_ ((widget_instance *, widget_value *));
110 static void show_one_widget_busy P_ ((Widget, Boolean));
112 void
113 lwlib_memset (address, value, length)
114 char *address;
115 int value;
116 int length;
118 int i;
120 for (i = 0; i < length; i++)
121 address[i] = value;
124 void
125 lwlib_bcopy (from, to, length)
126 char *from;
127 char *to;
128 int length;
130 int i;
132 for (i = 0; i < length; i++)
133 to[i] = from[i];
135 \f/* utility functions for widget_instance and widget_info */
136 char *
137 safe_strdup (s)
138 const char *s;
140 char *result;
141 if (! s) return 0;
142 result = (char *) malloc (strlen (s) + 1);
143 if (! result)
144 return 0;
145 strcpy (result, s);
146 return result;
149 /* Like strcmp but ignore differences in case. */
151 static int
152 my_strcasecmp (s1, s2)
153 char *s1, *s2;
155 while (1)
157 int c1 = *s1++;
158 int c2 = *s2++;
159 if (isupper (c1))
160 c1 = tolower (c1);
161 if (isupper (c2))
162 c2 = tolower (c2);
163 if (c1 != c2)
164 return (c1 > c2 ? 1 : -1);
165 if (c1 == 0)
166 return 0;
170 static void
171 safe_free_str (s)
172 char *s;
174 if (s) free (s);
177 static widget_value *widget_value_free_list = 0;
178 static int malloc_cpt = 0;
180 widget_value *
181 malloc_widget_value ()
183 widget_value *wv;
184 if (widget_value_free_list)
186 wv = widget_value_free_list;
187 widget_value_free_list = wv->free_list;
188 wv->free_list = 0;
190 else
192 wv = (widget_value *) malloc (sizeof (widget_value));
193 malloc_cpt++;
195 lwlib_memset (wv, 0, sizeof (widget_value));
196 return wv;
199 /* this is analogous to free(). It frees only what was allocated
200 by malloc_widget_value(), and no substructures.
202 void
203 free_widget_value (wv)
204 widget_value *wv;
206 if (wv->free_list)
207 abort ();
209 if (malloc_cpt > 25)
211 /* When the number of already allocated cells is too big,
212 We free it. */
213 free (wv);
214 malloc_cpt--;
216 else
218 wv->free_list = widget_value_free_list;
219 widget_value_free_list = wv;
223 static void
224 free_widget_value_tree (wv)
225 widget_value *wv;
227 if (!wv)
228 return;
230 if (wv->name) free (wv->name);
231 if (wv->value) free (wv->value);
232 if (wv->key) free (wv->key);
234 wv->name = wv->value = wv->key = (char *) 0xDEADBEEF;
236 if (wv->toolkit_data && wv->free_toolkit_data)
238 XtFree (wv->toolkit_data);
239 wv->toolkit_data = (void *) 0xDEADBEEF;
242 if (wv->contents && (wv->contents != (widget_value*)1))
244 free_widget_value_tree (wv->contents);
245 wv->contents = (widget_value *) 0xDEADBEEF;
247 if (wv->next)
249 free_widget_value_tree (wv->next);
250 wv->next = (widget_value *) 0xDEADBEEF;
252 free_widget_value (wv);
255 static widget_value *
256 copy_widget_value_tree (val, change)
257 widget_value* val;
258 change_type change;
260 widget_value* copy;
262 if (!val)
263 return NULL;
264 if (val == (widget_value *) 1)
265 return val;
267 copy = malloc_widget_value ();
268 copy->name = safe_strdup (val->name);
269 copy->value = safe_strdup (val->value);
270 copy->key = safe_strdup (val->key);
271 copy->help = val->help;
272 copy->enabled = val->enabled;
273 copy->button_type = val->button_type;
274 copy->selected = val->selected;
275 copy->edited = False;
276 copy->change = change;
277 copy->this_one_change = change;
278 copy->contents = copy_widget_value_tree (val->contents, change);
279 copy->call_data = val->call_data;
280 copy->next = copy_widget_value_tree (val->next, change);
281 copy->toolkit_data = NULL;
282 copy->free_toolkit_data = False;
283 return copy;
286 static widget_info *
287 allocate_widget_info (type, name, id, val, pre_activate_cb,
288 selection_cb, post_activate_cb, highlight_cb)
289 char* type;
290 char* name;
291 LWLIB_ID id;
292 widget_value* val;
293 lw_callback pre_activate_cb;
294 lw_callback selection_cb;
295 lw_callback post_activate_cb;
296 lw_callback highlight_cb;
298 widget_info* info = (widget_info*)malloc (sizeof (widget_info));
299 info->type = safe_strdup (type);
300 info->name = safe_strdup (name);
301 info->id = id;
302 info->val = copy_widget_value_tree (val, STRUCTURAL_CHANGE);
303 info->busy = False;
304 info->pre_activate_cb = pre_activate_cb;
305 info->selection_cb = selection_cb;
306 info->post_activate_cb = post_activate_cb;
307 info->highlight_cb = highlight_cb;
308 info->instances = NULL;
310 info->next = all_widget_info;
311 all_widget_info = info;
313 return info;
316 static void
317 free_widget_info (info)
318 widget_info* info;
320 safe_free_str (info->type);
321 safe_free_str (info->name);
322 free_widget_value_tree (info->val);
323 lwlib_memset ((void*)info, 0xDEADBEEF, sizeof (widget_info));
324 free (info);
327 static void
328 mark_widget_destroyed (widget, closure, call_data)
329 Widget widget;
330 XtPointer closure;
331 XtPointer call_data;
333 widget_instance* instance = (widget_instance*)closure;
335 /* be very conservative */
336 if (instance->widget == widget)
337 instance->widget = NULL;
340 static widget_instance *
341 allocate_widget_instance (info, parent, pop_up_p)
342 widget_info* info;
343 Widget parent;
344 Boolean pop_up_p;
346 widget_instance* instance =
347 (widget_instance*)malloc (sizeof (widget_instance));
348 bzero (instance, sizeof *instance);
349 instance->parent = parent;
350 instance->pop_up_p = pop_up_p;
351 instance->info = info;
352 instance->next = info->instances;
353 info->instances = instance;
355 instantiate_widget_instance (instance);
357 XtAddCallback (instance->widget, XtNdestroyCallback,
358 mark_widget_destroyed, (XtPointer)instance);
359 return instance;
362 static void
363 free_widget_instance (instance)
364 widget_instance* instance;
366 lwlib_memset ((void*)instance, 0xDEADBEEF, sizeof (widget_instance));
367 free (instance);
370 static widget_info *
371 get_widget_info (id, remove_p)
372 LWLIB_ID id;
373 Boolean remove_p;
375 widget_info* info;
376 widget_info* prev;
377 for (prev = NULL, info = all_widget_info;
378 info;
379 prev = info, info = info->next)
380 if (info->id == id)
382 if (remove_p)
384 if (prev)
385 prev->next = info->next;
386 else
387 all_widget_info = info->next;
389 return info;
391 return NULL;
394 /* Internal function used by the library dependent implementation to get the
395 widget_value for a given widget in an instance */
396 widget_info *
397 lw_get_widget_info (id)
398 LWLIB_ID id;
400 return get_widget_info (id, 0);
403 static widget_instance *
404 get_widget_instance (widget, remove_p)
405 Widget widget;
406 Boolean remove_p;
408 widget_info* info;
409 widget_instance* instance;
410 widget_instance* prev;
411 for (info = all_widget_info; info; info = info->next)
412 for (prev = NULL, instance = info->instances;
413 instance;
414 prev = instance, instance = instance->next)
415 if (instance->widget == widget)
417 if (remove_p)
419 if (prev)
420 prev->next = instance->next;
421 else
422 info->instances = instance->next;
424 return instance;
426 return (widget_instance *) 0;
429 /* Value is a pointer to the widget_instance corresponding to
430 WIDGET, or null if WIDGET is not a lwlib widget. */
432 widget_instance *
433 lw_get_widget_instance (widget)
434 Widget widget;
436 return get_widget_instance (widget, False);
439 static widget_instance*
440 find_instance (id, parent, pop_up_p)
441 LWLIB_ID id;
442 Widget parent;
443 Boolean pop_up_p;
445 widget_info* info = get_widget_info (id, False);
446 widget_instance* instance;
448 if (info)
449 for (instance = info->instances; instance; instance = instance->next)
450 if (instance->parent == parent && instance->pop_up_p == pop_up_p)
451 return instance;
453 return NULL;
457 /* utility function for widget_value */
458 static Boolean
459 safe_strcmp (s1, s2)
460 char* s1;
461 char* s2;
463 if (!!s1 ^ !!s2) return True;
464 return (s1 && s2) ? strcmp (s1, s2) : s1 ? False : !!s2;
468 #if 0
469 # define EXPLAIN(name, oc, nc, desc, a1, a2) \
470 printf ("Change: \"%s\"\tmax(%s=%d,%s=%d)\t%s %d %d\n", \
471 name, \
472 (oc == NO_CHANGE ? "none" : \
473 (oc == INVISIBLE_CHANGE ? "invisible" : \
474 (oc == VISIBLE_CHANGE ? "visible" : \
475 (oc == STRUCTURAL_CHANGE ? "structural" : "???")))), \
476 oc, \
477 (nc == NO_CHANGE ? "none" : \
478 (nc == INVISIBLE_CHANGE ? "invisible" : \
479 (nc == VISIBLE_CHANGE ? "visible" : \
480 (nc == STRUCTURAL_CHANGE ? "structural" : "???")))), \
481 nc, desc, a1, a2)
482 #else
483 # define EXPLAIN(name, oc, nc, desc, a1, a2)
484 #endif
487 static widget_value *
488 merge_widget_value (val1, val2, level, change_p)
489 widget_value* val1;
490 widget_value* val2;
491 int level;
492 int *change_p;
494 change_type change, this_one_change;
495 widget_value* merged_next;
496 widget_value* merged_contents;
498 if (!val1)
500 if (val2)
502 *change_p = 1;
503 return copy_widget_value_tree (val2, STRUCTURAL_CHANGE);
505 else
506 return NULL;
508 if (!val2)
510 *change_p = 1;
511 free_widget_value_tree (val1);
512 return NULL;
515 change = NO_CHANGE;
517 if (safe_strcmp (val1->name, val2->name))
519 EXPLAIN (val1->name, change, STRUCTURAL_CHANGE, "name change",
520 val1->name, val2->name);
521 change = max (change, STRUCTURAL_CHANGE);
522 safe_free_str (val1->name);
523 val1->name = safe_strdup (val2->name);
525 if (safe_strcmp (val1->value, val2->value))
527 EXPLAIN (val1->name, change, VISIBLE_CHANGE, "value change",
528 val1->value, val2->value);
529 change = max (change, VISIBLE_CHANGE);
530 safe_free_str (val1->value);
531 val1->value = safe_strdup (val2->value);
533 if (safe_strcmp (val1->key, val2->key))
535 EXPLAIN (val1->name, change, VISIBLE_CHANGE, "key change",
536 val1->key, val2->key);
537 change = max (change, VISIBLE_CHANGE);
538 safe_free_str (val1->key);
539 val1->key = safe_strdup (val2->key);
541 if (! EQ (val1->help, val2->help))
543 EXPLAIN (val1->name, change, VISIBLE_CHANGE, "help change",
544 val1->help, val2->help);
545 change = max (change, VISIBLE_CHANGE);
546 val1->help = val2->help;
548 if (val1->enabled != val2->enabled)
550 EXPLAIN (val1->name, change, VISIBLE_CHANGE, "enablement change",
551 val1->enabled, val2->enabled);
552 change = max (change, VISIBLE_CHANGE);
553 val1->enabled = val2->enabled;
555 if (val1->button_type != val2->button_type)
557 EXPLAIN (val1->name, change, VISIBLE_CHANGE, "button type change",
558 val1->button_type, val2->button_type);
559 change = max (change, VISIBLE_CHANGE);
560 val1->button_type = val2->button_type;
562 if (val1->selected != val2->selected)
564 EXPLAIN (val1->name, change, VISIBLE_CHANGE, "selection change",
565 val1->selected, val2->selected);
566 change = max (change, VISIBLE_CHANGE);
567 val1->selected = val2->selected;
569 if (val1->call_data != val2->call_data)
571 EXPLAIN (val1->name, change, INVISIBLE_CHANGE, "call-data change",
572 val1->call_data, val2->call_data);
573 change = max (change, INVISIBLE_CHANGE);
574 val1->call_data = val2->call_data;
577 if (level > 0)
579 merged_contents =
580 merge_widget_value (val1->contents, val2->contents, level - 1,
581 change_p);
583 if (val1->contents && !merged_contents)
585 /* This used to say INVISIBLE_CHANGE,
586 but it is visible and vitally important when
587 the contents of the menu bar itself are entirely deleted.
589 But maybe it doesn't matter. This fails to fix the bug. */
590 EXPLAIN (val1->name, change, STRUCTURAL_CHANGE, "(contents gone)",
591 0, 0);
592 change = max (change, STRUCTURAL_CHANGE);
594 else if (merged_contents && merged_contents->change != NO_CHANGE)
596 EXPLAIN (val1->name, change, INVISIBLE_CHANGE, "(contents change)",
597 0, 0);
598 change = max (change, INVISIBLE_CHANGE);
599 #if 0 /* This was replaced by the August 9 1996 change in lwlib-Xm.c. */
600 #ifdef USE_MOTIF
601 change = max (merged_contents->change, change);
602 #endif
603 #endif
606 val1->contents = merged_contents;
609 this_one_change = change;
611 merged_next = merge_widget_value (val1->next, val2->next, level, change_p);
613 if (val1->next && !merged_next)
615 EXPLAIN (val1->name, change, STRUCTURAL_CHANGE, "(following gone)",
616 0, 0);
617 change = max (change, STRUCTURAL_CHANGE);
619 else if (merged_next)
621 if (merged_next->change)
622 EXPLAIN (val1->name, change, merged_next->change, "(following change)",
623 0, 0);
624 change = max (change, merged_next->change);
627 val1->next = merged_next;
629 val1->this_one_change = this_one_change;
630 val1->change = change;
632 if (change > NO_CHANGE && val1->toolkit_data)
634 *change_p = 1;
635 if (val1->free_toolkit_data)
636 XtFree (val1->toolkit_data);
637 val1->toolkit_data = NULL;
640 return val1;
644 /* modifying the widgets */
645 static Widget
646 name_to_widget (instance, name)
647 widget_instance* instance;
648 char* name;
650 Widget widget = NULL;
652 if (!instance->widget)
653 return NULL;
655 if (!strcmp (XtName (instance->widget), name))
656 widget = instance->widget;
657 else
659 int length = strlen (name) + 2;
660 char* real_name = (char *) xmalloc (length);
661 real_name [0] = '*';
662 strcpy (real_name + 1, name);
664 widget = XtNameToWidget (instance->widget, real_name);
666 free (real_name);
668 return widget;
671 static void
672 set_one_value (instance, val, deep_p)
673 widget_instance* instance;
674 widget_value* val;
675 Boolean deep_p;
677 Widget widget = name_to_widget (instance, val->name);
679 if (widget)
681 #if defined (USE_LUCID)
682 if (lw_lucid_widget_p (instance->widget))
683 xlw_update_one_widget (instance, widget, val, deep_p);
684 #endif
685 #if defined (USE_MOTIF)
686 if (lw_motif_widget_p (instance->widget))
687 xm_update_one_widget (instance, widget, val, deep_p);
688 #endif
689 #if defined (USE_OLIT)
690 if (lw_olit_widget_p (instance->widget))
691 xol_update_one_widget (instance, widget, val, deep_p);
692 #endif
693 #if defined (USE_XAW)
694 if (lw_xaw_widget_p (instance->widget))
695 xaw_update_one_widget (instance, widget, val, deep_p);
696 #endif
700 static void
701 update_one_widget_instance (instance, deep_p)
702 widget_instance* instance;
703 Boolean deep_p;
705 widget_value *val;
707 if (!instance->widget)
708 /* the widget was destroyed */
709 return;
711 for (val = instance->info->val; val; val = val->next)
712 if (val->change != NO_CHANGE)
713 set_one_value (instance, val, deep_p);
716 static void
717 update_all_widget_values (info, deep_p)
718 widget_info* info;
719 Boolean deep_p;
721 widget_instance* instance;
722 widget_value* val;
724 for (instance = info->instances; instance; instance = instance->next)
725 update_one_widget_instance (instance, deep_p);
727 for (val = info->val; val; val = val->next)
728 val->change = NO_CHANGE;
732 lw_modify_all_widgets (id, val, deep_p)
733 LWLIB_ID id;
734 widget_value* val;
735 Boolean deep_p;
737 widget_info* info = get_widget_info (id, False);
738 widget_value* new_val;
739 widget_value* next_new_val;
740 widget_value* cur;
741 widget_value* prev;
742 widget_value* next;
743 int found;
744 int change_p = 0;
746 if (!info)
747 return 0;
749 for (new_val = val; new_val; new_val = new_val->next)
751 next_new_val = new_val->next;
752 new_val->next = NULL;
753 found = False;
754 for (prev = NULL, cur = info->val; cur; prev = cur, cur = cur->next)
755 if (!strcmp (cur->name, new_val->name))
757 found = True;
758 next = cur->next;
759 cur->next = NULL;
760 cur = merge_widget_value (cur, new_val, deep_p ? 1000 : 1,
761 &change_p);
762 if (prev)
763 prev->next = cur ? cur : next;
764 else
765 info->val = cur ? cur : next;
766 if (cur)
767 cur->next = next;
768 break;
770 if (!found)
772 /* Could not find it, add it */
773 if (prev)
774 prev->next = copy_widget_value_tree (new_val, STRUCTURAL_CHANGE);
775 else
776 info->val = copy_widget_value_tree (new_val, STRUCTURAL_CHANGE);
777 change_p = 1;
779 new_val->next = next_new_val;
782 update_all_widget_values (info, deep_p);
783 return change_p;
787 /* creating the widgets */
789 static void
790 initialize_widget_instance (instance)
791 widget_instance* instance;
793 widget_value* val;
795 for (val = instance->info->val; val; val = val->next)
796 val->change = STRUCTURAL_CHANGE;
798 update_one_widget_instance (instance, True);
800 for (val = instance->info->val; val; val = val->next)
801 val->change = NO_CHANGE;
805 static widget_creation_function
806 find_in_table (type, table)
807 char* type;
808 widget_creation_entry* table;
810 widget_creation_entry* cur;
811 for (cur = table; cur->type; cur++)
812 if (!my_strcasecmp (type, cur->type))
813 return cur->function;
814 return NULL;
817 static Boolean
818 dialog_spec_p (name)
819 char* name;
821 /* return True if name matches [EILPQeilpq][1-9][Bb] or
822 [EILPQeilpq][1-9][Bb][Rr][1-9] */
823 if (!name)
824 return False;
826 switch (name [0])
828 case 'E': case 'I': case 'L': case 'P': case 'Q':
829 case 'e': case 'i': case 'l': case 'p': case 'q':
830 if (name [1] >= '0' && name [1] <= '9')
832 if (name [2] != 'B' && name [2] != 'b')
833 return False;
834 if (!name [3])
835 return True;
836 if ((name [3] == 'T' || name [3] == 't') && !name [4])
837 return True;
838 if ((name [3] == 'R' || name [3] == 'r')
839 && name [4] >= '0' && name [4] <= '9' && !name [5])
840 return True;
841 return False;
843 else
844 return False;
846 default:
847 return False;
851 static void
852 instantiate_widget_instance (instance)
853 widget_instance* instance;
855 widget_creation_function function = NULL;
857 #if defined (USE_LUCID)
858 if (!function)
859 function = find_in_table (instance->info->type, xlw_creation_table);
860 #endif
861 #if defined(USE_MOTIF)
862 if (!function)
863 function = find_in_table (instance->info->type, xm_creation_table);
864 #endif
865 #if defined (USE_OLIT)
866 if (!function)
867 function = find_in_table (instance->info->type, xol_creation_table);
868 #endif
869 #if defined (USE_XAW)
870 if (!function)
871 function = find_in_table (instance->info->type, xaw_creation_table);
872 #endif
874 if (!function)
876 if (dialog_spec_p (instance->info->type))
878 #if defined (USE_LUCID)
879 /* not yet */
880 #endif
881 #if defined(USE_MOTIF)
882 if (!function)
883 function = xm_create_dialog;
884 #endif
885 #if defined (USE_XAW)
886 if (!function)
887 function = xaw_create_dialog;
888 #endif
889 #if defined (USE_OLIT)
890 /* not yet */
891 #endif
895 if (!function)
897 printf ("No creation function for widget type %s\n",
898 instance->info->type);
899 abort ();
902 instance->widget = (*function) (instance);
904 if (!instance->widget)
905 abort ();
907 /* XtRealizeWidget (instance->widget);*/
910 void
911 lw_register_widget (type, name, id, val, pre_activate_cb,
912 selection_cb, post_activate_cb, highlight_cb)
913 char* type;
914 char* name;
915 LWLIB_ID id;
916 widget_value* val;
917 lw_callback pre_activate_cb;
918 lw_callback selection_cb;
919 lw_callback post_activate_cb;
920 lw_callback highlight_cb;
922 if (!get_widget_info (id, False))
923 allocate_widget_info (type, name, id, val, pre_activate_cb, selection_cb,
924 post_activate_cb, highlight_cb);
927 Widget
928 lw_get_widget (id, parent, pop_up_p)
929 LWLIB_ID id;
930 Widget parent;
931 Boolean pop_up_p;
933 widget_instance* instance;
935 instance = find_instance (id, parent, pop_up_p);
936 return instance ? instance->widget : NULL;
939 Widget
940 lw_make_widget (id, parent, pop_up_p)
941 LWLIB_ID id;
942 Widget parent;
943 Boolean pop_up_p;
945 widget_instance* instance;
946 widget_info* info;
948 instance = find_instance (id, parent, pop_up_p);
949 if (!instance)
951 info = get_widget_info (id, False);
952 if (!info)
953 return NULL;
954 instance = allocate_widget_instance (info, parent, pop_up_p);
955 initialize_widget_instance (instance);
957 if (!instance->widget)
958 abort ();
959 return instance->widget;
962 Widget
963 lw_create_widget (type, name, id, val, parent, pop_up_p, pre_activate_cb,
964 selection_cb, post_activate_cb, highlight_cb)
965 char* type;
966 char* name;
967 LWLIB_ID id;
968 widget_value* val;
969 Widget parent;
970 Boolean pop_up_p;
971 lw_callback pre_activate_cb;
972 lw_callback selection_cb;
973 lw_callback post_activate_cb;
974 lw_callback highlight_cb;
976 lw_register_widget (type, name, id, val, pre_activate_cb, selection_cb,
977 post_activate_cb, highlight_cb);
978 return lw_make_widget (id, parent, pop_up_p);
982 /* destroying the widgets */
983 static void
984 destroy_one_instance (instance)
985 widget_instance* instance;
987 /* Remove the destroy callback on the widget; that callback will try to
988 dereference the instance object (to set its widget slot to 0, since the
989 widget is dead.) Since the instance is now dead, we don't have to worry
990 about the fact that its widget is dead too.
992 This happens in the Phase2Destroy of the widget, so this callback would
993 not have been run until arbitrarily long after the instance was freed.
995 if (instance->widget)
996 XtRemoveCallback (instance->widget, XtNdestroyCallback,
997 mark_widget_destroyed, (XtPointer)instance);
999 if (instance->widget)
1001 /* The else are pretty tricky here, including the empty statement
1002 at the end because it would be very bad to destroy a widget
1003 twice. */
1004 #if defined (USE_LUCID)
1005 if (lw_lucid_widget_p (instance->widget))
1006 xlw_destroy_instance (instance);
1007 else
1008 #endif
1009 #if defined (USE_MOTIF)
1010 if (lw_motif_widget_p (instance->widget))
1011 xm_destroy_instance (instance);
1012 else
1013 #endif
1014 #if defined (USE_OLIT)
1015 if (lw_olit_widget_p (instance->widget))
1016 xol_destroy_instance (instance);
1017 else
1018 #endif
1019 #if defined (USE_XAW)
1020 if (lw_xaw_widget_p (instance->widget))
1021 xaw_destroy_instance (instance);
1022 else
1023 #endif
1024 /* do not remove the empty statement */
1028 free_widget_instance (instance);
1031 void
1032 lw_destroy_widget (w)
1033 Widget w;
1035 widget_instance* instance = get_widget_instance (w, True);
1037 if (instance)
1039 widget_info *info = instance->info;
1040 /* instance has already been removed from the list; free it */
1041 destroy_one_instance (instance);
1042 /* if there are no instances left, free the info too */
1043 if (!info->instances)
1044 lw_destroy_all_widgets (info->id);
1048 void
1049 lw_destroy_all_widgets (id)
1050 LWLIB_ID id;
1052 widget_info* info = get_widget_info (id, True);
1053 widget_instance* instance;
1054 widget_instance* next;
1056 if (info)
1058 for (instance = info->instances; instance; )
1060 next = instance->next;
1061 destroy_one_instance (instance);
1062 instance = next;
1064 free_widget_info (info);
1068 void
1069 lw_destroy_everything ()
1071 while (all_widget_info)
1072 lw_destroy_all_widgets (all_widget_info->id);
1075 void
1076 lw_destroy_all_pop_ups ()
1078 widget_info* info;
1079 widget_info* next;
1080 widget_instance* instance;
1082 for (info = all_widget_info; info; info = next)
1084 next = info->next;
1085 instance = info->instances;
1086 if (instance && instance->pop_up_p)
1087 lw_destroy_all_widgets (info->id);
1091 #ifdef USE_MOTIF
1092 extern Widget first_child (/* Widget */); /* garbage */
1093 #endif
1095 Widget
1096 lw_raise_all_pop_up_widgets ()
1098 widget_info* info;
1099 widget_instance* instance;
1100 Widget result = NULL;
1102 for (info = all_widget_info; info; info = info->next)
1103 for (instance = info->instances; instance; instance = instance->next)
1104 if (instance->pop_up_p)
1106 Widget widget = instance->widget;
1107 if (widget)
1109 if (XtIsManaged (widget)
1110 #ifdef USE_MOTIF
1111 /* What a complete load of crap!!!!
1112 When a dialogShell is on the screen, it is not managed!
1114 || (lw_motif_widget_p (instance->widget) &&
1115 XtIsManaged (first_child (widget)))
1116 #endif
1119 if (!result)
1120 result = widget;
1121 XMapRaised (XtDisplay (widget), XtWindow (widget));
1125 return result;
1128 static void
1129 lw_pop_all_widgets (id, up)
1130 LWLIB_ID id;
1131 Boolean up;
1133 widget_info* info = get_widget_info (id, False);
1134 widget_instance* instance;
1136 if (info)
1137 for (instance = info->instances; instance; instance = instance->next)
1138 if (instance->pop_up_p && instance->widget)
1140 #if defined (USE_LUCID)
1141 if (lw_lucid_widget_p (instance->widget))
1143 XtRealizeWidget (instance->widget);
1144 xlw_pop_instance (instance, up);
1146 #endif
1147 #if defined (USE_MOTIF)
1148 if (lw_motif_widget_p (instance->widget))
1150 XtRealizeWidget (instance->widget);
1151 xm_pop_instance (instance, up);
1153 #endif
1154 #if defined (USE_OLIT)
1155 if (lw_olit_widget_p (instance->widget))
1157 XtRealizeWidget (instance->widget);
1158 xol_pop_instance (instance, up);
1160 #endif
1161 #if defined (USE_XAW)
1162 if (lw_xaw_widget_p (instance->widget))
1164 XtRealizeWidget (XtParent (instance->widget));
1165 XtRealizeWidget (instance->widget);
1166 xaw_pop_instance (instance, up);
1168 #endif
1172 void
1173 lw_pop_up_all_widgets (id)
1174 LWLIB_ID id;
1176 lw_pop_all_widgets (id, True);
1179 void
1180 lw_pop_down_all_widgets (id)
1181 LWLIB_ID id;
1183 lw_pop_all_widgets (id, False);
1186 void
1187 lw_popup_menu (widget, event)
1188 Widget widget;
1189 XEvent *event;
1191 #if defined (USE_LUCID)
1192 if (lw_lucid_widget_p (widget))
1193 xlw_popup_menu (widget, event);
1194 #endif
1195 #if defined (USE_MOTIF)
1196 if (lw_motif_widget_p (widget))
1197 xm_popup_menu (widget, event);
1198 #endif
1199 #if defined (USE_OLIT)
1200 if (lw_olit_widget_p (widget))
1201 xol_popup_menu (widget, event);
1202 #endif
1203 #if defined (USE_XAW)
1204 if (lw_xaw_widget_p (widget))
1205 xaw_popup_menu (widget, event);
1206 #endif
1209 \f/* get the values back */
1210 static Boolean
1211 get_one_value (instance, val)
1212 widget_instance* instance;
1213 widget_value* val;
1215 Widget widget = name_to_widget (instance, val->name);
1217 if (widget)
1219 #if defined (USE_LUCID)
1220 if (lw_lucid_widget_p (instance->widget))
1221 xlw_update_one_value (instance, widget, val);
1222 #endif
1223 #if defined (USE_MOTIF)
1224 if (lw_motif_widget_p (instance->widget))
1225 xm_update_one_value (instance, widget, val);
1226 #endif
1227 #if defined (USE_OLIT)
1228 if (lw_olit_widget_p (instance->widget))
1229 xol_update_one_value (instance, widget, val);
1230 #endif
1231 #if defined (USE_XAW)
1232 if (lw_xaw_widget_p (instance->widget))
1233 xaw_update_one_value (instance, widget, val);
1234 #endif
1235 return True;
1237 else
1238 return False;
1241 Boolean
1242 lw_get_some_values (id, val_out)
1243 LWLIB_ID id;
1244 widget_value* val_out;
1246 widget_info* info = get_widget_info (id, False);
1247 widget_instance* instance;
1248 widget_value* val;
1249 Boolean result = False;
1251 if (!info)
1252 return False;
1254 instance = info->instances;
1255 if (!instance)
1256 return False;
1258 for (val = val_out; val; val = val->next)
1259 if (get_one_value (instance, val))
1260 result = True;
1262 return result;
1265 widget_value*
1266 lw_get_all_values (id)
1267 LWLIB_ID id;
1269 widget_info* info = get_widget_info (id, False);
1270 widget_value* val = info->val;
1271 if (lw_get_some_values (id, val))
1272 return val;
1273 else
1274 return NULL;
1277 /* internal function used by the library dependent implementation to get the
1278 widget_value for a given widget in an instance */
1279 widget_value*
1280 lw_get_widget_value_for_widget (instance, w)
1281 widget_instance* instance;
1282 Widget w;
1284 char* name = XtName (w);
1285 widget_value* cur;
1286 for (cur = instance->info->val; cur; cur = cur->next)
1287 if (!strcmp (cur->name, name))
1288 return cur;
1289 return NULL;
1292 \f/* update other instances value when one thing changed */
1294 /* To forbid recursive calls */
1295 static Boolean lwlib_updating;
1297 /* This function can be used as a an XtCallback for the widgets that get
1298 modified to update other instances of the widgets. Closure should be the
1299 widget_instance. */
1300 void
1301 lw_internal_update_other_instances (widget, closure, call_data)
1302 Widget widget;
1303 XtPointer closure;
1304 XtPointer call_data;
1306 widget_instance* instance = (widget_instance*)closure;
1307 char* name = XtName (widget);
1308 widget_info* info;
1309 widget_instance* cur;
1310 widget_value* val;
1312 /* Avoid possibly infinite recursion. */
1313 if (lwlib_updating)
1314 return;
1316 /* protect against the widget being destroyed */
1317 if (XtWidgetBeingDestroyedP (widget))
1318 return;
1320 /* Return immediately if there are no other instances */
1321 info = instance->info;
1322 if (!info->instances->next)
1323 return;
1325 lwlib_updating = True;
1327 for (val = info->val; val && strcmp (val->name, name); val = val->next);
1329 if (val && get_one_value (instance, val))
1330 for (cur = info->instances; cur; cur = cur->next)
1331 if (cur != instance)
1332 set_one_value (cur, val, True);
1334 lwlib_updating = False;
1338 \f/* get the id */
1340 LWLIB_ID
1341 lw_get_widget_id (w)
1342 Widget w;
1344 widget_instance* instance = get_widget_instance (w, False);
1346 return instance ? instance->info->id : 0;
1349 \f/* set the keyboard focus */
1350 void
1351 lw_set_keyboard_focus (parent, w)
1352 Widget parent;
1353 Widget w;
1355 #if defined (USE_MOTIF)
1356 xm_set_keyboard_focus (parent, w);
1357 #else
1358 XtSetKeyboardFocus (parent, w);
1359 #endif
1362 \f/* Show busy */
1363 static void
1364 show_one_widget_busy (w, flag)
1365 Widget w;
1366 Boolean flag;
1368 Pixel foreground = 0;
1369 Pixel background = 1;
1370 Widget widget_to_invert = XtNameToWidget (w, "*sheet");
1371 if (!widget_to_invert)
1372 widget_to_invert = w;
1374 XtVaGetValues (widget_to_invert,
1375 XtNforeground, &foreground,
1376 XtNbackground, &background,
1377 NULL);
1378 XtVaSetValues (widget_to_invert,
1379 XtNforeground, background,
1380 XtNbackground, foreground,
1381 NULL);
1384 void
1385 lw_show_busy (w, busy)
1386 Widget w;
1387 Boolean busy;
1389 widget_instance* instance = get_widget_instance (w, False);
1390 widget_info* info;
1391 widget_instance* next;
1393 if (instance)
1395 info = instance->info;
1396 if (info->busy != busy)
1398 for (next = info->instances; next; next = next->next)
1399 if (next->widget)
1400 show_one_widget_busy (next->widget, busy);
1401 info->busy = busy;
1406 /* This hack exists because Lucid/Athena need to execute the strange
1407 function below to support geometry management. */
1408 void
1409 lw_refigure_widget (w, doit)
1410 Widget w;
1411 Boolean doit;
1413 #if defined (USE_XAW)
1414 XawPanedSetRefigureMode (w, doit);
1415 #endif
1416 #if defined (USE_MOTIF)
1417 if (doit)
1418 XtManageChild (w);
1419 else
1420 XtUnmanageChild (w);
1421 #endif
1424 /* Toolkit independent way of determining if an event window is in the
1425 menubar. */
1426 Boolean
1427 lw_window_is_in_menubar (win, menubar_widget)
1428 Window win;
1429 Widget menubar_widget;
1431 return menubar_widget
1432 #if defined (USE_LUCID)
1433 && XtWindow (menubar_widget) == win;
1434 #endif
1435 #if defined (USE_MOTIF)
1436 && ((XtWindow (menubar_widget) == win)
1437 || (XtWindowToWidget (XtDisplay (menubar_widget), win)
1438 && (XtParent (XtWindowToWidget (XtDisplay (menubar_widget), win))
1439 == menubar_widget)));
1440 #endif
1443 /* Motif hack to set the main window areas. */
1444 void
1445 lw_set_main_areas (parent, menubar, work_area)
1446 Widget parent;
1447 Widget menubar;
1448 Widget work_area;
1450 #if defined (USE_MOTIF)
1451 xm_set_main_areas (parent, menubar, work_area);
1452 #endif
1455 /* Manage resizing for Motif. This disables resizing when the menubar
1456 is about to be modified. */
1457 void
1458 lw_allow_resizing (w, flag)
1459 Widget w;
1460 Boolean flag;
1462 #if defined (USE_MOTIF)
1463 xm_manage_resizing (w, flag);
1464 #endif
1468 /* Value is non-zero if LABEL is a menu separator. If it is, *TYPE is
1469 set to an appropriate enumerator of type enum menu_separator.
1470 MOTIF_P non-zero means map separator types not supported by Motif
1471 to similar ones that are supported. */
1474 lw_separator_p (label, type, motif_p)
1475 char *label;
1476 enum menu_separator *type;
1477 int motif_p;
1479 int separator_p = 0;
1481 if (strlen (label) >= 3
1482 && bcmp (label, "--:", 3) == 0)
1484 static struct separator_table
1486 char *name;
1487 enum menu_separator type;
1489 separator_names[] =
1491 {"space", SEPARATOR_NO_LINE},
1492 {"noLine", SEPARATOR_NO_LINE},
1493 {"singleLine", SEPARATOR_SINGLE_LINE},
1494 {"doubleLine", SEPARATOR_DOUBLE_LINE},
1495 {"singleDashedLine", SEPARATOR_SINGLE_DASHED_LINE},
1496 {"doubleDashedLine", SEPARATOR_DOUBLE_DASHED_LINE},
1497 {"shadowEtchedIn", SEPARATOR_SHADOW_ETCHED_IN},
1498 {"shadowEtchedOut", SEPARATOR_SHADOW_ETCHED_OUT},
1499 {"shadowEtchedInDash", SEPARATOR_SHADOW_ETCHED_IN_DASH},
1500 {"shadowEtchedOutDash", SEPARATOR_SHADOW_ETCHED_OUT_DASH},
1501 {"shadowDoubleEtchedIn", SEPARATOR_SHADOW_DOUBLE_ETCHED_IN},
1502 {"shadowDoubleEtchedOut", SEPARATOR_SHADOW_DOUBLE_ETCHED_OUT},
1503 {"shadowDoubleEtchedInDash", SEPARATOR_SHADOW_DOUBLE_ETCHED_IN_DASH},
1504 {"shadowDoubleEtchedOutDash", SEPARATOR_SHADOW_DOUBLE_ETCHED_OUT_DASH},
1505 {0,0}
1508 int i;
1510 label += 3;
1511 for (i = 0; separator_names[i].name; ++i)
1512 if (strcmp (label, separator_names[i].name) == 0)
1514 separator_p = 1;
1515 *type = separator_names[i].type;
1517 /* If separator type is not supported under Motif,
1518 use a similar one. */
1519 if (motif_p && *type >= SEPARATOR_SHADOW_DOUBLE_ETCHED_IN)
1520 *type -= 4;
1521 break;
1524 else if (strlen (label) > 3
1525 && bcmp (label, "--", 2) == 0
1526 && label[2] != '-')
1528 /* Alternative, more Emacs-style names. */
1529 static struct separator_table
1531 char *name;
1532 enum menu_separator type;
1534 separator_names[] =
1536 {"space", SEPARATOR_NO_LINE},
1537 {"no-line", SEPARATOR_NO_LINE},
1538 {"single-line", SEPARATOR_SINGLE_LINE},
1539 {"double-line", SEPARATOR_DOUBLE_LINE},
1540 {"single-dashed-line", SEPARATOR_SINGLE_DASHED_LINE},
1541 {"double-dashed-line", SEPARATOR_DOUBLE_DASHED_LINE},
1542 {"shadow-etched-in", SEPARATOR_SHADOW_ETCHED_IN},
1543 {"shadow-etched-out", SEPARATOR_SHADOW_ETCHED_OUT},
1544 {"shadow-etched-in-dash", SEPARATOR_SHADOW_ETCHED_IN_DASH},
1545 {"shadow-etched-out-dash", SEPARATOR_SHADOW_ETCHED_OUT_DASH},
1546 {"shadow-double-etched-in", SEPARATOR_SHADOW_DOUBLE_ETCHED_IN},
1547 {"shadow-double-etched-out", SEPARATOR_SHADOW_DOUBLE_ETCHED_OUT},
1548 {"shadow-double-etched-in-dash", SEPARATOR_SHADOW_DOUBLE_ETCHED_IN_DASH},
1549 {"shadow-double-etched-out-dash",SEPARATOR_SHADOW_DOUBLE_ETCHED_OUT_DASH},
1550 {0,0}
1553 int i;
1555 label += 2;
1556 for (i = 0; separator_names[i].name; ++i)
1557 if (strcmp (label, separator_names[i].name) == 0)
1559 separator_p = 1;
1560 *type = separator_names[i].type;
1562 /* If separator type is not supported under Motif,
1563 use a similar one. */
1564 if (motif_p && *type >= SEPARATOR_SHADOW_DOUBLE_ETCHED_IN)
1565 *type -= 4;
1566 break;
1569 else
1571 /* Old-style separator, maybe. It's a separator if it contains
1572 only dashes. */
1573 while (*label == '-')
1574 ++label;
1575 separator_p = *label == 0;
1576 *type = SEPARATOR_SHADOW_ETCHED_IN;
1579 return separator_p;