1 /* A general interface to the widgets of different toolkits.
2 Copyright (C) 1992, 1993, 1994 Lucid, Inc.
3 Copyright (C) 1995 Tinker Systems and INS Engineering Corp.
5 This file is part of the Lucid Widget Library.
7 The Lucid Widget Library is free software: you can redistribute it
8 and/or modify it under the terms of the GNU General Public License as
9 published by the Free Software Foundation, either version 3 of the
10 License, or (at your option) any later version.
12 The Lucid Widget Library is distributed in the hope that it will be
13 useful, but WITHOUT ANY WARRANTY; without even the implied warranty of
14 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15 General Public License for more details.
17 You should have received a copy of the GNU General Public License
18 along with this program. If not, see <http://www.gnu.org/licenses/>. */
21 #undef __STRICT_BSD__ /* ick */
28 #include <sys/types.h>
32 #include <X11/StringDefs.h>
33 #include "lwlib-internal.h"
34 #include "lwlib-utils.h"
37 #include "lwlib-Xlw.h"
41 #ifdef LWLIB_WIDGETS_MOTIF
46 #include "lwlib-Xaw.h"
49 #if defined HAVE_BDWGC && defined EF_USE_BDWGC
50 # if defined HAVE_GC_GC_H
52 # elif defined HAVE_GC_H
56 # define xmalloc GC_MALLOC
57 # define xmalloc_atomic GC_MALLOC_ATOMIC
58 # define xrealloc GC_REALLOC
60 # define xstrdup GC_STRDUP
61 #else /* !HAVE_BDWGC */
62 # define xmalloc malloc
63 # define xmalloc_atomic malloc
64 # define xrealloc realloc
66 # define xstrdup strdup
67 #endif /* HAVE_BDWGC */
70 /* #### Does a check need to be put back in here to make sure we have
71 sufficient defines to function properly or are the checks in the
72 makefile sufficient? */
74 /* List of all widgets managed by the library. Note that each "widget"
75 listed here may actually be a tree of widgets; for example, a
76 single entry here might represent a single menubar or popup menu,
77 each of which might be implemented with a tree of widgets.
79 static widget_info *all_widget_info = NULL;
81 /* boolean flag indicating that the menubar is active */
82 int lw_menu_active = 0;
84 /* X11 menubar widget */
85 Widget lw_menubar_widget = NULL;
87 /* whether the last menu operation was a keyboard accelerator */
88 int lw_menu_accelerate = False;
90 /* Forward declarations */
91 static void instantiate_widget_instance(widget_instance * instance);
92 static void free_widget_value_args(widget_value * wv);
94 /* utility functions for widget_instance and widget_info */
95 static char *safe_strdup(const char *s)
100 result = (char *)xmalloc(strlen(s) + 1);
107 static inline void safe_free_str(char *s)
114 static widget_value *widget_value_free_list = 0;
116 widget_value *malloc_widget_value(void)
119 if (widget_value_free_list) {
120 wv = widget_value_free_list;
121 widget_value_free_list = wv->free_list;
124 wv = (widget_value *) xmalloc(sizeof(widget_value));
127 memset(wv, '\0', sizeof(widget_value));
132 /* this is analogous to free(). It frees only what was allocated
133 by malloc_widget_value(), and no substructures.
135 void free_widget_value(widget_value * wv)
139 wv->free_list = widget_value_free_list;
140 widget_value_free_list = wv;
143 static void free_widget_value_contents(widget_value * wv)
152 /* #### - all of this 0xDEADBEEF stuff should be unnecessary
153 in production code... it should be conditionalized. */
154 wv->name = wv->value = wv->key = (char *)0xDEADBEEF;
156 if (wv->toolkit_data && wv->free_toolkit_data) {
157 XtFree((char *)wv->toolkit_data);
158 wv->toolkit_data = (void *)0xDEADBEEF;
160 #ifdef NEED_SCROLLBARS
161 if (wv->scrollbar_data) {
162 xfree(wv->scrollbar_data);
163 wv->scrollbar_data = NULL;
166 if (wv->contents && (wv->contents != (widget_value *) 1)) {
167 free_widget_value_tree(wv->contents);
168 wv->contents = (widget_value *) 0xDEADBEEF;
171 free_widget_value_args(wv);
174 free_widget_value_tree(wv->next);
175 wv->next = (widget_value *) 0xDEADBEEF;
179 void free_widget_value_tree(widget_value * wv)
184 free_widget_value_contents(wv);
185 free_widget_value(wv);
188 #ifdef NEED_SCROLLBARS
190 static void copy_scrollbar_values(widget_value * val, widget_value * copy)
192 if (!copy->scrollbar_data)
193 copy->scrollbar_data =
194 (scrollbar_values *) xmalloc(sizeof(scrollbar_values));
196 if (val->scrollbar_data)
197 *copy->scrollbar_data = *val->scrollbar_data;
199 memset(copy->scrollbar_data, '\0', sizeof(scrollbar_values));
203 * Return true if old->scrollbar_data were not equivalent
204 * to new->scrollbar_data.
206 static Boolean merge_scrollbar_values(widget_value * old, widget_value * new)
208 Boolean changed = False;
210 if (new->scrollbar_data && !old->scrollbar_data) {
211 copy_scrollbar_values(new, old);
213 } else if (!new->scrollbar_data && old->scrollbar_data) {
214 xfree(old->scrollbar_data);
215 old->scrollbar_data = NULL;
216 } else if (new->scrollbar_data && old->scrollbar_data) {
217 scrollbar_values *old_sb = old->scrollbar_data;
218 scrollbar_values *new_sb = new->scrollbar_data;
220 if ((old_sb->line_increment != new_sb->line_increment) ||
221 (old_sb->page_increment != new_sb->page_increment) ||
222 (old_sb->minimum != new_sb->minimum) ||
223 (old_sb->maximum != new_sb->maximum) ||
224 (old_sb->slider_size != new_sb->slider_size) ||
225 (old_sb->slider_position != new_sb->slider_position) ||
226 (old_sb->scrollbar_width != new_sb->scrollbar_width) ||
227 (old_sb->scrollbar_height != new_sb->scrollbar_height) ||
228 (old_sb->scrollbar_x != new_sb->scrollbar_x) ||
229 (old_sb->scrollbar_y != new_sb->scrollbar_y))
238 #endif /* NEED_SCROLLBARS */
242 * Return true if old->args was not equivalent
245 static Boolean merge_widget_value_args(widget_value * old, widget_value * new)
247 Boolean changed = False;
249 if (new->args && !old->args) {
250 lw_copy_widget_value_args(new, old);
253 /* Generally we don't want to lose values that are already in the
255 else if (!new->args && old->args) {
256 lw_copy_widget_value_args(old, new);
258 } else if (new->args && old->args && new->args != old->args) {
259 /* #### Do something more sensible here than just copying the
260 new values (like actually merging the values). */
261 lw_copy_widget_value_args(new, old);
263 } else if (new->args && new->args == old->args
264 && new->args->args_changed == True) {
270 #endif /* HAVE_WIDGETS */
272 /* Make a complete copy of a widget_value tree. Store CHANGE into
273 the widget_value tree's `change' field. */
275 widget_value *copy_widget_value_tree(widget_value * val, change_type change)
281 if (val == (widget_value *) 1)
284 copy = malloc_widget_value();
286 /* #### - don't seg fault *here* if out of memory. Menus will be
287 truncated inexplicably. */
288 copy->type = val->type;
289 copy->name = safe_strdup(val->name);
290 copy->value = safe_strdup(val->value);
291 copy->key = safe_strdup(val->key);
292 copy->accel = val->accel;
293 copy->enabled = val->enabled;
294 copy->selected = val->selected;
295 copy->edited = False;
296 copy->change = change;
297 copy->contents = copy_widget_value_tree(val->contents, change);
298 copy->call_data = val->call_data;
299 copy->next = copy_widget_value_tree(val->next, change);
300 copy->toolkit_data = NULL;
301 copy->free_toolkit_data = False;
303 lw_copy_widget_value_args(val, copy);
304 #ifdef NEED_SCROLLBARS
305 copy_scrollbar_values(val, copy);
311 /* This function is used to implement incremental menu construction. */
313 widget_value *replace_widget_value_tree(widget_value * node,
314 widget_value * newtree)
318 if (!node || !newtree)
321 copy = copy_widget_value_tree(newtree, STRUCTURAL_CHANGE);
323 free_widget_value_contents(node);
325 free_widget_value(copy); /* free the node, but not its contents. */
329 static widget_info *allocate_widget_info(const char *type, const char *name,
330 LWLIB_ID id, widget_value * val,
331 lw_callback pre_activate_cb,
332 lw_callback selection_cb,
333 lw_callback post_activate_cb)
335 widget_info *info = (widget_info *) xmalloc(sizeof(widget_info));
336 info->type = safe_strdup(type);
337 info->name = safe_strdup(name);
339 info->val = copy_widget_value_tree(val, STRUCTURAL_CHANGE);
341 info->pre_activate_cb = pre_activate_cb;
342 info->selection_cb = selection_cb;
343 info->post_activate_cb = post_activate_cb;
344 info->instances = NULL;
346 info->next = all_widget_info;
347 all_widget_info = info;
352 static void free_widget_info(widget_info * info)
354 safe_free_str(info->type);
355 safe_free_str(info->name);
356 free_widget_value_tree(info->val);
357 memset(info, '\0', sizeof(widget_info));
362 mark_widget_destroyed(Widget widget, XtPointer closure, XtPointer call_data)
364 widget_instance *instance = (widget_instance *) closure;
366 /* be very conservative */
367 if (instance->widget == widget)
368 instance->widget = NULL;
371 static widget_instance *allocate_widget_instance(widget_info * info,
375 widget_instance *instance =
376 (widget_instance *) xmalloc(sizeof(widget_instance));
377 instance->parent = parent;
378 instance->pop_up_p = pop_up_p;
379 instance->info = info;
380 instance->next = info->instances;
381 info->instances = instance;
383 instantiate_widget_instance(instance);
385 XtAddCallback(instance->widget, XtNdestroyCallback,
386 mark_widget_destroyed, (XtPointer) instance);
390 static void free_widget_instance(widget_instance * instance)
392 memset(instance, '\0', sizeof(widget_instance));
396 static widget_info *get_widget_info(LWLIB_ID id, Boolean remove_p)
400 for (prev = NULL, info = all_widget_info;
401 info; prev = info, info = info->next)
402 if (info->id == id) {
405 prev->next = info->next;
407 all_widget_info = info->next;
414 /* Internal function used by the library dependent implementation to get the
415 widget_value for a given widget in an instance */
416 widget_info *lw_get_widget_info(LWLIB_ID id)
418 return get_widget_info(id, 0);
422 map_widget_values(widget_value * value, int (*mapfunc) (widget_value * value,
429 retval = map_widget_values(value->contents, mapfunc, closure);
434 retval = map_widget_values(value->next, mapfunc, closure);
438 return (mapfunc) (value, closure);
442 lw_map_widget_values(LWLIB_ID id, int (*mapfunc) (widget_value * value,
443 void *closure), void *closure)
445 widget_info *info = get_widget_info(id, 0);
451 return map_widget_values(info->val, mapfunc, closure);
455 static widget_instance *get_widget_instance(Widget widget, Boolean remove_p)
458 widget_instance *instance;
459 widget_instance *prev;
460 for (info = all_widget_info; info; info = info->next)
461 for (prev = NULL, instance = info->instances;
462 instance; prev = instance, instance = instance->next)
463 if (instance->widget == widget) {
466 prev->next = instance->next;
473 return (widget_instance *) 0;
476 static widget_instance *find_instance(LWLIB_ID id, Widget parent,
479 widget_info *info = get_widget_info(id, False);
480 widget_instance *instance;
483 for (instance = info->instances; instance;
484 instance = instance->next)
485 if (instance->parent == parent
486 && instance->pop_up_p == pop_up_p)
492 /* utility function for widget_value */
493 static Boolean safe_strcmp(const char *s1, const char *s2)
497 return (s1 && s2) ? strcmp(s1, s2) : s1 ? False : !!s2;
500 static change_type max(change_type i1, change_type i2)
502 return (int)i1 > (int)i2 ? i1 : i2;
506 # define EXPLAIN(name, oc, nc, desc, a1, a2) \
507 printf ("Change: \"%s\"\tmax(%s=%d,%s=%d)\t%s %d %d\n", \
509 (oc == NO_CHANGE ? "none" : \
510 (oc == INVISIBLE_CHANGE ? "invisible" : \
511 (oc == VISIBLE_CHANGE ? "visible" : \
512 (oc == STRUCTURAL_CHANGE ? "structural" : "???")))), \
514 (nc == NO_CHANGE ? "none" : \
515 (nc == INVISIBLE_CHANGE ? "invisible" : \
516 (nc == VISIBLE_CHANGE ? "visible" : \
517 (nc == STRUCTURAL_CHANGE ? "structural" : "???")))), \
520 # define EXPLAIN(name, oc, nc, desc, a1, a2)
523 static widget_value *merge_widget_value(widget_value * val1,
524 widget_value * val2, int level)
527 widget_value *merged_next;
528 widget_value *merged_contents;
532 return copy_widget_value_tree(val2, STRUCTURAL_CHANGE);
537 free_widget_value_tree(val1);
543 if (val1->type != val2->type) {
544 EXPLAIN(val1->name, change, STRUCTURAL_CHANGE, "type change",
545 val1->type, val2->type);
546 change = max(change, STRUCTURAL_CHANGE);
547 val1->type = val2->type;
549 if (safe_strcmp(val1->name, val2->name)) {
550 EXPLAIN(val1->name, change, STRUCTURAL_CHANGE, "name change",
551 val1->name, val2->name);
552 change = max(change, STRUCTURAL_CHANGE);
553 safe_free_str(val1->name);
554 val1->name = safe_strdup(val2->name);
556 if (safe_strcmp(val1->value, val2->value)) {
557 EXPLAIN(val1->name, change, VISIBLE_CHANGE, "value change",
558 val1->value, val2->value);
559 change = max(change, VISIBLE_CHANGE);
560 safe_free_str(val1->value);
561 val1->value = safe_strdup(val2->value);
563 if (safe_strcmp(val1->key, val2->key)) {
564 EXPLAIN(val1->name, change, VISIBLE_CHANGE, "key change",
565 val1->key, val2->key);
566 change = max(change, VISIBLE_CHANGE);
567 safe_free_str(val1->key);
568 val1->key = safe_strdup(val2->key);
570 if (val1->accel != val2->accel) {
571 EXPLAIN(val1->name, change, VISIBLE_CHANGE,
572 "accelerator change", val1->accel, val2->accel);
573 change = max(change, VISIBLE_CHANGE);
574 val1->accel = val2->accel;
576 if (val1->enabled != val2->enabled) {
577 EXPLAIN(val1->name, change, VISIBLE_CHANGE, "enablement change",
578 val1->enabled, val2->enabled);
579 change = max(change, VISIBLE_CHANGE);
580 val1->enabled = val2->enabled;
582 if (val1->selected != val2->selected) {
583 EXPLAIN(val1->name, change, VISIBLE_CHANGE, "selection change",
584 val1->selected, val2->selected);
585 change = max(change, VISIBLE_CHANGE);
586 val1->selected = val2->selected;
588 if (val1->call_data != val2->call_data) {
589 EXPLAIN(val1->name, change, INVISIBLE_CHANGE,
590 "call-data change", val1->call_data, val2->call_data);
591 change = max(change, INVISIBLE_CHANGE);
592 val1->call_data = val2->call_data;
595 if (merge_widget_value_args(val1, val2)) {
596 EXPLAIN(val1->name, change, VISIBLE_CHANGE, "widget change", 0,
598 change = max(change, VISIBLE_CHANGE);
602 #ifdef NEED_SCROLLBARS
603 if (merge_scrollbar_values(val1, val2)) {
604 EXPLAIN(val1->name, change, VISIBLE_CHANGE, "scrollbar change",
606 change = max(change, VISIBLE_CHANGE);
612 merge_widget_value(val1->contents, val2->contents,
615 if (val1->contents && !merged_contents) {
616 EXPLAIN(val1->name, change, INVISIBLE_CHANGE,
617 "(contents gone)", 0, 0);
618 change = max(change, INVISIBLE_CHANGE);
619 } else if (merged_contents
620 && merged_contents->change != NO_CHANGE) {
621 EXPLAIN(val1->name, change, INVISIBLE_CHANGE,
622 "(contents change)", 0, 0);
623 change = max(change, INVISIBLE_CHANGE);
626 val1->contents = merged_contents;
629 merged_next = merge_widget_value(val1->next, val2->next, level);
631 if (val1->next && !merged_next) {
632 EXPLAIN(val1->name, change, STRUCTURAL_CHANGE,
633 "(following gone)", 0, 0);
634 change = max(change, STRUCTURAL_CHANGE);
635 } else if (merged_next) {
636 if (merged_next->change) {
637 EXPLAIN(val1->name, change, merged_next->change,
638 "(following change)", 0, 0);
640 change = max(change, merged_next->change);
643 val1->next = merged_next;
645 val1->change = change;
647 if (change > NO_CHANGE && val1->toolkit_data) {
648 if (val1->free_toolkit_data)
649 XtFree((char *)val1->toolkit_data);
650 val1->toolkit_data = NULL;
656 /* modifying the widgets */
657 static Widget name_to_widget(widget_instance * instance, const char *name)
659 Widget widget = NULL;
661 if (!instance->widget)
664 if (!strcmp(XtName(instance->widget), name))
665 widget = instance->widget;
667 int length = strlen(name) + 2;
668 char *real_name = (char *)alloca(length);
670 strcpy(real_name + 1, name);
672 widget = XtNameToWidget(instance->widget, real_name);
678 set_one_value(widget_instance * instance, widget_value * val, Boolean deep_p)
680 Widget widget = name_to_widget(instance, val->name);
684 if (lw_lucid_widget_p(instance->widget))
685 xlw_update_one_widget(instance, widget, val, deep_p);
688 if (lw_motif_widget_p(instance->widget))
689 xm_update_one_widget(instance, widget, val, deep_p);
692 if (lw_xaw_widget_p(instance->widget))
693 xaw_update_one_widget(instance, widget, val, deep_p);
699 update_one_widget_instance(widget_instance * instance, Boolean deep_p)
703 if (!instance->widget)
704 /* the widget was destroyed */
707 for (val = instance->info->val; val; val = val->next)
708 if (val->change != NO_CHANGE)
709 set_one_value(instance, val, deep_p);
712 static void update_all_widget_values(widget_info * info, Boolean deep_p)
714 widget_instance *instance;
717 for (instance = info->instances; instance; instance = instance->next)
718 update_one_widget_instance(instance, deep_p);
720 for (val = info->val; val; val = val->next) {
721 val->change = NO_CHANGE;
723 val->args->args_changed = False;
727 void lw_modify_all_widgets(LWLIB_ID id, widget_value * val, Boolean deep_p)
729 widget_info *info = get_widget_info(id, False);
730 widget_value *new_val;
731 widget_value *next_new_val;
740 for (new_val = val; new_val; new_val = new_val->next) {
741 next_new_val = new_val->next;
742 new_val->next = NULL;
744 for (prev = NULL, cur = info->val; cur;
745 prev = cur, cur = cur->next)
746 if (!strcmp(cur->name, new_val->name)) {
751 merge_widget_value(cur, new_val,
754 prev->next = cur ? cur : next;
756 info->val = cur ? cur : next;
762 /* Could not find it, add it */
765 copy_widget_value_tree(new_val,
769 copy_widget_value_tree(new_val,
772 new_val->next = next_new_val;
775 update_all_widget_values(info, deep_p);
778 /* creating the widgets */
780 static void initialize_widget_instance(widget_instance * instance)
784 for (val = instance->info->val; val; val = val->next)
785 val->change = STRUCTURAL_CHANGE;
787 update_one_widget_instance(instance, True);
789 for (val = instance->info->val; val; val = val->next) {
790 val->change = NO_CHANGE;
792 val->args->args_changed = False;
796 /* strcasecmp() is not sufficiently portable or standard,
797 and it's easier just to write our own. */
798 static int ascii_strcasecmp(const char *s1, const char *s2)
803 if (c1 >= 'A' && c1 <= 'Z')
805 if (c2 >= 'A' && c2 <= 'Z')
814 static widget_creation_function
815 find_in_table(const char *type, const widget_creation_entry table[])
817 const widget_creation_entry *cur;
818 for (cur = table; cur->type; cur++)
819 if (!ascii_strcasecmp(type, cur->type))
820 return cur->function;
824 static Boolean dialog_spec_p(const char *name)
826 /* return True if name matches [EILPQeilpq][1-9][Bb] or
827 [EILPQeilpq][1-9][Bb][Rr][1-9] */
842 if (name[1] >= '0' && name[1] <= '9') {
843 if (name[2] != 'B' && name[2] != 'b')
847 if ((name[3] == 'T' || name[3] == 't') && !name[4])
849 if ((name[3] == 'R' || name[3] == 'r')
850 && name[4] >= '0' && name[4] <= '9' && !name[5])
861 static void instantiate_widget_instance(widget_instance * instance)
863 widget_creation_function function = NULL;
868 find_in_table(instance->info->type, xlw_creation_table);
873 find_in_table(instance->info->type, xm_creation_table);
878 find_in_table(instance->info->type, xaw_creation_table);
882 if (dialog_spec_p(instance->info->type)) {
883 #ifdef LWLIB_DIALOGS_MOTIF
885 function = xm_create_dialog;
887 #ifdef LWLIB_DIALOGS_ATHENA
889 function = xaw_create_dialog;
895 fprintf(stderr, "No creation function for widget type %s\n",
896 instance->info->type);
900 instance->widget = (*function) (instance);
902 if (!instance->widget)
905 /* XtRealizeWidget (instance->widget); */
909 lw_register_widget(const char *type, const char *name,
910 LWLIB_ID id, widget_value * val,
911 lw_callback pre_activate_cb, lw_callback selection_cb,
912 lw_callback post_activate_cb)
914 if (!get_widget_info(id, False))
915 allocate_widget_info(type, name, id, val, pre_activate_cb,
916 selection_cb, post_activate_cb);
919 Widget lw_get_widget(LWLIB_ID id, Widget parent, Boolean pop_up_p)
921 widget_instance *instance = find_instance(id, parent, pop_up_p);
922 return instance ? instance->widget : NULL;
925 Widget lw_make_widget(LWLIB_ID id, Widget parent, Boolean pop_up_p)
927 widget_instance *instance = find_instance(id, parent, pop_up_p);
930 widget_info *info = get_widget_info(id, False);
933 instance = allocate_widget_instance(info, parent, pop_up_p);
934 initialize_widget_instance(instance);
936 if (!instance->widget)
938 return instance->widget;
942 lw_create_widget(const char *type, const char *name,
943 LWLIB_ID id, widget_value * val,
944 Widget parent, Boolean pop_up_p, lw_callback pre_activate_cb,
945 lw_callback selection_cb, lw_callback post_activate_cb)
947 lw_register_widget(type, name, id, val, pre_activate_cb, selection_cb,
949 return lw_make_widget(id, parent, pop_up_p);
952 /* destroying the widgets */
953 static void destroy_one_instance(widget_instance * instance)
955 /* Remove the destroy callback on the widget; that callback will try to
956 dereference the instance object (to set its widget slot to 0, since the
957 widget is dead.) Since the instance is now dead, we don't have to worry
958 about the fact that its widget is dead too.
960 This happens in the Phase2Destroy of the widget, so this callback would
961 not have been run until arbitrarily long after the instance was freed.
963 if (instance->widget)
964 XtRemoveCallback(instance->widget, XtNdestroyCallback,
965 mark_widget_destroyed, (XtPointer) instance);
967 if (instance->widget) {
968 /* The else are pretty tricky here, including the empty statement
969 at the end because it would be very bad to destroy a widget
972 if (lw_lucid_widget_p(instance->widget))
973 xlw_destroy_instance(instance);
977 if (lw_motif_widget_p(instance->widget))
978 xm_destroy_instance(instance);
982 if (lw_xaw_widget_p(instance->widget))
983 xaw_destroy_instance(instance);
987 /* do not remove the empty statement */
992 free_widget_instance(instance);
995 void lw_destroy_widget(Widget w)
997 widget_instance *instance = get_widget_instance(w, True);
1000 widget_info *info = instance->info;
1001 /* instance has already been removed from the list; free it */
1002 destroy_one_instance(instance);
1003 /* if there are no instances left, free the info too */
1004 if (!info->instances)
1005 lw_destroy_all_widgets(info->id);
1009 void lw_destroy_all_widgets(LWLIB_ID id)
1011 widget_info *info = get_widget_info(id, True);
1012 widget_instance *instance;
1013 widget_instance *next;
1016 for (instance = info->instances; instance;) {
1017 next = instance->next;
1018 destroy_one_instance(instance);
1021 free_widget_info(info);
1025 void lw_destroy_everything(void)
1027 while (all_widget_info)
1028 lw_destroy_all_widgets(all_widget_info->id);
1031 void lw_destroy_all_pop_ups(void)
1035 widget_instance *instance;
1037 for (info = all_widget_info; info; info = next) {
1039 instance = info->instances;
1040 if (instance && instance->pop_up_p)
1041 lw_destroy_all_widgets(info->id);
1045 Widget lw_raise_all_pop_up_widgets(void)
1048 widget_instance *instance;
1049 Widget result = NULL;
1051 for (info = all_widget_info; info; info = info->next)
1052 for (instance = info->instances; instance;
1053 instance = instance->next)
1054 if (instance->pop_up_p) {
1055 Widget widget = instance->widget;
1057 if (XtIsManaged(widget)
1059 /* What a complete load of crap!!!!
1060 When a dialogShell is on the screen, it is not managed!
1063 (lw_motif_widget_p(instance->widget)
1065 XtIsManaged(first_child(widget)))
1070 XMapRaised(XtDisplay(widget),
1078 static void lw_pop_all_widgets(LWLIB_ID id, Boolean up)
1080 widget_info *info = get_widget_info(id, False);
1081 widget_instance *instance;
1084 for (instance = info->instances; instance;
1085 instance = instance->next)
1086 if (instance->pop_up_p && instance->widget) {
1088 if (lw_lucid_widget_p(instance->widget)) {
1089 XtRealizeWidget(instance->widget);
1090 xlw_pop_instance(instance, up);
1094 if (lw_motif_widget_p(instance->widget)) {
1095 XtRealizeWidget(instance->widget);
1096 xm_pop_instance(instance, up);
1100 if (lw_xaw_widget_p(instance->widget)) {
1101 XtRealizeWidget(XtParent
1102 (instance->widget));
1103 XtRealizeWidget(instance->widget);
1104 xaw_pop_instance(instance, up);
1110 void lw_pop_up_all_widgets(LWLIB_ID id)
1112 lw_pop_all_widgets(id, True);
1115 void lw_pop_down_all_widgets(LWLIB_ID id)
1117 lw_pop_all_widgets(id, False);
1120 void lw_popup_menu(Widget widget, XEvent * event)
1122 #ifdef LWLIB_MENUBARS_LUCID
1123 if (lw_lucid_widget_p(widget))
1124 xlw_popup_menu(widget, event);
1126 #ifdef LWLIB_MENUBARS_MOTIF
1127 if (lw_motif_widget_p(widget))
1128 xm_popup_menu(widget, event);
1130 #ifdef LWLIB_MENUBARS_ATHENA
1131 if (lw_xaw_widget_p(widget))
1132 xaw_popup_menu(widget, event); /* not implemented */
1136 /* get the values back */
1137 static Boolean get_one_value(widget_instance * instance, widget_value * val)
1139 Widget widget = name_to_widget(instance, val->name);
1143 if (lw_lucid_widget_p(instance->widget))
1144 xlw_update_one_value(instance, widget, val);
1147 if (lw_motif_widget_p(instance->widget))
1148 xm_update_one_value(instance, widget, val);
1151 if (lw_xaw_widget_p(instance->widget))
1152 xaw_update_one_value(instance, widget, val);
1159 Boolean lw_get_some_values(LWLIB_ID id, widget_value * val_out)
1161 widget_info *info = get_widget_info(id, False);
1162 widget_instance *instance;
1164 Boolean result = False;
1169 instance = info->instances;
1173 for (val = val_out; val; val = val->next)
1174 if (get_one_value(instance, val))
1180 widget_value *lw_get_all_values(LWLIB_ID id)
1182 widget_info *info = get_widget_info(id, False);
1183 widget_value *val = info->val;
1184 if (lw_get_some_values(id, val))
1190 /* internal function used by the library dependent implementation to get the
1191 widget_value for a given widget in an instance */
1192 widget_value *lw_get_widget_value_for_widget(widget_instance * instance,
1195 char *name = XtName(w);
1197 for (cur = instance->info->val; cur; cur = cur->next)
1198 if (!strcmp(cur->name, name))
1203 /* update other instances value when one thing changed */
1204 /* This function can be used as a an XtCallback for the widgets that get
1205 modified to update other instances of the widgets. Closure should be the
1208 lw_internal_update_other_instances(Widget widget, XtPointer closure,
1209 XtPointer call_data)
1211 /* To forbid recursive calls */
1212 static Boolean updating;
1214 widget_instance *instance = (widget_instance *) closure;
1215 char *name = XtName(widget);
1217 widget_instance *cur;
1220 /* never recurse as this could cause infinite recursions. */
1224 /* protect against the widget being destroyed */
1225 if (XtWidgetBeingDestroyedP(widget))
1228 /* Return immediately if there are no other instances */
1229 info = instance->info;
1230 if (!info->instances->next)
1235 for (val = info->val; val && strcmp(val->name, name); val = val->next) ;
1237 if (val && get_one_value(instance, val))
1238 for (cur = info->instances; cur; cur = cur->next)
1239 if (cur != instance)
1240 set_one_value(cur, val, True);
1247 LWLIB_ID lw_get_widget_id(Widget w)
1249 widget_instance *instance = get_widget_instance(w, False);
1251 return instance ? instance->info->id : 0;
1254 /* set the keyboard focus */
1255 void lw_set_keyboard_focus(Widget parent, Widget w)
1257 #if defined(NEED_MOTIF) && !defined(LESSTIF_VERSION)
1258 /* This loses with Lesstif v0.75a */
1259 xm_set_keyboard_focus(parent, w);
1261 XtSetKeyboardFocus(parent, w);
1266 static void show_one_widget_busy(Widget w, Boolean flag)
1268 Pixel foreground = 0;
1269 Pixel background = 1;
1270 Widget widget_to_invert = XtNameToWidget(w, "*sheet");
1273 if (!widget_to_invert)
1274 widget_to_invert = w;
1276 XtSetArg(al[0], XtNforeground, &foreground);
1277 XtSetArg(al[1], XtNbackground, &background);
1278 XtGetValues(widget_to_invert, al, 2);
1280 XtSetArg(al[0], XtNforeground, background);
1281 XtSetArg(al[1], XtNbackground, foreground);
1282 XtSetValues(widget_to_invert, al, 2);
1285 void lw_show_busy(Widget w, Boolean busy)
1287 widget_instance *instance = get_widget_instance(w, False);
1289 widget_instance *next;
1292 info = instance->info;
1293 if (info->busy != busy) {
1294 for (next = info->instances; next; next = next->next)
1296 show_one_widget_busy(next->widget,
1303 void lw_add_value_args_to_args(widget_value * wv, ArgList addto, int *offset)
1306 if (wv->args && wv->args->nargs) {
1307 for (i = 0; i < wv->args->nargs; i++) {
1308 addto[i + *offset] = wv->args->args[i];
1310 *offset += wv->args->nargs;
1314 XtArgVal lw_get_value_arg(widget_value * wv, String name)
1318 for (i = 0; i < wv->args->nargs; i++) {
1319 if (!strcmp(wv->args->args[i].name, name)) {
1320 return wv->args->args[i].value;
1324 return (XtArgVal) 0;
1327 void lw_add_widget_value_arg(widget_value * wv, String name, XtArgVal value)
1331 wv->args = (widget_args *) xmalloc(sizeof(widget_args));
1332 memset(wv->args, '\0', sizeof(widget_args));
1333 wv->args->ref_count = 1;
1334 wv->args->nargs = 0;
1335 wv->args->args = (ArgList) xmalloc(sizeof(Arg) * 10);
1336 memset(wv->args->args, '\0', sizeof(Arg) * 10);
1339 if (wv->args->nargs > 10)
1342 /* Register the change. */
1343 wv->args->args_changed = True;
1344 /* If the arg is already there then we must replace it. */
1345 for (i = 0; i < wv->args->nargs; i++) {
1346 if (!strcmp(wv->args->args[i].name, name)) {
1347 XtSetArg(wv->args->args[i], name, value);
1351 if (i >= wv->args->nargs) {
1352 XtSetArg(wv->args->args[wv->args->nargs], name, value);
1357 static void free_widget_value_args(widget_value * wv)
1360 if (--wv->args->ref_count <= 0) {
1361 #ifdef LWLIB_WIDGETS_MOTIF
1363 for (i = 0; i < wv->args->nargs; i++) {
1365 (wv->args->args[i].name, XmNfontList))
1366 XmFontListFree((XmFontList) wv->args->
1370 xfree(wv->args->args);
1377 void lw_copy_widget_value_args(widget_value * val, widget_value * copy)
1379 if (val == copy || val->args == copy->args)
1383 free_widget_value_args(copy);
1387 copy->args = val->args;
1388 copy->args->ref_count++;
1392 /* Remove %_ and convert %% to %. We can do this in-place because we
1393 are always shortening, never lengthening, the string. */
1394 void lw_remove_accelerator_spec(char *val)
1396 char *foo = val, *bar = val;
1399 if (*bar == '%' && *(bar + 1) == '_')
1401 else if (*bar == '%' && *(bar + 1) == '%') {