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 ssize_t len = strlen(s)+1;
101 result = (char *)xmalloc(len);
104 strncpy(result, s, len);
108 static inline void safe_free_str(char *s)
115 static widget_value *widget_value_free_list = 0;
117 widget_value *malloc_widget_value(void)
120 if (widget_value_free_list) {
121 wv = widget_value_free_list;
122 widget_value_free_list = wv->free_list;
125 wv = (widget_value *) xmalloc(sizeof(widget_value));
128 memset(wv, '\0', sizeof(widget_value));
133 /* this is analogous to free(). It frees only what was allocated
134 by malloc_widget_value(), and no substructures.
136 void free_widget_value(widget_value * wv)
140 wv->free_list = widget_value_free_list;
141 widget_value_free_list = wv;
144 static void free_widget_value_contents(widget_value * wv)
153 /* #### - all of this 0xDEADBEEF stuff should be unnecessary
154 in production code... it should be conditionalized. */
155 wv->name = wv->value = wv->key = (char *)0xDEADBEEF;
157 if (wv->toolkit_data && wv->free_toolkit_data) {
158 XtFree((char *)wv->toolkit_data);
159 wv->toolkit_data = (void *)0xDEADBEEF;
161 #ifdef NEED_SCROLLBARS
162 if (wv->scrollbar_data) {
163 xfree(wv->scrollbar_data);
164 wv->scrollbar_data = NULL;
167 if (wv->contents && (wv->contents != (widget_value *) 1)) {
168 free_widget_value_tree(wv->contents);
169 wv->contents = (widget_value *) 0xDEADBEEF;
172 free_widget_value_args(wv);
175 free_widget_value_tree(wv->next);
176 wv->next = (widget_value *) 0xDEADBEEF;
180 void free_widget_value_tree(widget_value * wv)
185 free_widget_value_contents(wv);
186 free_widget_value(wv);
189 #ifdef NEED_SCROLLBARS
191 static void copy_scrollbar_values(widget_value * val, widget_value * copy)
193 if (!copy->scrollbar_data)
194 copy->scrollbar_data =
195 (scrollbar_values *) xmalloc(sizeof(scrollbar_values));
197 if (val->scrollbar_data)
198 *copy->scrollbar_data = *val->scrollbar_data;
200 memset(copy->scrollbar_data, '\0', sizeof(scrollbar_values));
204 * Return true if old->scrollbar_data were not equivalent
205 * to new->scrollbar_data.
207 static Boolean merge_scrollbar_values(widget_value * old, widget_value * new)
209 Boolean changed = False;
211 if (new->scrollbar_data && !old->scrollbar_data) {
212 copy_scrollbar_values(new, old);
214 } else if (!new->scrollbar_data && old->scrollbar_data) {
215 xfree(old->scrollbar_data);
216 old->scrollbar_data = NULL;
217 } else if (new->scrollbar_data && old->scrollbar_data) {
218 scrollbar_values *old_sb = old->scrollbar_data;
219 scrollbar_values *new_sb = new->scrollbar_data;
221 if ((old_sb->line_increment != new_sb->line_increment) ||
222 (old_sb->page_increment != new_sb->page_increment) ||
223 (old_sb->minimum != new_sb->minimum) ||
224 (old_sb->maximum != new_sb->maximum) ||
225 (old_sb->slider_size != new_sb->slider_size) ||
226 (old_sb->slider_position != new_sb->slider_position) ||
227 (old_sb->scrollbar_width != new_sb->scrollbar_width) ||
228 (old_sb->scrollbar_height != new_sb->scrollbar_height) ||
229 (old_sb->scrollbar_x != new_sb->scrollbar_x) ||
230 (old_sb->scrollbar_y != new_sb->scrollbar_y))
239 #endif /* NEED_SCROLLBARS */
243 * Return true if old->args was not equivalent
246 static Boolean merge_widget_value_args(widget_value * old, widget_value * new)
248 Boolean changed = False;
250 if (new->args && !old->args) {
251 lw_copy_widget_value_args(new, old);
254 /* Generally we don't want to lose values that are already in the
256 else if (!new->args && old->args) {
257 lw_copy_widget_value_args(old, new);
259 } else if (new->args && old->args && new->args != old->args) {
260 /* #### Do something more sensible here than just copying the
261 new values (like actually merging the values). */
262 lw_copy_widget_value_args(new, old);
264 } else if (new->args && new->args == old->args
265 && new->args->args_changed == True) {
271 #endif /* HAVE_WIDGETS */
273 /* Make a complete copy of a widget_value tree. Store CHANGE into
274 the widget_value tree's `change' field. */
276 widget_value *copy_widget_value_tree(widget_value * val, change_type change)
282 if (val == (widget_value *) 1)
285 copy = malloc_widget_value();
287 /* #### - don't seg fault *here* if out of memory. Menus will be
288 truncated inexplicably. */
289 copy->type = val->type;
290 copy->name = safe_strdup(val->name);
291 copy->value = safe_strdup(val->value);
292 copy->key = safe_strdup(val->key);
293 copy->accel = val->accel;
294 copy->enabled = val->enabled;
295 copy->selected = val->selected;
296 copy->edited = False;
297 copy->change = change;
298 copy->contents = copy_widget_value_tree(val->contents, change);
299 copy->call_data = val->call_data;
300 copy->next = copy_widget_value_tree(val->next, change);
301 copy->toolkit_data = NULL;
302 copy->free_toolkit_data = False;
304 lw_copy_widget_value_args(val, copy);
305 #ifdef NEED_SCROLLBARS
306 copy_scrollbar_values(val, copy);
312 /* This function is used to implement incremental menu construction. */
314 widget_value *replace_widget_value_tree(widget_value * node,
315 widget_value * newtree)
319 if (!node || !newtree)
323 copy = copy_widget_value_tree(newtree, STRUCTURAL_CHANGE);
325 free_widget_value_contents(node);
327 /* free the node, but not its contents. */
328 free_widget_value(copy);
333 static widget_info *allocate_widget_info(const char *type, const char *name,
334 LWLIB_ID id, widget_value * val,
335 lw_callback pre_activate_cb,
336 lw_callback selection_cb,
337 lw_callback post_activate_cb)
339 widget_info *info = (widget_info *) xmalloc(sizeof(widget_info));
340 info->type = safe_strdup(type);
341 info->name = safe_strdup(name);
343 info->val = copy_widget_value_tree(val, STRUCTURAL_CHANGE);
345 info->pre_activate_cb = pre_activate_cb;
346 info->selection_cb = selection_cb;
347 info->post_activate_cb = post_activate_cb;
348 info->instances = NULL;
350 info->next = all_widget_info;
351 all_widget_info = info;
356 static void free_widget_info(widget_info * info)
358 safe_free_str(info->type);
359 safe_free_str(info->name);
360 free_widget_value_tree(info->val);
361 memset(info, '\0', sizeof(widget_info));
366 mark_widget_destroyed(Widget widget, XtPointer closure, XtPointer call_data)
368 widget_instance *instance = (widget_instance *) closure;
370 /* be very conservative */
371 if (instance->widget == widget)
372 instance->widget = NULL;
375 static widget_instance *allocate_widget_instance(widget_info * info,
379 widget_instance *instance =
380 (widget_instance *) xmalloc(sizeof(widget_instance));
381 instance->parent = parent;
382 instance->pop_up_p = pop_up_p;
383 instance->info = info;
384 instance->next = info->instances;
385 info->instances = instance;
387 instantiate_widget_instance(instance);
389 XtAddCallback(instance->widget, XtNdestroyCallback,
390 mark_widget_destroyed, (XtPointer) instance);
394 static void free_widget_instance(widget_instance * instance)
396 memset(instance, '\0', sizeof(widget_instance));
400 static widget_info *get_widget_info(LWLIB_ID id, Boolean remove_p)
404 for (prev = NULL, info = all_widget_info;
405 info; prev = info, info = info->next)
406 if (info->id == id) {
409 prev->next = info->next;
411 all_widget_info = info->next;
418 /* Internal function used by the library dependent implementation to get the
419 widget_value for a given widget in an instance */
420 widget_info *lw_get_widget_info(LWLIB_ID id)
422 return get_widget_info(id, 0);
426 map_widget_values(widget_value * value, int (*mapfunc) (widget_value * value,
433 retval = map_widget_values(value->contents, mapfunc, closure);
438 retval = map_widget_values(value->next, mapfunc, closure);
442 return (mapfunc) (value, closure);
446 lw_map_widget_values(LWLIB_ID id, int (*mapfunc) (widget_value * value,
447 void *closure), void *closure)
449 widget_info *info = get_widget_info(id, 0);
454 return map_widget_values(info->val, mapfunc, closure);
458 static widget_instance *get_widget_instance(Widget widget, Boolean remove_p)
461 widget_instance *instance;
462 widget_instance *prev;
463 for (info = all_widget_info; info; info = info->next)
464 for (prev = NULL, instance = info->instances;
465 instance; prev = instance, instance = instance->next)
466 if (instance->widget == widget) {
469 prev->next = instance->next;
476 return (widget_instance *) 0;
479 static widget_instance *find_instance(LWLIB_ID id, Widget parent,
482 widget_info *info = get_widget_info(id, False);
483 widget_instance *instance;
486 for (instance = info->instances; instance;
487 instance = instance->next)
488 if (instance->parent == parent
489 && instance->pop_up_p == pop_up_p)
495 /* utility function for widget_value */
496 static Boolean safe_strcmp(const char *s1, const char *s2)
500 return (s1 && s2) ? strcmp(s1, s2) : s1 ? False : !!s2;
503 static change_type max(change_type i1, change_type i2)
505 return (int)i1 > (int)i2 ? i1 : i2;
509 # define EXPLAIN(name, oc, nc, desc, a1, a2) \
510 printf ("Change: \"%s\"\tmax(%s=%d,%s=%d)\t%s %d %d\n", \
512 (oc == NO_CHANGE ? "none" : \
513 (oc == INVISIBLE_CHANGE ? "invisible" : \
514 (oc == VISIBLE_CHANGE ? "visible" : \
515 (oc == STRUCTURAL_CHANGE ? "structural" : "???")))), \
517 (nc == NO_CHANGE ? "none" : \
518 (nc == INVISIBLE_CHANGE ? "invisible" : \
519 (nc == VISIBLE_CHANGE ? "visible" : \
520 (nc == STRUCTURAL_CHANGE ? "structural" : "???")))), \
523 # define EXPLAIN(name, oc, nc, desc, a1, a2)
526 static widget_value *merge_widget_value(widget_value * val1,
527 widget_value * val2, int level)
530 widget_value *merged_next;
531 widget_value *merged_contents;
535 return copy_widget_value_tree(val2, STRUCTURAL_CHANGE);
540 free_widget_value_tree(val1);
546 if (val1->type != val2->type) {
547 EXPLAIN(val1->name, change, STRUCTURAL_CHANGE, "type change",
548 val1->type, val2->type);
549 change = max(change, STRUCTURAL_CHANGE);
550 val1->type = val2->type;
552 if (safe_strcmp(val1->name, val2->name)) {
553 EXPLAIN(val1->name, change, STRUCTURAL_CHANGE, "name change",
554 val1->name, val2->name);
555 change = max(change, STRUCTURAL_CHANGE);
556 safe_free_str(val1->name);
557 val1->name = safe_strdup(val2->name);
559 if (safe_strcmp(val1->value, val2->value)) {
560 EXPLAIN(val1->name, change, VISIBLE_CHANGE, "value change",
561 val1->value, val2->value);
562 change = max(change, VISIBLE_CHANGE);
563 safe_free_str(val1->value);
564 val1->value = safe_strdup(val2->value);
566 if (safe_strcmp(val1->key, val2->key)) {
567 EXPLAIN(val1->name, change, VISIBLE_CHANGE, "key change",
568 val1->key, val2->key);
569 change = max(change, VISIBLE_CHANGE);
570 safe_free_str(val1->key);
571 val1->key = safe_strdup(val2->key);
573 if (val1->accel != val2->accel) {
574 EXPLAIN(val1->name, change, VISIBLE_CHANGE,
575 "accelerator change", val1->accel, val2->accel);
576 change = max(change, VISIBLE_CHANGE);
577 val1->accel = val2->accel;
579 if (val1->enabled != val2->enabled) {
580 EXPLAIN(val1->name, change, VISIBLE_CHANGE, "enablement change",
581 val1->enabled, val2->enabled);
582 change = max(change, VISIBLE_CHANGE);
583 val1->enabled = val2->enabled;
585 if (val1->selected != val2->selected) {
586 EXPLAIN(val1->name, change, VISIBLE_CHANGE, "selection change",
587 val1->selected, val2->selected);
588 change = max(change, VISIBLE_CHANGE);
589 val1->selected = val2->selected;
591 if (val1->call_data != val2->call_data) {
592 EXPLAIN(val1->name, change, INVISIBLE_CHANGE,
593 "call-data change", val1->call_data, val2->call_data);
594 change = max(change, INVISIBLE_CHANGE);
595 val1->call_data = val2->call_data;
598 if (merge_widget_value_args(val1, val2)) {
599 EXPLAIN(val1->name, change, VISIBLE_CHANGE, "widget change", 0,
601 change = max(change, VISIBLE_CHANGE);
605 #ifdef NEED_SCROLLBARS
606 if (merge_scrollbar_values(val1, val2)) {
607 EXPLAIN(val1->name, change, VISIBLE_CHANGE, "scrollbar change",
609 change = max(change, VISIBLE_CHANGE);
615 merge_widget_value(val1->contents, val2->contents,
618 if (val1->contents && !merged_contents) {
619 EXPLAIN(val1->name, change, INVISIBLE_CHANGE,
620 "(contents gone)", 0, 0);
621 change = max(change, INVISIBLE_CHANGE);
622 } else if (merged_contents
623 && merged_contents->change != NO_CHANGE) {
624 EXPLAIN(val1->name, change, INVISIBLE_CHANGE,
625 "(contents change)", 0, 0);
626 change = max(change, INVISIBLE_CHANGE);
629 val1->contents = merged_contents;
632 merged_next = merge_widget_value(val1->next, val2->next, level);
634 if (val1->next && !merged_next) {
635 EXPLAIN(val1->name, change, STRUCTURAL_CHANGE,
636 "(following gone)", 0, 0);
637 change = max(change, STRUCTURAL_CHANGE);
638 } else if (merged_next) {
639 if (merged_next->change) {
640 EXPLAIN(val1->name, change, merged_next->change,
641 "(following change)", 0, 0);
643 change = max(change, merged_next->change);
646 val1->next = merged_next;
648 val1->change = change;
650 if (change > NO_CHANGE && val1->toolkit_data) {
651 if (val1->free_toolkit_data)
652 XtFree((char *)val1->toolkit_data);
653 val1->toolkit_data = NULL;
659 /* modifying the widgets */
660 static Widget name_to_widget(widget_instance * instance, const char *name)
662 Widget widget = NULL;
664 if (!instance->widget)
667 if (!strcmp(XtName(instance->widget), name))
668 widget = instance->widget;
670 int length = strlen(name) + 2;
671 char *real_name = (char *)alloca(length);
673 strcpy(real_name + 1, name);
675 widget = XtNameToWidget(instance->widget, real_name);
681 set_one_value(widget_instance * instance, widget_value * val, Boolean deep_p)
683 Widget widget = name_to_widget(instance, val->name);
687 if (lw_lucid_widget_p(instance->widget))
688 xlw_update_one_widget(instance, widget, val, deep_p);
691 if (lw_motif_widget_p(instance->widget))
692 xm_update_one_widget(instance, widget, val, deep_p);
695 if (lw_xaw_widget_p(instance->widget))
696 xaw_update_one_widget(instance, widget, val, deep_p);
702 update_one_widget_instance(widget_instance * instance, Boolean deep_p)
706 if (!instance->widget)
707 /* the widget was destroyed */
710 for (val = instance->info->val; val; val = val->next)
711 if (val->change != NO_CHANGE)
712 set_one_value(instance, val, deep_p);
715 static void update_all_widget_values(widget_info * info, Boolean deep_p)
717 widget_instance *instance;
720 for (instance = info->instances; instance; instance = instance->next)
721 update_one_widget_instance(instance, deep_p);
723 for (val = info->val; val; val = val->next) {
724 val->change = NO_CHANGE;
726 val->args->args_changed = False;
730 void lw_modify_all_widgets(LWLIB_ID id, widget_value * val, Boolean deep_p)
732 widget_info *info = get_widget_info(id, False);
733 widget_value *new_val;
734 widget_value *next_new_val;
743 for (new_val = val; new_val; new_val = new_val->next) {
744 next_new_val = new_val->next;
745 new_val->next = NULL;
747 for (prev = NULL, cur = info->val; cur;
748 prev = cur, cur = cur->next)
749 if (!strcmp(cur->name, new_val->name)) {
754 merge_widget_value(cur, new_val,
757 prev->next = cur ? cur : next;
759 info->val = cur ? cur : next;
765 /* Could not find it, add it */
768 copy_widget_value_tree(new_val,
772 copy_widget_value_tree(new_val,
775 new_val->next = next_new_val;
778 update_all_widget_values(info, deep_p);
781 /* creating the widgets */
783 static void initialize_widget_instance(widget_instance * instance)
787 for (val = instance->info->val; val; val = val->next)
788 val->change = STRUCTURAL_CHANGE;
790 update_one_widget_instance(instance, True);
792 for (val = instance->info->val; val; val = val->next) {
793 val->change = NO_CHANGE;
795 val->args->args_changed = False;
799 /* strcasecmp() is not sufficiently portable or standard,
800 and it's easier just to write our own. */
801 static int ascii_strcasecmp(const char *s1, const char *s2)
806 if (c1 >= 'A' && c1 <= 'Z')
808 if (c2 >= 'A' && c2 <= 'Z')
817 static widget_creation_function
818 find_in_table(const char *type, const widget_creation_entry table[])
820 const widget_creation_entry *cur;
821 for (cur = table; cur->type; cur++)
822 if (!ascii_strcasecmp(type, cur->type))
823 return cur->function;
827 static Boolean dialog_spec_p(const char *name)
829 /* return True if name matches [EILPQeilpq][1-9][Bb] or
830 [EILPQeilpq][1-9][Bb][Rr][1-9] */
845 if (name[1] >= '0' && name[1] <= '9') {
846 if (name[2] != 'B' && name[2] != 'b')
850 if ((name[3] == 'T' || name[3] == 't') && !name[4])
852 if ((name[3] == 'R' || name[3] == 'r')
853 && name[4] >= '0' && name[4] <= '9' && !name[5])
864 static void instantiate_widget_instance(widget_instance * instance)
866 widget_creation_function function = NULL;
871 find_in_table(instance->info->type, xlw_creation_table);
876 find_in_table(instance->info->type, xm_creation_table);
881 find_in_table(instance->info->type, xaw_creation_table);
885 if (dialog_spec_p(instance->info->type)) {
886 #ifdef LWLIB_DIALOGS_MOTIF
888 function = xm_create_dialog;
890 #ifdef LWLIB_DIALOGS_ATHENA
892 function = xaw_create_dialog;
898 fprintf(stderr, "No creation function for widget type %s\n",
899 instance->info->type);
902 instance->widget = (*function) (instance);
905 if (!instance->widget)
908 /* XtRealizeWidget (instance->widget); */
912 lw_register_widget(const char *type, const char *name,
913 LWLIB_ID id, widget_value * val,
914 lw_callback pre_activate_cb, lw_callback selection_cb,
915 lw_callback post_activate_cb)
917 if (!get_widget_info(id, False))
918 allocate_widget_info(type, name, id, val, pre_activate_cb,
919 selection_cb, post_activate_cb);
922 Widget lw_get_widget(LWLIB_ID id, Widget parent, Boolean pop_up_p)
924 widget_instance *instance = find_instance(id, parent, pop_up_p);
925 return instance ? instance->widget : NULL;
928 Widget lw_make_widget(LWLIB_ID id, Widget parent, Boolean pop_up_p)
930 widget_instance *instance = find_instance(id, parent, pop_up_p);
933 widget_info *info = get_widget_info(id, False);
936 instance = allocate_widget_instance(info, parent, pop_up_p);
937 initialize_widget_instance(instance);
939 if (!instance->widget)
941 return instance->widget;
945 lw_create_widget(const char *type, const char *name,
946 LWLIB_ID id, widget_value * val,
947 Widget parent, Boolean pop_up_p, lw_callback pre_activate_cb,
948 lw_callback selection_cb, lw_callback post_activate_cb)
950 lw_register_widget(type, name, id, val, pre_activate_cb, selection_cb,
952 return lw_make_widget(id, parent, pop_up_p);
955 /* destroying the widgets */
956 static void destroy_one_instance(widget_instance * instance)
958 /* Remove the destroy callback on the widget; that callback will try to
959 dereference the instance object (to set its widget slot to 0, since the
960 widget is dead.) Since the instance is now dead, we don't have to worry
961 about the fact that its widget is dead too.
963 This happens in the Phase2Destroy of the widget, so this callback would
964 not have been run until arbitrarily long after the instance was freed.
966 if (instance->widget)
967 XtRemoveCallback(instance->widget, XtNdestroyCallback,
968 mark_widget_destroyed, (XtPointer) instance);
970 if (instance->widget) {
971 /* The else are pretty tricky here, including the empty statement
972 at the end because it would be very bad to destroy a widget
975 if (lw_lucid_widget_p(instance->widget))
976 xlw_destroy_instance(instance);
980 if (lw_motif_widget_p(instance->widget))
981 xm_destroy_instance(instance);
985 if (lw_xaw_widget_p(instance->widget))
986 xaw_destroy_instance(instance);
990 /* do not remove the empty statement */
995 free_widget_instance(instance);
998 void lw_destroy_widget(Widget w)
1000 widget_instance *instance = get_widget_instance(w, True);
1003 widget_info *info = instance->info;
1004 /* instance has already been removed from the list; free it */
1005 destroy_one_instance(instance);
1006 /* if there are no instances left, free the info too */
1007 if (!info->instances)
1008 lw_destroy_all_widgets(info->id);
1012 void lw_destroy_all_widgets(LWLIB_ID id)
1014 widget_info *info = get_widget_info(id, True);
1015 widget_instance *instance;
1016 widget_instance *next;
1019 for (instance = info->instances; instance;) {
1020 next = instance->next;
1021 destroy_one_instance(instance);
1024 free_widget_info(info);
1028 void lw_destroy_everything(void)
1030 while (all_widget_info)
1031 lw_destroy_all_widgets(all_widget_info->id);
1034 void lw_destroy_all_pop_ups(void)
1038 widget_instance *instance;
1040 for (info = all_widget_info; info; info = next) {
1042 instance = info->instances;
1043 if (instance && instance->pop_up_p)
1044 lw_destroy_all_widgets(info->id);
1048 Widget lw_raise_all_pop_up_widgets(void)
1051 widget_instance *instance;
1052 Widget result = NULL;
1054 for (info = all_widget_info; info; info = info->next)
1055 for (instance = info->instances; instance;
1056 instance = instance->next)
1057 if (instance->pop_up_p) {
1058 Widget widget = instance->widget;
1060 if (XtIsManaged(widget)
1062 /* What a complete load of crap!!!!
1063 When a dialogShell is on the screen, it is not managed!
1066 (lw_motif_widget_p(instance->widget)
1068 XtIsManaged(first_child(widget)))
1073 XMapRaised(XtDisplay(widget),
1081 static void lw_pop_all_widgets(LWLIB_ID id, Boolean up)
1083 widget_info *info = get_widget_info(id, False);
1084 widget_instance *instance;
1087 for (instance = info->instances; instance;
1088 instance = instance->next)
1089 if (instance->pop_up_p && instance->widget) {
1091 if (lw_lucid_widget_p(instance->widget)) {
1092 XtRealizeWidget(instance->widget);
1093 xlw_pop_instance(instance, up);
1097 if (lw_motif_widget_p(instance->widget)) {
1098 XtRealizeWidget(instance->widget);
1099 xm_pop_instance(instance, up);
1103 if (lw_xaw_widget_p(instance->widget)) {
1104 XtRealizeWidget(XtParent
1105 (instance->widget));
1106 XtRealizeWidget(instance->widget);
1107 xaw_pop_instance(instance, up);
1113 void lw_pop_up_all_widgets(LWLIB_ID id)
1115 lw_pop_all_widgets(id, True);
1118 void lw_pop_down_all_widgets(LWLIB_ID id)
1120 lw_pop_all_widgets(id, False);
1123 void lw_popup_menu(Widget widget, XEvent * event)
1125 #ifdef LWLIB_MENUBARS_LUCID
1126 if (lw_lucid_widget_p(widget))
1127 xlw_popup_menu(widget, event);
1129 #ifdef LWLIB_MENUBARS_MOTIF
1130 if (lw_motif_widget_p(widget))
1131 xm_popup_menu(widget, event);
1133 #ifdef LWLIB_MENUBARS_ATHENA
1134 if (lw_xaw_widget_p(widget))
1135 xaw_popup_menu(widget, event); /* not implemented */
1139 /* get the values back */
1140 static Boolean get_one_value(widget_instance * instance, widget_value * val)
1142 Widget widget = name_to_widget(instance, val->name);
1146 if (lw_lucid_widget_p(instance->widget))
1147 xlw_update_one_value(instance, widget, val);
1150 if (lw_motif_widget_p(instance->widget))
1151 xm_update_one_value(instance, widget, val);
1154 if (lw_xaw_widget_p(instance->widget))
1155 xaw_update_one_value(instance, widget, val);
1162 Boolean lw_get_some_values(LWLIB_ID id, widget_value * val_out)
1164 widget_info *info = get_widget_info(id, False);
1165 widget_instance *instance;
1167 Boolean result = False;
1172 instance = info->instances;
1176 for (val = val_out; val; val = val->next)
1177 if (get_one_value(instance, val))
1183 widget_value *lw_get_all_values(LWLIB_ID id)
1185 widget_info *info = get_widget_info(id, False);
1186 widget_value *val = info->val;
1187 if (lw_get_some_values(id, val))
1193 /* internal function used by the library dependent implementation to get the
1194 widget_value for a given widget in an instance */
1195 widget_value *lw_get_widget_value_for_widget(widget_instance * instance,
1198 char *name = XtName(w);
1200 for (cur = instance->info->val; cur; cur = cur->next)
1201 if (!strcmp(cur->name, name))
1206 /* update other instances value when one thing changed */
1207 /* This function can be used as a an XtCallback for the widgets that get
1208 modified to update other instances of the widgets. Closure should be the
1211 lw_internal_update_other_instances(Widget widget, XtPointer closure,
1212 XtPointer call_data)
1214 /* To forbid recursive calls */
1215 static Boolean updating;
1217 widget_instance *instance = (widget_instance *) closure;
1218 char *name = XtName(widget);
1220 widget_instance *cur;
1223 /* never recurse as this could cause infinite recursions. */
1227 /* protect against the widget being destroyed */
1228 if (XtWidgetBeingDestroyedP(widget))
1231 /* Return immediately if there are no other instances */
1232 info = instance->info;
1233 if (!info->instances->next)
1238 for (val = info->val; val && strcmp(val->name, name); val = val->next) ;
1240 if (val && get_one_value(instance, val))
1241 for (cur = info->instances; cur; cur = cur->next)
1242 if (cur != instance)
1243 set_one_value(cur, val, True);
1250 LWLIB_ID lw_get_widget_id(Widget w)
1252 widget_instance *instance = get_widget_instance(w, False);
1254 return instance ? instance->info->id : 0;
1257 /* set the keyboard focus */
1258 void lw_set_keyboard_focus(Widget parent, Widget w)
1260 #if defined(NEED_MOTIF) && !defined(LESSTIF_VERSION)
1261 /* This loses with Lesstif v0.75a */
1262 xm_set_keyboard_focus(parent, w);
1264 XtSetKeyboardFocus(parent, w);
1269 static void show_one_widget_busy(Widget w, Boolean flag)
1271 Pixel foreground = 0;
1272 Pixel background = 1;
1273 Widget widget_to_invert = XtNameToWidget(w, "*sheet");
1276 if (!widget_to_invert)
1277 widget_to_invert = w;
1279 XtSetArg(al[0], XtNforeground, &foreground);
1280 XtSetArg(al[1], XtNbackground, &background);
1281 XtGetValues(widget_to_invert, al, 2);
1283 XtSetArg(al[0], XtNforeground, background);
1284 XtSetArg(al[1], XtNbackground, foreground);
1285 XtSetValues(widget_to_invert, al, 2);
1288 void lw_show_busy(Widget w, Boolean busy)
1290 widget_instance *instance = get_widget_instance(w, False);
1292 widget_instance *next;
1295 info = instance->info;
1296 if (info->busy != busy) {
1297 for (next = info->instances; next; next = next->next)
1299 show_one_widget_busy(next->widget,
1306 void lw_add_value_args_to_args(widget_value * wv, ArgList addto, int *offset)
1309 if (wv->args && wv->args->nargs) {
1310 for (i = 0; i < wv->args->nargs; i++) {
1311 addto[i + *offset] = wv->args->args[i];
1313 *offset += wv->args->nargs;
1317 XtArgVal lw_get_value_arg(widget_value * wv, String name)
1321 for (i = 0; i < wv->args->nargs; i++) {
1322 if (!strcmp(wv->args->args[i].name, name)) {
1323 return wv->args->args[i].value;
1327 return (XtArgVal) 0;
1330 void lw_add_widget_value_arg(widget_value * wv, String name, XtArgVal value)
1334 wv->args = (widget_args *) xmalloc(sizeof(widget_args));
1335 memset(wv->args, '\0', sizeof(widget_args));
1336 wv->args->ref_count = 1;
1337 wv->args->nargs = 0;
1338 wv->args->args = (ArgList) xmalloc(sizeof(Arg) * 10);
1339 memset(wv->args->args, '\0', sizeof(Arg) * 10);
1342 if (wv->args->nargs > 10)
1345 /* Register the change. */
1346 wv->args->args_changed = True;
1347 /* If the arg is already there then we must replace it. */
1348 for (i = 0; i < wv->args->nargs; i++) {
1349 if (!strcmp(wv->args->args[i].name, name)) {
1350 XtSetArg(wv->args->args[i], name, value);
1354 if (i >= wv->args->nargs) {
1355 XtSetArg(wv->args->args[wv->args->nargs], name, value);
1360 static void free_widget_value_args(widget_value * wv)
1363 if (--wv->args->ref_count <= 0) {
1364 #ifdef LWLIB_WIDGETS_MOTIF
1366 for (i = 0; i < wv->args->nargs; i++) {
1368 (wv->args->args[i].name, XmNfontList))
1369 XmFontListFree((XmFontList) wv->args->
1373 xfree(wv->args->args);
1380 void lw_copy_widget_value_args(widget_value * val, widget_value * copy)
1382 if (val == copy || val->args == copy->args)
1386 free_widget_value_args(copy);
1390 copy->args = val->args;
1391 copy->args->ref_count++;
1395 /* Remove %_ and convert %% to %. We can do this in-place because we
1396 are always shortening, never lengthening, the string. */
1397 void lw_remove_accelerator_spec(char *val)
1399 char *foo = val, *bar = val;
1402 if (*bar == '%' && *(bar + 1) == '_')
1404 else if (*bar == '%' && *(bar + 1) == '%') {