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;
504 /* We only expect to use the following max function */
509 static change_type max(change_type i1, change_type i2)
511 return (int)i1 > (int)i2 ? i1 : i2;
515 # define EXPLAIN(name, oc, nc, desc, a1, a2) \
516 printf ("Change: \"%s\"\tmax(%s=%d,%s=%d)\t%s %d %d\n", \
518 (oc == NO_CHANGE ? "none" : \
519 (oc == INVISIBLE_CHANGE ? "invisible" : \
520 (oc == VISIBLE_CHANGE ? "visible" : \
521 (oc == STRUCTURAL_CHANGE ? "structural" : "???")))), \
523 (nc == NO_CHANGE ? "none" : \
524 (nc == INVISIBLE_CHANGE ? "invisible" : \
525 (nc == VISIBLE_CHANGE ? "visible" : \
526 (nc == STRUCTURAL_CHANGE ? "structural" : "???")))), \
529 # define EXPLAIN(name, oc, nc, desc, a1, a2)
532 static widget_value *merge_widget_value(widget_value * val1,
533 widget_value * val2, int level)
536 widget_value *merged_next;
537 widget_value *merged_contents;
541 return copy_widget_value_tree(val2, STRUCTURAL_CHANGE);
546 free_widget_value_tree(val1);
552 if (val1->type != val2->type) {
553 EXPLAIN(val1->name, change, STRUCTURAL_CHANGE, "type change",
554 val1->type, val2->type);
555 change = max(change, STRUCTURAL_CHANGE);
556 val1->type = val2->type;
558 if (safe_strcmp(val1->name, val2->name)) {
559 EXPLAIN(val1->name, change, STRUCTURAL_CHANGE, "name change",
560 val1->name, val2->name);
561 change = max(change, STRUCTURAL_CHANGE);
562 safe_free_str(val1->name);
563 val1->name = safe_strdup(val2->name);
565 if (safe_strcmp(val1->value, val2->value)) {
566 EXPLAIN(val1->name, change, VISIBLE_CHANGE, "value change",
567 val1->value, val2->value);
568 change = max(change, VISIBLE_CHANGE);
569 safe_free_str(val1->value);
570 val1->value = safe_strdup(val2->value);
572 if (safe_strcmp(val1->key, val2->key)) {
573 EXPLAIN(val1->name, change, VISIBLE_CHANGE, "key change",
574 val1->key, val2->key);
575 change = max(change, VISIBLE_CHANGE);
576 safe_free_str(val1->key);
577 val1->key = safe_strdup(val2->key);
579 if (val1->accel != val2->accel) {
580 EXPLAIN(val1->name, change, VISIBLE_CHANGE,
581 "accelerator change", val1->accel, val2->accel);
582 change = max(change, VISIBLE_CHANGE);
583 val1->accel = val2->accel;
585 if (val1->enabled != val2->enabled) {
586 EXPLAIN(val1->name, change, VISIBLE_CHANGE, "enablement change",
587 val1->enabled, val2->enabled);
588 change = max(change, VISIBLE_CHANGE);
589 val1->enabled = val2->enabled;
591 if (val1->selected != val2->selected) {
592 EXPLAIN(val1->name, change, VISIBLE_CHANGE, "selection change",
593 val1->selected, val2->selected);
594 change = max(change, VISIBLE_CHANGE);
595 val1->selected = val2->selected;
597 if (val1->call_data != val2->call_data) {
598 EXPLAIN(val1->name, change, INVISIBLE_CHANGE,
599 "call-data change", val1->call_data, val2->call_data);
600 change = max(change, INVISIBLE_CHANGE);
601 val1->call_data = val2->call_data;
604 if (merge_widget_value_args(val1, val2)) {
605 EXPLAIN(val1->name, change, VISIBLE_CHANGE, "widget change", 0,
607 change = max(change, VISIBLE_CHANGE);
611 #ifdef NEED_SCROLLBARS
612 if (merge_scrollbar_values(val1, val2)) {
613 EXPLAIN(val1->name, change, VISIBLE_CHANGE, "scrollbar change",
615 change = max(change, VISIBLE_CHANGE);
621 merge_widget_value(val1->contents, val2->contents,
624 if (val1->contents && !merged_contents) {
625 EXPLAIN(val1->name, change, INVISIBLE_CHANGE,
626 "(contents gone)", 0, 0);
627 change = max(change, INVISIBLE_CHANGE);
628 } else if (merged_contents
629 && merged_contents->change != NO_CHANGE) {
630 EXPLAIN(val1->name, change, INVISIBLE_CHANGE,
631 "(contents change)", 0, 0);
632 change = max(change, INVISIBLE_CHANGE);
635 val1->contents = merged_contents;
638 merged_next = merge_widget_value(val1->next, val2->next, level);
640 if (val1->next && !merged_next) {
641 EXPLAIN(val1->name, change, STRUCTURAL_CHANGE,
642 "(following gone)", 0, 0);
643 change = max(change, STRUCTURAL_CHANGE);
644 } else if (merged_next) {
645 if (merged_next->change) {
646 EXPLAIN(val1->name, change, merged_next->change,
647 "(following change)", 0, 0);
649 change = max(change, merged_next->change);
652 val1->next = merged_next;
654 val1->change = change;
656 if (change > NO_CHANGE && val1->toolkit_data) {
657 if (val1->free_toolkit_data)
658 XtFree((char *)val1->toolkit_data);
659 val1->toolkit_data = NULL;
665 /* modifying the widgets */
666 static Widget name_to_widget(widget_instance * instance, const char *name)
668 Widget widget = NULL;
670 if (!instance->widget)
673 if (!strcmp(XtName(instance->widget), name))
674 widget = instance->widget;
676 int length = strlen(name) + 2;
677 char *real_name = (char *)alloca(length);
679 strcpy(real_name + 1, name);
681 widget = XtNameToWidget(instance->widget, real_name);
687 set_one_value(widget_instance * instance, widget_value * val, Boolean deep_p)
689 Widget widget = name_to_widget(instance, val->name);
693 if (lw_lucid_widget_p(instance->widget))
694 xlw_update_one_widget(instance, widget, val, deep_p);
697 if (lw_motif_widget_p(instance->widget))
698 xm_update_one_widget(instance, widget, val, deep_p);
701 if (lw_xaw_widget_p(instance->widget))
702 xaw_update_one_widget(instance, widget, val, deep_p);
708 update_one_widget_instance(widget_instance * instance, Boolean deep_p)
712 if (!instance->widget)
713 /* the widget was destroyed */
716 for (val = instance->info->val; val; val = val->next)
717 if (val->change != NO_CHANGE)
718 set_one_value(instance, val, deep_p);
721 static void update_all_widget_values(widget_info * info, Boolean deep_p)
723 widget_instance *instance;
726 for (instance = info->instances; instance; instance = instance->next)
727 update_one_widget_instance(instance, deep_p);
729 for (val = info->val; val; val = val->next) {
730 val->change = NO_CHANGE;
732 val->args->args_changed = False;
736 void lw_modify_all_widgets(LWLIB_ID id, widget_value * val, Boolean deep_p)
738 widget_info *info = get_widget_info(id, False);
739 widget_value *new_val;
740 widget_value *next_new_val;
749 for (new_val = val; new_val; new_val = new_val->next) {
750 next_new_val = new_val->next;
751 new_val->next = NULL;
753 for (prev = NULL, cur = info->val; cur;
754 prev = cur, cur = cur->next)
755 if (!strcmp(cur->name, new_val->name)) {
760 merge_widget_value(cur, new_val,
763 prev->next = cur ? cur : next;
765 info->val = cur ? cur : next;
771 /* Could not find it, add it */
774 copy_widget_value_tree(new_val,
778 copy_widget_value_tree(new_val,
781 new_val->next = next_new_val;
784 update_all_widget_values(info, deep_p);
787 /* creating the widgets */
789 static void initialize_widget_instance(widget_instance * instance)
793 for (val = instance->info->val; val; val = val->next)
794 val->change = STRUCTURAL_CHANGE;
796 update_one_widget_instance(instance, True);
798 for (val = instance->info->val; val; val = val->next) {
799 val->change = NO_CHANGE;
801 val->args->args_changed = False;
805 /* strcasecmp() is not sufficiently portable or standard,
806 and it's easier just to write our own. */
807 static int ascii_strcasecmp(const char *s1, const char *s2)
812 if (c1 >= 'A' && c1 <= 'Z')
814 if (c2 >= 'A' && c2 <= 'Z')
823 static widget_creation_function
824 find_in_table(const char *type, const widget_creation_entry table[])
826 const widget_creation_entry *cur;
827 for (cur = table; cur->type; cur++)
828 if (!ascii_strcasecmp(type, cur->type))
829 return cur->function;
833 static Boolean dialog_spec_p(const char *name)
835 /* return True if name matches [EILPQeilpq][1-9][Bb] or
836 [EILPQeilpq][1-9][Bb][Rr][1-9] */
851 if (name[1] >= '0' && name[1] <= '9') {
852 if (name[2] != 'B' && name[2] != 'b')
856 if ((name[3] == 'T' || name[3] == 't') && !name[4])
858 if ((name[3] == 'R' || name[3] == 'r')
859 && name[4] >= '0' && name[4] <= '9' && !name[5])
870 static void instantiate_widget_instance(widget_instance * instance)
872 widget_creation_function function = NULL;
877 find_in_table(instance->info->type, xlw_creation_table);
882 find_in_table(instance->info->type, xm_creation_table);
887 find_in_table(instance->info->type, xaw_creation_table);
891 if (dialog_spec_p(instance->info->type)) {
892 #ifdef LWLIB_DIALOGS_MOTIF
894 function = xm_create_dialog;
896 #ifdef LWLIB_DIALOGS_ATHENA
898 function = xaw_create_dialog;
904 fprintf(stderr, "No creation function for widget type %s\n",
905 instance->info->type);
908 instance->widget = (*function) (instance);
911 if (!instance->widget)
914 /* XtRealizeWidget (instance->widget); */
918 lw_register_widget(const char *type, const char *name,
919 LWLIB_ID id, widget_value * val,
920 lw_callback pre_activate_cb, lw_callback selection_cb,
921 lw_callback post_activate_cb)
923 if (!get_widget_info(id, False))
924 allocate_widget_info(type, name, id, val, pre_activate_cb,
925 selection_cb, post_activate_cb);
928 Widget lw_get_widget(LWLIB_ID id, Widget parent, Boolean pop_up_p)
930 widget_instance *instance = find_instance(id, parent, pop_up_p);
931 return instance ? instance->widget : NULL;
934 Widget lw_make_widget(LWLIB_ID id, Widget parent, Boolean pop_up_p)
936 widget_instance *instance = find_instance(id, parent, pop_up_p);
939 widget_info *info = get_widget_info(id, False);
942 instance = allocate_widget_instance(info, parent, pop_up_p);
943 initialize_widget_instance(instance);
945 if (!instance->widget)
947 return instance->widget;
951 lw_create_widget(const char *type, const char *name,
952 LWLIB_ID id, widget_value * val,
953 Widget parent, Boolean pop_up_p, lw_callback pre_activate_cb,
954 lw_callback selection_cb, lw_callback post_activate_cb)
956 lw_register_widget(type, name, id, val, pre_activate_cb, selection_cb,
958 return lw_make_widget(id, parent, pop_up_p);
961 /* destroying the widgets */
962 static void destroy_one_instance(widget_instance * instance)
964 /* Remove the destroy callback on the widget; that callback will try to
965 dereference the instance object (to set its widget slot to 0, since the
966 widget is dead.) Since the instance is now dead, we don't have to worry
967 about the fact that its widget is dead too.
969 This happens in the Phase2Destroy of the widget, so this callback would
970 not have been run until arbitrarily long after the instance was freed.
972 if (instance->widget)
973 XtRemoveCallback(instance->widget, XtNdestroyCallback,
974 mark_widget_destroyed, (XtPointer) instance);
976 if (instance->widget) {
977 /* The else are pretty tricky here, including the empty statement
978 at the end because it would be very bad to destroy a widget
981 if (lw_lucid_widget_p(instance->widget))
982 xlw_destroy_instance(instance);
986 if (lw_motif_widget_p(instance->widget))
987 xm_destroy_instance(instance);
991 if (lw_xaw_widget_p(instance->widget))
992 xaw_destroy_instance(instance);
996 /* do not remove the empty statement */
1001 free_widget_instance(instance);
1004 void lw_destroy_widget(Widget w)
1006 widget_instance *instance = get_widget_instance(w, True);
1009 widget_info *info = instance->info;
1010 /* instance has already been removed from the list; free it */
1011 destroy_one_instance(instance);
1012 /* if there are no instances left, free the info too */
1013 if (!info->instances)
1014 lw_destroy_all_widgets(info->id);
1018 void lw_destroy_all_widgets(LWLIB_ID id)
1020 widget_info *info = get_widget_info(id, True);
1021 widget_instance *instance;
1022 widget_instance *next;
1025 for (instance = info->instances; instance;) {
1026 next = instance->next;
1027 destroy_one_instance(instance);
1030 free_widget_info(info);
1034 void lw_destroy_everything(void)
1036 while (all_widget_info)
1037 lw_destroy_all_widgets(all_widget_info->id);
1040 void lw_destroy_all_pop_ups(void)
1044 widget_instance *instance;
1046 for (info = all_widget_info; info; info = next) {
1048 instance = info->instances;
1049 if (instance && instance->pop_up_p)
1050 lw_destroy_all_widgets(info->id);
1054 Widget lw_raise_all_pop_up_widgets(void)
1057 widget_instance *instance;
1058 Widget result = NULL;
1060 for (info = all_widget_info; info; info = info->next)
1061 for (instance = info->instances; instance;
1062 instance = instance->next)
1063 if (instance->pop_up_p) {
1064 Widget widget = instance->widget;
1066 if (XtIsManaged(widget)
1068 /* What a complete load of crap!!!!
1069 When a dialogShell is on the screen, it is not managed!
1072 (lw_motif_widget_p(instance->widget)
1074 XtIsManaged(first_child(widget)))
1079 XMapRaised(XtDisplay(widget),
1087 static void lw_pop_all_widgets(LWLIB_ID id, Boolean up)
1089 widget_info *info = get_widget_info(id, False);
1090 widget_instance *instance;
1093 for (instance = info->instances; instance;
1094 instance = instance->next)
1095 if (instance->pop_up_p && instance->widget) {
1097 if (lw_lucid_widget_p(instance->widget)) {
1098 XtRealizeWidget(instance->widget);
1099 xlw_pop_instance(instance, up);
1103 if (lw_motif_widget_p(instance->widget)) {
1104 XtRealizeWidget(instance->widget);
1105 xm_pop_instance(instance, up);
1109 if (lw_xaw_widget_p(instance->widget)) {
1110 XtRealizeWidget(XtParent
1111 (instance->widget));
1112 XtRealizeWidget(instance->widget);
1113 xaw_pop_instance(instance, up);
1119 void lw_pop_up_all_widgets(LWLIB_ID id)
1121 lw_pop_all_widgets(id, True);
1124 void lw_pop_down_all_widgets(LWLIB_ID id)
1126 lw_pop_all_widgets(id, False);
1129 void lw_popup_menu(Widget widget, XEvent * event)
1131 #ifdef LWLIB_MENUBARS_LUCID
1132 if (lw_lucid_widget_p(widget))
1133 xlw_popup_menu(widget, event);
1135 #ifdef LWLIB_MENUBARS_MOTIF
1136 if (lw_motif_widget_p(widget))
1137 xm_popup_menu(widget, event);
1139 #ifdef LWLIB_MENUBARS_ATHENA
1140 if (lw_xaw_widget_p(widget))
1141 xaw_popup_menu(widget, event); /* not implemented */
1145 /* get the values back */
1146 static Boolean get_one_value(widget_instance * instance, widget_value * val)
1148 Widget widget = name_to_widget(instance, val->name);
1152 if (lw_lucid_widget_p(instance->widget))
1153 xlw_update_one_value(instance, widget, val);
1156 if (lw_motif_widget_p(instance->widget))
1157 xm_update_one_value(instance, widget, val);
1160 if (lw_xaw_widget_p(instance->widget))
1161 xaw_update_one_value(instance, widget, val);
1168 Boolean lw_get_some_values(LWLIB_ID id, widget_value * val_out)
1170 widget_info *info = get_widget_info(id, False);
1171 widget_instance *instance;
1173 Boolean result = False;
1178 instance = info->instances;
1182 for (val = val_out; val; val = val->next)
1183 if (get_one_value(instance, val))
1189 widget_value *lw_get_all_values(LWLIB_ID id)
1191 widget_info *info = get_widget_info(id, False);
1192 widget_value *val = info->val;
1193 if (lw_get_some_values(id, val))
1199 /* internal function used by the library dependent implementation to get the
1200 widget_value for a given widget in an instance */
1201 widget_value *lw_get_widget_value_for_widget(widget_instance * instance,
1204 char *name = XtName(w);
1206 for (cur = instance->info->val; cur; cur = cur->next)
1207 if (!strcmp(cur->name, name))
1212 /* update other instances value when one thing changed */
1213 /* This function can be used as a an XtCallback for the widgets that get
1214 modified to update other instances of the widgets. Closure should be the
1217 lw_internal_update_other_instances(Widget widget, XtPointer closure,
1218 XtPointer call_data)
1220 /* To forbid recursive calls */
1221 static Boolean updating;
1223 widget_instance *instance = (widget_instance *) closure;
1224 char *name = XtName(widget);
1226 widget_instance *cur;
1229 /* never recurse as this could cause infinite recursions. */
1233 /* protect against the widget being destroyed */
1234 if (XtWidgetBeingDestroyedP(widget))
1237 /* Return immediately if there are no other instances */
1238 info = instance->info;
1239 if (!info->instances->next)
1244 for (val = info->val; val && strcmp(val->name, name); val = val->next) ;
1246 if (val && get_one_value(instance, val))
1247 for (cur = info->instances; cur; cur = cur->next)
1248 if (cur != instance)
1249 set_one_value(cur, val, True);
1256 LWLIB_ID lw_get_widget_id(Widget w)
1258 widget_instance *instance = get_widget_instance(w, False);
1260 return instance ? instance->info->id : 0;
1263 /* set the keyboard focus */
1264 void lw_set_keyboard_focus(Widget parent, Widget w)
1266 #if defined(NEED_MOTIF) && !defined(LESSTIF_VERSION)
1267 /* This loses with Lesstif v0.75a */
1268 xm_set_keyboard_focus(parent, w);
1270 XtSetKeyboardFocus(parent, w);
1275 static void show_one_widget_busy(Widget w, Boolean flag)
1277 Pixel foreground = 0;
1278 Pixel background = 1;
1279 Widget widget_to_invert = XtNameToWidget(w, "*sheet");
1282 if (!widget_to_invert)
1283 widget_to_invert = w;
1285 XtSetArg(al[0], XtNforeground, &foreground);
1286 XtSetArg(al[1], XtNbackground, &background);
1287 XtGetValues(widget_to_invert, al, 2);
1289 XtSetArg(al[0], XtNforeground, background);
1290 XtSetArg(al[1], XtNbackground, foreground);
1291 XtSetValues(widget_to_invert, al, 2);
1294 void lw_show_busy(Widget w, Boolean busy)
1296 widget_instance *instance = get_widget_instance(w, False);
1298 widget_instance *next;
1301 info = instance->info;
1302 if (info->busy != busy) {
1303 for (next = info->instances; next; next = next->next)
1305 show_one_widget_busy(next->widget,
1312 void lw_add_value_args_to_args(widget_value * wv, ArgList addto, int *offset)
1315 if (wv->args && wv->args->nargs) {
1316 for (i = 0; i < wv->args->nargs; i++) {
1317 addto[i + *offset] = wv->args->args[i];
1319 *offset += wv->args->nargs;
1323 XtArgVal lw_get_value_arg(widget_value * wv, String name)
1327 for (i = 0; i < wv->args->nargs; i++) {
1328 if (!strcmp(wv->args->args[i].name, name)) {
1329 return wv->args->args[i].value;
1333 return (XtArgVal) 0;
1336 void lw_add_widget_value_arg(widget_value * wv, String name, XtArgVal value)
1340 wv->args = (widget_args *) xmalloc(sizeof(widget_args));
1341 memset(wv->args, '\0', sizeof(widget_args));
1342 wv->args->ref_count = 1;
1343 wv->args->nargs = 0;
1344 wv->args->args = (ArgList) xmalloc(sizeof(Arg) * 10);
1345 memset(wv->args->args, '\0', sizeof(Arg) * 10);
1348 if (wv->args->nargs > 10)
1351 /* Register the change. */
1352 wv->args->args_changed = True;
1353 /* If the arg is already there then we must replace it. */
1354 for (i = 0; i < wv->args->nargs; i++) {
1355 if (!strcmp(wv->args->args[i].name, name)) {
1356 XtSetArg(wv->args->args[i], name, value);
1360 if (i >= wv->args->nargs) {
1361 XtSetArg(wv->args->args[wv->args->nargs], name, value);
1366 static void free_widget_value_args(widget_value * wv)
1369 if (--wv->args->ref_count <= 0) {
1370 #ifdef LWLIB_WIDGETS_MOTIF
1372 for (i = 0; i < wv->args->nargs; i++) {
1374 (wv->args->args[i].name, XmNfontList))
1375 XmFontListFree((XmFontList) wv->args->
1379 xfree(wv->args->args);
1386 void lw_copy_widget_value_args(widget_value * val, widget_value * copy)
1388 if (val == copy || val->args == copy->args)
1392 free_widget_value_args(copy);
1396 copy->args = val->args;
1397 copy->args->ref_count++;
1401 /* Remove %_ and convert %% to %. We can do this in-place because we
1402 are always shortening, never lengthening, the string. */
1403 void lw_remove_accelerator_spec(char *val)
1405 char *foo = val, *bar = val;
1408 if (*bar == '%' && *(bar + 1) == '_')
1410 else if (*bar == '%' && *(bar + 1) == '%') {