*** empty log message ***
[emacs.git] / lwlib / lwlib.c
blob94da7cfa0f3f5616ae9d863455829d7c1e01c102
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 <sys/types.h>
30 #include <stdio.h>
31 #include <ctype.h>
32 #include "lwlib-int.h"
33 #include "lwlib-utils.h"
34 #include <X11/StringDefs.h>
36 extern long *xmalloc();
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
77 \f/* Forward declarations */
78 static void
79 instantiate_widget_instance (/* widget_instance* instance */);
81 void
82 lwlib_memset (address, value, length)
83 char *address;
84 int value;
85 int length;
87 int i;
89 for (i = 0; i < length; i++)
90 address[i] = value;
93 void
94 lwlib_bcopy (from, to, length)
95 char *from;
96 char *to;
97 int length;
99 int i;
101 for (i = 0; i < length; i++)
102 to[i] = from[i];
104 \f/* utility functions for widget_instance and widget_info */
105 char *
106 safe_strdup (s)
107 char *s;
109 char *result;
110 if (! s) return 0;
111 result = (char *) malloc (strlen (s) + 1);
112 if (! result)
113 return 0;
114 strcpy (result, s);
115 return result;
118 /* Like strcmp but ignore differences in case. */
120 static int
121 my_strcasecmp (s1, s2)
122 char *s1, *s2;
124 while (1)
126 int c1 = *s1++;
127 int c2 = *s2++;
128 if (isupper (c1))
129 c1 = tolower (c1);
130 if (isupper (c2))
131 c2 = tolower (c2);
132 if (c1 != c2)
133 return (c1 > c2 ? 1 : -1);
134 if (c1 == 0)
135 return 0;
139 static void
140 safe_free_str (s)
141 char *s;
143 if (s) free (s);
146 static widget_value *widget_value_free_list = 0;
147 static int malloc_cpt = 0;
149 widget_value *
150 malloc_widget_value ()
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 lwlib_memset (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 (wv)
173 widget_value *wv;
175 if (wv->free_list)
176 abort ();
178 if (malloc_cpt > 25)
180 /* When the number of already allocated cells is too big,
181 We free it. */
182 free (wv);
183 malloc_cpt--;
185 else
187 wv->free_list = widget_value_free_list;
188 widget_value_free_list = wv;
192 static void
193 free_widget_value_tree (wv)
194 widget_value *wv;
196 if (!wv)
197 return;
199 if (wv->name) free (wv->name);
200 if (wv->value) free (wv->value);
201 if (wv->key) free (wv->key);
202 if (wv->help) free (wv->help);
204 wv->name = wv->value = wv->key = wv->help = (char *) 0xDEADBEEF;
206 if (wv->toolkit_data && wv->free_toolkit_data)
208 XtFree (wv->toolkit_data);
209 wv->toolkit_data = (void *) 0xDEADBEEF;
212 if (wv->contents && (wv->contents != (widget_value*)1))
214 free_widget_value_tree (wv->contents);
215 wv->contents = (widget_value *) 0xDEADBEEF;
217 if (wv->next)
219 free_widget_value_tree (wv->next);
220 wv->next = (widget_value *) 0xDEADBEEF;
222 free_widget_value (wv);
225 static widget_value *
226 copy_widget_value_tree (val, change)
227 widget_value* val;
228 change_type change;
230 widget_value* copy;
232 if (!val)
233 return NULL;
234 if (val == (widget_value *) 1)
235 return val;
237 copy = malloc_widget_value ();
238 copy->name = safe_strdup (val->name);
239 copy->value = safe_strdup (val->value);
240 copy->key = safe_strdup (val->key);
241 copy->help = safe_strdup (val->help);
242 copy->enabled = val->enabled;
243 copy->button_type = val->button_type;
244 copy->selected = val->selected;
245 copy->edited = False;
246 copy->change = change;
247 copy->this_one_change = change;
248 copy->contents = copy_widget_value_tree (val->contents, change);
249 copy->call_data = val->call_data;
250 copy->next = copy_widget_value_tree (val->next, change);
251 copy->toolkit_data = NULL;
252 copy->free_toolkit_data = False;
253 return copy;
256 static widget_info *
257 allocate_widget_info (type, name, id, val, pre_activate_cb,
258 selection_cb, post_activate_cb, highlight_cb)
259 char* type;
260 char* name;
261 LWLIB_ID id;
262 widget_value* val;
263 lw_callback pre_activate_cb;
264 lw_callback selection_cb;
265 lw_callback post_activate_cb;
266 lw_callback highlight_cb;
268 widget_info* info = (widget_info*)malloc (sizeof (widget_info));
269 info->type = safe_strdup (type);
270 info->name = safe_strdup (name);
271 info->id = id;
272 info->val = copy_widget_value_tree (val, STRUCTURAL_CHANGE);
273 info->busy = False;
274 info->pre_activate_cb = pre_activate_cb;
275 info->selection_cb = selection_cb;
276 info->post_activate_cb = post_activate_cb;
277 info->highlight_cb = highlight_cb;
278 info->instances = NULL;
280 info->next = all_widget_info;
281 all_widget_info = info;
283 return info;
286 static void
287 free_widget_info (info)
288 widget_info* info;
290 safe_free_str (info->type);
291 safe_free_str (info->name);
292 free_widget_value_tree (info->val);
293 lwlib_memset ((void*)info, 0xDEADBEEF, sizeof (widget_info));
294 free (info);
297 static void
298 mark_widget_destroyed (widget, closure, call_data)
299 Widget widget;
300 XtPointer closure;
301 XtPointer call_data;
303 widget_instance* instance = (widget_instance*)closure;
305 /* be very conservative */
306 if (instance->widget == widget)
307 instance->widget = NULL;
310 static widget_instance *
311 allocate_widget_instance (info, parent, pop_up_p)
312 widget_info* info;
313 Widget parent;
314 Boolean pop_up_p;
316 widget_instance* instance =
317 (widget_instance*)malloc (sizeof (widget_instance));
318 bzero (instance, sizeof *instance);
319 instance->parent = parent;
320 instance->pop_up_p = pop_up_p;
321 instance->info = info;
322 instance->next = info->instances;
323 info->instances = instance;
325 instantiate_widget_instance (instance);
327 XtAddCallback (instance->widget, XtNdestroyCallback,
328 mark_widget_destroyed, (XtPointer)instance);
329 return instance;
332 static void
333 free_widget_instance (instance)
334 widget_instance* instance;
336 lwlib_memset ((void*)instance, 0xDEADBEEF, sizeof (widget_instance));
337 free (instance);
340 static widget_info *
341 get_widget_info (id, remove_p)
342 LWLIB_ID id;
343 Boolean remove_p;
345 widget_info* info;
346 widget_info* prev;
347 for (prev = NULL, info = all_widget_info;
348 info;
349 prev = info, info = info->next)
350 if (info->id == id)
352 if (remove_p)
354 if (prev)
355 prev->next = info->next;
356 else
357 all_widget_info = info->next;
359 return info;
361 return NULL;
364 /* Internal function used by the library dependent implementation to get the
365 widget_value for a given widget in an instance */
366 widget_info *
367 lw_get_widget_info (id)
368 LWLIB_ID id;
370 return get_widget_info (id, 0);
373 static widget_instance *
374 get_widget_instance (widget, remove_p)
375 Widget widget;
376 Boolean remove_p;
378 widget_info* info;
379 widget_instance* instance;
380 widget_instance* prev;
381 for (info = all_widget_info; info; info = info->next)
382 for (prev = NULL, instance = info->instances;
383 instance;
384 prev = instance, instance = instance->next)
385 if (instance->widget == widget)
387 if (remove_p)
389 if (prev)
390 prev->next = instance->next;
391 else
392 info->instances = instance->next;
394 return instance;
396 return (widget_instance *) 0;
399 /* Value is a pointer to the widget_instance corresponding to
400 WIDGET, or null if WIDGET is not a lwlib widget. */
402 widget_instance *
403 lw_get_widget_instance (widget)
404 Widget widget;
406 return get_widget_instance (widget, False);
409 static widget_instance*
410 find_instance (id, parent, pop_up_p)
411 LWLIB_ID id;
412 Widget parent;
413 Boolean pop_up_p;
415 widget_info* info = get_widget_info (id, False);
416 widget_instance* instance;
418 if (info)
419 for (instance = info->instances; instance; instance = instance->next)
420 if (instance->parent == parent && instance->pop_up_p == pop_up_p)
421 return instance;
423 return NULL;
427 /* utility function for widget_value */
428 static Boolean
429 safe_strcmp (s1, s2)
430 char* s1;
431 char* s2;
433 if (!!s1 ^ !!s2) return True;
434 return (s1 && s2) ? strcmp (s1, s2) : s1 ? False : !!s2;
438 #if 0
439 # define EXPLAIN(name, oc, nc, desc, a1, a2) \
440 printf ("Change: \"%s\"\tmax(%s=%d,%s=%d)\t%s %d %d\n", \
441 name, \
442 (oc == NO_CHANGE ? "none" : \
443 (oc == INVISIBLE_CHANGE ? "invisible" : \
444 (oc == VISIBLE_CHANGE ? "visible" : \
445 (oc == STRUCTURAL_CHANGE ? "structural" : "???")))), \
446 oc, \
447 (nc == NO_CHANGE ? "none" : \
448 (nc == INVISIBLE_CHANGE ? "invisible" : \
449 (nc == VISIBLE_CHANGE ? "visible" : \
450 (nc == STRUCTURAL_CHANGE ? "structural" : "???")))), \
451 nc, desc, a1, a2)
452 #else
453 # define EXPLAIN(name, oc, nc, desc, a1, a2)
454 #endif
457 static widget_value *
458 merge_widget_value (val1, val2, level)
459 widget_value* val1;
460 widget_value* val2;
461 int level;
463 change_type change, this_one_change;
464 widget_value* merged_next;
465 widget_value* merged_contents;
467 if (!val1)
469 if (val2)
470 return copy_widget_value_tree (val2, STRUCTURAL_CHANGE);
471 else
472 return NULL;
474 if (!val2)
476 free_widget_value_tree (val1);
477 return NULL;
480 change = NO_CHANGE;
482 if (safe_strcmp (val1->name, val2->name))
484 EXPLAIN (val1->name, change, STRUCTURAL_CHANGE, "name change",
485 val1->name, val2->name);
486 change = max (change, STRUCTURAL_CHANGE);
487 safe_free_str (val1->name);
488 val1->name = safe_strdup (val2->name);
490 if (safe_strcmp (val1->value, val2->value))
492 EXPLAIN (val1->name, change, VISIBLE_CHANGE, "value change",
493 val1->value, val2->value);
494 change = max (change, VISIBLE_CHANGE);
495 safe_free_str (val1->value);
496 val1->value = safe_strdup (val2->value);
498 if (safe_strcmp (val1->key, val2->key))
500 EXPLAIN (val1->name, change, VISIBLE_CHANGE, "key change",
501 val1->key, val2->key);
502 change = max (change, VISIBLE_CHANGE);
503 safe_free_str (val1->key);
504 val1->key = safe_strdup (val2->key);
506 if (safe_strcmp (val1->help, val2->help))
508 EXPLAIN (val1->name, change, VISIBLE_CHANGE, "help change",
509 val1->help, val2->help);
510 change = max (change, VISIBLE_CHANGE);
511 safe_free_str (val1->help);
512 val1->key = safe_strdup (val2->help);
514 if (val1->enabled != val2->enabled)
516 EXPLAIN (val1->name, change, VISIBLE_CHANGE, "enablement change",
517 val1->enabled, val2->enabled);
518 change = max (change, VISIBLE_CHANGE);
519 val1->enabled = val2->enabled;
521 if (val1->button_type != val2->button_type)
523 EXPLAIN (val1->name, change, VISIBLE_CHANGE, "button type change",
524 val1->button_type, val2->button_type);
525 change = max (change, VISIBLE_CHANGE);
526 val1->button_type = val2->button_type;
528 if (val1->selected != val2->selected)
530 EXPLAIN (val1->name, change, VISIBLE_CHANGE, "selection change",
531 val1->selected, val2->selected);
532 change = max (change, VISIBLE_CHANGE);
533 val1->selected = val2->selected;
535 if (val1->call_data != val2->call_data)
537 EXPLAIN (val1->name, change, INVISIBLE_CHANGE, "call-data change",
538 val1->call_data, val2->call_data);
539 change = max (change, INVISIBLE_CHANGE);
540 val1->call_data = val2->call_data;
543 if (level > 0)
545 merged_contents =
546 merge_widget_value (val1->contents, val2->contents, level - 1);
548 if (val1->contents && !merged_contents)
550 /* This used to say INVISIBLE_CHANGE,
551 but it is visible and vitally important when
552 the contents of the menu bar itself are entirely deleted.
554 But maybe it doesn't matter. This fails to fix the bug. */
555 EXPLAIN (val1->name, change, STRUCTURAL_CHANGE, "(contents gone)",
556 0, 0);
557 change = max (change, STRUCTURAL_CHANGE);
559 else if (merged_contents && merged_contents->change != NO_CHANGE)
561 EXPLAIN (val1->name, change, INVISIBLE_CHANGE, "(contents change)",
562 0, 0);
563 change = max (change, INVISIBLE_CHANGE);
564 #if 0 /* This was replaced by the August 9 1996 change in lwlib-Xm.c. */
565 #ifdef USE_MOTIF
566 change = max (merged_contents->change, change);
567 #endif
568 #endif
571 val1->contents = merged_contents;
574 this_one_change = change;
576 merged_next = merge_widget_value (val1->next, val2->next, level);
578 if (val1->next && !merged_next)
580 EXPLAIN (val1->name, change, STRUCTURAL_CHANGE, "(following gone)",
581 0, 0);
582 change = max (change, STRUCTURAL_CHANGE);
584 else if (merged_next)
586 if (merged_next->change)
587 EXPLAIN (val1->name, change, merged_next->change, "(following change)",
588 0, 0);
589 change = max (change, merged_next->change);
592 val1->next = merged_next;
594 val1->this_one_change = this_one_change;
595 val1->change = change;
597 if (change > NO_CHANGE && val1->toolkit_data)
599 if (val1->free_toolkit_data)
600 XtFree (val1->toolkit_data);
601 val1->toolkit_data = NULL;
604 return val1;
608 /* modifying the widgets */
609 static Widget
610 name_to_widget (instance, name)
611 widget_instance* instance;
612 char* name;
614 Widget widget = NULL;
616 if (!instance->widget)
617 return NULL;
619 if (!strcmp (XtName (instance->widget), name))
620 widget = instance->widget;
621 else
623 int length = strlen (name) + 2;
624 char* real_name = (char *) xmalloc (length);
625 real_name [0] = '*';
626 strcpy (real_name + 1, name);
628 widget = XtNameToWidget (instance->widget, real_name);
630 free (real_name);
632 return widget;
635 static void
636 set_one_value (instance, val, deep_p)
637 widget_instance* instance;
638 widget_value* val;
639 Boolean deep_p;
641 Widget widget = name_to_widget (instance, val->name);
643 if (widget)
645 #if defined (USE_LUCID)
646 if (lw_lucid_widget_p (instance->widget))
647 xlw_update_one_widget (instance, widget, val, deep_p);
648 #endif
649 #if defined (USE_MOTIF)
650 if (lw_motif_widget_p (instance->widget))
651 xm_update_one_widget (instance, widget, val, deep_p);
652 #endif
653 #if defined (USE_OLIT)
654 if (lw_olit_widget_p (instance->widget))
655 xol_update_one_widget (instance, widget, val, deep_p);
656 #endif
657 #if defined (USE_XAW)
658 if (lw_xaw_widget_p (instance->widget))
659 xaw_update_one_widget (instance, widget, val, deep_p);
660 #endif
664 static void
665 update_one_widget_instance (instance, deep_p)
666 widget_instance* instance;
667 Boolean deep_p;
669 widget_value *val;
671 if (!instance->widget)
672 /* the widget was destroyed */
673 return;
675 for (val = instance->info->val; val; val = val->next)
676 if (val->change != NO_CHANGE)
677 set_one_value (instance, val, deep_p);
680 static void
681 update_all_widget_values (info, deep_p)
682 widget_info* info;
683 Boolean deep_p;
685 widget_instance* instance;
686 widget_value* val;
688 for (instance = info->instances; instance; instance = instance->next)
689 update_one_widget_instance (instance, deep_p);
691 for (val = info->val; val; val = val->next)
692 val->change = NO_CHANGE;
695 void
696 lw_modify_all_widgets (id, val, deep_p)
697 LWLIB_ID id;
698 widget_value* val;
699 Boolean deep_p;
701 widget_info* info = get_widget_info (id, False);
702 widget_value* new_val;
703 widget_value* next_new_val;
704 widget_value* cur;
705 widget_value* prev;
706 widget_value* next;
707 int found;
709 if (!info)
710 return;
712 for (new_val = val; new_val; new_val = new_val->next)
714 next_new_val = new_val->next;
715 new_val->next = NULL;
716 found = False;
717 for (prev = NULL, cur = info->val; cur; prev = cur, cur = cur->next)
718 if (!strcmp (cur->name, new_val->name))
720 found = True;
721 next = cur->next;
722 cur->next = NULL;
723 cur = merge_widget_value (cur, new_val, deep_p ? 1000 : 1);
724 if (prev)
725 prev->next = cur ? cur : next;
726 else
727 info->val = cur ? cur : next;
728 if (cur)
729 cur->next = next;
730 break;
732 if (!found)
734 /* Could not find it, add it */
735 if (prev)
736 prev->next = copy_widget_value_tree (new_val, STRUCTURAL_CHANGE);
737 else
738 info->val = copy_widget_value_tree (new_val, STRUCTURAL_CHANGE);
740 new_val->next = next_new_val;
743 update_all_widget_values (info, deep_p);
747 /* creating the widgets */
749 static void
750 initialize_widget_instance (instance)
751 widget_instance* instance;
753 widget_value* val;
755 for (val = instance->info->val; val; val = val->next)
756 val->change = STRUCTURAL_CHANGE;
758 update_one_widget_instance (instance, True);
760 for (val = instance->info->val; val; val = val->next)
761 val->change = NO_CHANGE;
765 static widget_creation_function
766 find_in_table (type, table)
767 char* type;
768 widget_creation_entry* table;
770 widget_creation_entry* cur;
771 for (cur = table; cur->type; cur++)
772 if (!my_strcasecmp (type, cur->type))
773 return cur->function;
774 return NULL;
777 static Boolean
778 dialog_spec_p (name)
779 char* name;
781 /* return True if name matches [EILPQeilpq][1-9][Bb] or
782 [EILPQeilpq][1-9][Bb][Rr][1-9] */
783 if (!name)
784 return False;
786 switch (name [0])
788 case 'E': case 'I': case 'L': case 'P': case 'Q':
789 case 'e': case 'i': case 'l': case 'p': case 'q':
790 if (name [1] >= '0' && name [1] <= '9')
792 if (name [2] != 'B' && name [2] != 'b')
793 return False;
794 if (!name [3])
795 return True;
796 if ((name [3] == 'T' || name [3] == 't') && !name [4])
797 return True;
798 if ((name [3] == 'R' || name [3] == 'r')
799 && name [4] >= '0' && name [4] <= '9' && !name [5])
800 return True;
801 return False;
803 else
804 return False;
806 default:
807 return False;
811 static void
812 instantiate_widget_instance (instance)
813 widget_instance* instance;
815 widget_creation_function function = NULL;
817 #if defined (USE_LUCID)
818 if (!function)
819 function = find_in_table (instance->info->type, xlw_creation_table);
820 #endif
821 #if defined(USE_MOTIF)
822 if (!function)
823 function = find_in_table (instance->info->type, xm_creation_table);
824 #endif
825 #if defined (USE_OLIT)
826 if (!function)
827 function = find_in_table (instance->info->type, xol_creation_table);
828 #endif
829 #if defined (USE_XAW)
830 if (!function)
831 function = find_in_table (instance->info->type, xaw_creation_table);
832 #endif
834 if (!function)
836 if (dialog_spec_p (instance->info->type))
838 #if defined (USE_LUCID)
839 /* not yet */
840 #endif
841 #if defined(USE_MOTIF)
842 if (!function)
843 function = xm_create_dialog;
844 #endif
845 #if defined (USE_XAW)
846 if (!function)
847 function = xaw_create_dialog;
848 #endif
849 #if defined (USE_OLIT)
850 /* not yet */
851 #endif
855 if (!function)
857 printf ("No creation function for widget type %s\n",
858 instance->info->type);
859 abort ();
862 instance->widget = (*function) (instance);
864 if (!instance->widget)
865 abort ();
867 /* XtRealizeWidget (instance->widget);*/
870 void
871 lw_register_widget (type, name, id, val, pre_activate_cb,
872 selection_cb, post_activate_cb, highlight_cb)
873 char* type;
874 char* name;
875 LWLIB_ID id;
876 widget_value* val;
877 lw_callback pre_activate_cb;
878 lw_callback selection_cb;
879 lw_callback post_activate_cb;
880 lw_callback highlight_cb;
882 if (!get_widget_info (id, False))
883 allocate_widget_info (type, name, id, val, pre_activate_cb, selection_cb,
884 post_activate_cb, highlight_cb);
887 Widget
888 lw_get_widget (id, parent, pop_up_p)
889 LWLIB_ID id;
890 Widget parent;
891 Boolean pop_up_p;
893 widget_instance* instance;
895 instance = find_instance (id, parent, pop_up_p);
896 return instance ? instance->widget : NULL;
899 Widget
900 lw_make_widget (id, parent, pop_up_p)
901 LWLIB_ID id;
902 Widget parent;
903 Boolean pop_up_p;
905 widget_instance* instance;
906 widget_info* info;
908 instance = find_instance (id, parent, pop_up_p);
909 if (!instance)
911 info = get_widget_info (id, False);
912 if (!info)
913 return NULL;
914 instance = allocate_widget_instance (info, parent, pop_up_p);
915 initialize_widget_instance (instance);
917 if (!instance->widget)
918 abort ();
919 return instance->widget;
922 Widget
923 lw_create_widget (type, name, id, val, parent, pop_up_p, pre_activate_cb,
924 selection_cb, post_activate_cb, highlight_cb)
925 char* type;
926 char* name;
927 LWLIB_ID id;
928 widget_value* val;
929 Widget parent;
930 Boolean pop_up_p;
931 lw_callback pre_activate_cb;
932 lw_callback selection_cb;
933 lw_callback post_activate_cb;
934 lw_callback highlight_cb;
936 lw_register_widget (type, name, id, val, pre_activate_cb, selection_cb,
937 post_activate_cb, highlight_cb);
938 return lw_make_widget (id, parent, pop_up_p);
942 /* destroying the widgets */
943 static void
944 destroy_one_instance (instance)
945 widget_instance* instance;
947 /* Remove the destroy callback on the widget; that callback will try to
948 dereference the instance object (to set its widget slot to 0, since the
949 widget is dead.) Since the instance is now dead, we don't have to worry
950 about the fact that its widget is dead too.
952 This happens in the Phase2Destroy of the widget, so this callback would
953 not have been run until arbitrarily long after the instance was freed.
955 if (instance->widget)
956 XtRemoveCallback (instance->widget, XtNdestroyCallback,
957 mark_widget_destroyed, (XtPointer)instance);
959 if (instance->widget)
961 /* The else are pretty tricky here, including the empty statement
962 at the end because it would be very bad to destroy a widget
963 twice. */
964 #if defined (USE_LUCID)
965 if (lw_lucid_widget_p (instance->widget))
966 xlw_destroy_instance (instance);
967 else
968 #endif
969 #if defined (USE_MOTIF)
970 if (lw_motif_widget_p (instance->widget))
971 xm_destroy_instance (instance);
972 else
973 #endif
974 #if defined (USE_OLIT)
975 if (lw_olit_widget_p (instance->widget))
976 xol_destroy_instance (instance);
977 else
978 #endif
979 #if defined (USE_XAW)
980 if (lw_xaw_widget_p (instance->widget))
981 xaw_destroy_instance (instance);
982 else
983 #endif
984 /* do not remove the empty statement */
988 free_widget_instance (instance);
991 void
992 lw_destroy_widget (w)
993 Widget w;
995 widget_instance* instance = get_widget_instance (w, True);
997 if (instance)
999 widget_info *info = instance->info;
1000 /* instance has already been removed from the list; free it */
1001 destroy_one_instance (instance);
1002 /* if there are no instances left, free the info too */
1003 if (!info->instances)
1004 lw_destroy_all_widgets (info->id);
1008 void
1009 lw_destroy_all_widgets (id)
1010 LWLIB_ID id;
1012 widget_info* info = get_widget_info (id, True);
1013 widget_instance* instance;
1014 widget_instance* next;
1016 if (info)
1018 for (instance = info->instances; instance; )
1020 next = instance->next;
1021 destroy_one_instance (instance);
1022 instance = next;
1024 free_widget_info (info);
1028 void
1029 lw_destroy_everything ()
1031 while (all_widget_info)
1032 lw_destroy_all_widgets (all_widget_info->id);
1035 void
1036 lw_destroy_all_pop_ups ()
1038 widget_info* info;
1039 widget_info* next;
1040 widget_instance* instance;
1042 for (info = all_widget_info; info; info = next)
1044 next = info->next;
1045 instance = info->instances;
1046 if (instance && instance->pop_up_p)
1047 lw_destroy_all_widgets (info->id);
1051 #ifdef USE_MOTIF
1052 extern Widget first_child (/* Widget */); /* garbage */
1053 #endif
1055 Widget
1056 lw_raise_all_pop_up_widgets ()
1058 widget_info* info;
1059 widget_instance* instance;
1060 Widget result = NULL;
1062 for (info = all_widget_info; info; info = info->next)
1063 for (instance = info->instances; instance; instance = instance->next)
1064 if (instance->pop_up_p)
1066 Widget widget = instance->widget;
1067 if (widget)
1069 if (XtIsManaged (widget)
1070 #ifdef USE_MOTIF
1071 /* What a complete load of crap!!!!
1072 When a dialogShell is on the screen, it is not managed!
1074 || (lw_motif_widget_p (instance->widget) &&
1075 XtIsManaged (first_child (widget)))
1076 #endif
1079 if (!result)
1080 result = widget;
1081 XMapRaised (XtDisplay (widget), XtWindow (widget));
1085 return result;
1088 static void
1089 lw_pop_all_widgets (id, up)
1090 LWLIB_ID id;
1091 Boolean up;
1093 widget_info* info = get_widget_info (id, False);
1094 widget_instance* instance;
1096 if (info)
1097 for (instance = info->instances; instance; instance = instance->next)
1098 if (instance->pop_up_p && instance->widget)
1100 #if defined (USE_LUCID)
1101 if (lw_lucid_widget_p (instance->widget))
1103 XtRealizeWidget (instance->widget);
1104 xlw_pop_instance (instance, up);
1106 #endif
1107 #if defined (USE_MOTIF)
1108 if (lw_motif_widget_p (instance->widget))
1110 XtRealizeWidget (instance->widget);
1111 xm_pop_instance (instance, up);
1113 #endif
1114 #if defined (USE_OLIT)
1115 if (lw_olit_widget_p (instance->widget))
1117 XtRealizeWidget (instance->widget);
1118 xol_pop_instance (instance, up);
1120 #endif
1121 #if defined (USE_XAW)
1122 if (lw_xaw_widget_p (instance->widget))
1124 XtRealizeWidget (XtParent (instance->widget));
1125 XtRealizeWidget (instance->widget);
1126 xaw_pop_instance (instance, up);
1128 #endif
1132 void
1133 lw_pop_up_all_widgets (id)
1134 LWLIB_ID id;
1136 lw_pop_all_widgets (id, True);
1139 void
1140 lw_pop_down_all_widgets (id)
1141 LWLIB_ID id;
1143 lw_pop_all_widgets (id, False);
1146 void
1147 lw_popup_menu (widget, event)
1148 Widget widget;
1149 XEvent *event;
1151 #if defined (USE_LUCID)
1152 if (lw_lucid_widget_p (widget))
1153 xlw_popup_menu (widget, event);
1154 #endif
1155 #if defined (USE_MOTIF)
1156 if (lw_motif_widget_p (widget))
1157 xm_popup_menu (widget, event);
1158 #endif
1159 #if defined (USE_OLIT)
1160 if (lw_olit_widget_p (widget))
1161 xol_popup_menu (widget, event);
1162 #endif
1163 #if defined (USE_XAW)
1164 if (lw_xaw_widget_p (widget))
1165 xaw_popup_menu (widget, event);
1166 #endif
1169 \f/* get the values back */
1170 static Boolean
1171 get_one_value (instance, val)
1172 widget_instance* instance;
1173 widget_value* val;
1175 Widget widget = name_to_widget (instance, val->name);
1177 if (widget)
1179 #if defined (USE_LUCID)
1180 if (lw_lucid_widget_p (instance->widget))
1181 xlw_update_one_value (instance, widget, val);
1182 #endif
1183 #if defined (USE_MOTIF)
1184 if (lw_motif_widget_p (instance->widget))
1185 xm_update_one_value (instance, widget, val);
1186 #endif
1187 #if defined (USE_OLIT)
1188 if (lw_olit_widget_p (instance->widget))
1189 xol_update_one_value (instance, widget, val);
1190 #endif
1191 #if defined (USE_XAW)
1192 if (lw_xaw_widget_p (instance->widget))
1193 xaw_update_one_value (instance, widget, val);
1194 #endif
1195 return True;
1197 else
1198 return False;
1201 Boolean
1202 lw_get_some_values (id, val_out)
1203 LWLIB_ID id;
1204 widget_value* val_out;
1206 widget_info* info = get_widget_info (id, False);
1207 widget_instance* instance;
1208 widget_value* val;
1209 Boolean result = False;
1211 if (!info)
1212 return False;
1214 instance = info->instances;
1215 if (!instance)
1216 return False;
1218 for (val = val_out; val; val = val->next)
1219 if (get_one_value (instance, val))
1220 result = True;
1222 return result;
1225 widget_value*
1226 lw_get_all_values (id)
1227 LWLIB_ID id;
1229 widget_info* info = get_widget_info (id, False);
1230 widget_value* val = info->val;
1231 if (lw_get_some_values (id, val))
1232 return val;
1233 else
1234 return NULL;
1237 /* internal function used by the library dependent implementation to get the
1238 widget_value for a given widget in an instance */
1239 widget_value*
1240 lw_get_widget_value_for_widget (instance, w)
1241 widget_instance* instance;
1242 Widget w;
1244 char* name = XtName (w);
1245 widget_value* cur;
1246 for (cur = instance->info->val; cur; cur = cur->next)
1247 if (!strcmp (cur->name, name))
1248 return cur;
1249 return NULL;
1252 \f/* update other instances value when one thing changed */
1254 /* To forbid recursive calls */
1255 static Boolean lwlib_updating;
1257 /* This function can be used as a an XtCallback for the widgets that get
1258 modified to update other instances of the widgets. Closure should be the
1259 widget_instance. */
1260 void
1261 lw_internal_update_other_instances (widget, closure, call_data)
1262 Widget widget;
1263 XtPointer closure;
1264 XtPointer call_data;
1266 widget_instance* instance = (widget_instance*)closure;
1267 char* name = XtName (widget);
1268 widget_info* info;
1269 widget_instance* cur;
1270 widget_value* val;
1272 /* Avoid possibly infinite recursion. */
1273 if (lwlib_updating)
1274 return;
1276 /* protect against the widget being destroyed */
1277 if (XtWidgetBeingDestroyedP (widget))
1278 return;
1280 /* Return immediately if there are no other instances */
1281 info = instance->info;
1282 if (!info->instances->next)
1283 return;
1285 lwlib_updating = True;
1287 for (val = info->val; val && strcmp (val->name, name); val = val->next);
1289 if (val && get_one_value (instance, val))
1290 for (cur = info->instances; cur; cur = cur->next)
1291 if (cur != instance)
1292 set_one_value (cur, val, True);
1294 lwlib_updating = False;
1298 \f/* get the id */
1300 LWLIB_ID
1301 lw_get_widget_id (w)
1302 Widget w;
1304 widget_instance* instance = get_widget_instance (w, False);
1306 return instance ? instance->info->id : 0;
1309 \f/* set the keyboard focus */
1310 void
1311 lw_set_keyboard_focus (parent, w)
1312 Widget parent;
1313 Widget w;
1315 #if defined (USE_MOTIF)
1316 xm_set_keyboard_focus (parent, w);
1317 #else
1318 XtSetKeyboardFocus (parent, w);
1319 #endif
1322 \f/* Show busy */
1323 static void
1324 show_one_widget_busy (w, flag)
1325 Widget w;
1326 Boolean flag;
1328 Pixel foreground = 0;
1329 Pixel background = 1;
1330 Widget widget_to_invert = XtNameToWidget (w, "*sheet");
1331 if (!widget_to_invert)
1332 widget_to_invert = w;
1334 XtVaGetValues (widget_to_invert,
1335 XtNforeground, &foreground,
1336 XtNbackground, &background,
1338 XtVaSetValues (widget_to_invert,
1339 XtNforeground, background,
1340 XtNbackground, foreground,
1344 void
1345 lw_show_busy (w, busy)
1346 Widget w;
1347 Boolean busy;
1349 widget_instance* instance = get_widget_instance (w, False);
1350 widget_info* info;
1351 widget_instance* next;
1353 if (instance)
1355 info = instance->info;
1356 if (info->busy != busy)
1358 for (next = info->instances; next; next = next->next)
1359 if (next->widget)
1360 show_one_widget_busy (next->widget, busy);
1361 info->busy = busy;
1366 /* This hack exists because Lucid/Athena need to execute the strange
1367 function below to support geometry management. */
1368 void
1369 lw_refigure_widget (w, doit)
1370 Widget w;
1371 Boolean doit;
1373 #if defined (USE_XAW)
1374 XawPanedSetRefigureMode (w, doit);
1375 #endif
1376 #if defined (USE_MOTIF)
1377 if (doit)
1378 XtManageChild (w);
1379 else
1380 XtUnmanageChild (w);
1381 #endif
1384 /* Toolkit independent way of determining if an event window is in the
1385 menubar. */
1386 Boolean
1387 lw_window_is_in_menubar (win, menubar_widget)
1388 Window win;
1389 Widget menubar_widget;
1391 return menubar_widget
1392 #if defined (USE_LUCID)
1393 && XtWindow (menubar_widget) == win;
1394 #endif
1395 #if defined (USE_MOTIF)
1396 && ((XtWindow (menubar_widget) == win)
1397 || (XtWindowToWidget (XtDisplay (menubar_widget), win)
1398 && (XtParent (XtWindowToWidget (XtDisplay (menubar_widget), win))
1399 == menubar_widget)));
1400 #endif
1403 /* Motif hack to set the main window areas. */
1404 void
1405 lw_set_main_areas (parent, menubar, work_area)
1406 Widget parent;
1407 Widget menubar;
1408 Widget work_area;
1410 #if defined (USE_MOTIF)
1411 xm_set_main_areas (parent, menubar, work_area);
1412 #endif
1415 /* Manage resizing for Motif. This disables resizing when the menubar
1416 is about to be modified. */
1417 void
1418 lw_allow_resizing (w, flag)
1419 Widget w;
1420 Boolean flag;
1422 #if defined (USE_MOTIF)
1423 xm_manage_resizing (w, flag);
1424 #endif
1428 /* Value is non-zero if LABEL is a menu separator. If it is, *TYPE is
1429 set to an appropriate enumerator of type enum menu_separator.
1430 MOTIF_P non-zero means map separator types not supported by Motif
1431 to similar ones that are supported. */
1434 lw_separator_p (label, type, motif_p)
1435 char *label;
1436 enum menu_separator *type;
1437 int motif_p;
1439 int separator_p;
1441 if (strlen (label) >= 3
1442 && bcmp (label, "--:", 3) == 0)
1444 static struct separator_table
1446 char *name;
1447 enum menu_separator type;
1449 separator_names[] =
1451 "space", SEPARATOR_NO_LINE,
1452 "noLine", SEPARATOR_NO_LINE,
1453 "singleLine", SEPARATOR_SINGLE_LINE,
1454 "doubleLine", SEPARATOR_DOUBLE_LINE,
1455 "singleDashedLine", SEPARATOR_SINGLE_DASHED_LINE,
1456 "doubleDashedLine", SEPARATOR_DOUBLE_DASHED_LINE,
1457 "shadowEtchedIn", SEPARATOR_SHADOW_ETCHED_IN,
1458 "shadowEtchedOut", SEPARATOR_SHADOW_ETCHED_OUT,
1459 "shadowEtchedInDash", SEPARATOR_SHADOW_ETCHED_IN_DASH,
1460 "shadowEtchedOutDash", SEPARATOR_SHADOW_ETCHED_OUT_DASH,
1461 "shadowDoubleEtchedIn", SEPARATOR_SHADOW_DOUBLE_ETCHED_IN,
1462 "shadowDoubleEtchedOut", SEPARATOR_SHADOW_DOUBLE_ETCHED_OUT,
1463 "shadowDoubleEtchedInDash", SEPARATOR_SHADOW_DOUBLE_ETCHED_IN_DASH,
1464 "shadowDoubleEtchedOutDash", SEPARATOR_SHADOW_DOUBLE_ETCHED_OUT_DASH,
1468 int i;
1470 label += 3;
1471 for (i = 0; separator_names[i].name; ++i)
1472 if (strcmp (label, separator_names[i].name) == 0)
1474 separator_p = 1;
1475 *type = separator_names[i].type;
1477 /* If separator type is not supported under Motif,
1478 use a similar one. */
1479 if (motif_p && *type >= SEPARATOR_SHADOW_DOUBLE_ETCHED_IN)
1480 *type -= 4;
1481 break;
1484 else if (strlen (label) > 3
1485 && bcmp (label, "--", 2) == 0
1486 && label[2] != '-')
1488 /* Alternative, more Emacs-style names. */
1489 static struct separator_table
1491 char *name;
1492 enum menu_separator type;
1494 separator_names[] =
1496 "space", SEPARATOR_NO_LINE,
1497 "no-line", SEPARATOR_NO_LINE,
1498 "single-line", SEPARATOR_SINGLE_LINE,
1499 "double-line", SEPARATOR_DOUBLE_LINE,
1500 "single-dashed-line", SEPARATOR_SINGLE_DASHED_LINE,
1501 "double-dashed-line", SEPARATOR_DOUBLE_DASHED_LINE,
1502 "shadow-etched-in", SEPARATOR_SHADOW_ETCHED_IN,
1503 "shadow-etched-out", SEPARATOR_SHADOW_ETCHED_OUT,
1504 "shadow-etched-in-dash", SEPARATOR_SHADOW_ETCHED_IN_DASH,
1505 "shadow-etched-out-dash", SEPARATOR_SHADOW_ETCHED_OUT_DASH,
1506 "shadow-double-etched-in", SEPARATOR_SHADOW_DOUBLE_ETCHED_IN,
1507 "shadow-double-etched-out", SEPARATOR_SHADOW_DOUBLE_ETCHED_OUT,
1508 "shadow-double-etched-in-dash", SEPARATOR_SHADOW_DOUBLE_ETCHED_IN_DASH,
1509 "shadow-double-etched-out-dash",SEPARATOR_SHADOW_DOUBLE_ETCHED_OUT_DASH,
1513 int i;
1515 label += 2;
1516 for (i = 0; separator_names[i].name; ++i)
1517 if (strcmp (label, separator_names[i].name) == 0)
1519 separator_p = 1;
1520 *type = separator_names[i].type;
1522 /* If separator type is not supported under Motif,
1523 use a similar one. */
1524 if (motif_p && *type >= SEPARATOR_SHADOW_DOUBLE_ETCHED_IN)
1525 *type -= 4;
1526 break;
1529 else
1531 /* Old-style separator, maybe. It's a separator if it contains
1532 only dashes. */
1533 while (*label == '-')
1534 ++label;
1535 separator_p = *label == 0;
1536 *type = SEPARATOR_SHADOW_ETCHED_IN;
1539 return separator_p;