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)
322 copy = copy_widget_value_tree(newtree, STRUCTURAL_CHANGE);
324 free_widget_value_contents(node);
326 free_widget_value(copy); /* free the node, but not its contents. */
330 static widget_info *allocate_widget_info(const char *type, const char *name,
331 LWLIB_ID id, widget_value * val,
332 lw_callback pre_activate_cb,
333 lw_callback selection_cb,
334 lw_callback post_activate_cb)
336 widget_info *info = (widget_info *) xmalloc(sizeof(widget_info));
337 info->type = safe_strdup(type);
338 info->name = safe_strdup(name);
340 info->val = copy_widget_value_tree(val, STRUCTURAL_CHANGE);
342 info->pre_activate_cb = pre_activate_cb;
343 info->selection_cb = selection_cb;
344 info->post_activate_cb = post_activate_cb;
345 info->instances = NULL;
347 info->next = all_widget_info;
348 all_widget_info = info;
353 static void free_widget_info(widget_info * info)
355 safe_free_str(info->type);
356 safe_free_str(info->name);
357 free_widget_value_tree(info->val);
358 memset(info, '\0', sizeof(widget_info));
363 mark_widget_destroyed(Widget widget, XtPointer closure, XtPointer call_data)
365 widget_instance *instance = (widget_instance *) closure;
367 /* be very conservative */
368 if (instance->widget == widget)
369 instance->widget = NULL;
372 static widget_instance *allocate_widget_instance(widget_info * info,
376 widget_instance *instance =
377 (widget_instance *) xmalloc(sizeof(widget_instance));
378 instance->parent = parent;
379 instance->pop_up_p = pop_up_p;
380 instance->info = info;
381 instance->next = info->instances;
382 info->instances = instance;
384 instantiate_widget_instance(instance);
386 XtAddCallback(instance->widget, XtNdestroyCallback,
387 mark_widget_destroyed, (XtPointer) instance);
391 static void free_widget_instance(widget_instance * instance)
393 memset(instance, '\0', sizeof(widget_instance));
397 static widget_info *get_widget_info(LWLIB_ID id, Boolean remove_p)
401 for (prev = NULL, info = all_widget_info;
402 info; prev = info, info = info->next)
403 if (info->id == id) {
406 prev->next = info->next;
408 all_widget_info = info->next;
415 /* Internal function used by the library dependent implementation to get the
416 widget_value for a given widget in an instance */
417 widget_info *lw_get_widget_info(LWLIB_ID id)
419 return get_widget_info(id, 0);
423 map_widget_values(widget_value * value, int (*mapfunc) (widget_value * value,
430 retval = map_widget_values(value->contents, mapfunc, closure);
435 retval = map_widget_values(value->next, mapfunc, closure);
439 return (mapfunc) (value, closure);
443 lw_map_widget_values(LWLIB_ID id, int (*mapfunc) (widget_value * value,
444 void *closure), void *closure)
446 widget_info *info = get_widget_info(id, 0);
452 return map_widget_values(info->val, mapfunc, closure);
456 static widget_instance *get_widget_instance(Widget widget, Boolean remove_p)
459 widget_instance *instance;
460 widget_instance *prev;
461 for (info = all_widget_info; info; info = info->next)
462 for (prev = NULL, instance = info->instances;
463 instance; prev = instance, instance = instance->next)
464 if (instance->widget == widget) {
467 prev->next = instance->next;
474 return (widget_instance *) 0;
477 static widget_instance *find_instance(LWLIB_ID id, Widget parent,
480 widget_info *info = get_widget_info(id, False);
481 widget_instance *instance;
484 for (instance = info->instances; instance;
485 instance = instance->next)
486 if (instance->parent == parent
487 && instance->pop_up_p == pop_up_p)
493 /* utility function for widget_value */
494 static Boolean safe_strcmp(const char *s1, const char *s2)
498 return (s1 && s2) ? strcmp(s1, s2) : s1 ? False : !!s2;
501 static change_type max(change_type i1, change_type i2)
503 return (int)i1 > (int)i2 ? i1 : i2;
507 # define EXPLAIN(name, oc, nc, desc, a1, a2) \
508 printf ("Change: \"%s\"\tmax(%s=%d,%s=%d)\t%s %d %d\n", \
510 (oc == NO_CHANGE ? "none" : \
511 (oc == INVISIBLE_CHANGE ? "invisible" : \
512 (oc == VISIBLE_CHANGE ? "visible" : \
513 (oc == STRUCTURAL_CHANGE ? "structural" : "???")))), \
515 (nc == NO_CHANGE ? "none" : \
516 (nc == INVISIBLE_CHANGE ? "invisible" : \
517 (nc == VISIBLE_CHANGE ? "visible" : \
518 (nc == STRUCTURAL_CHANGE ? "structural" : "???")))), \
521 # define EXPLAIN(name, oc, nc, desc, a1, a2)
524 static widget_value *merge_widget_value(widget_value * val1,
525 widget_value * val2, int level)
528 widget_value *merged_next;
529 widget_value *merged_contents;
533 return copy_widget_value_tree(val2, STRUCTURAL_CHANGE);
538 free_widget_value_tree(val1);
544 if (val1->type != val2->type) {
545 EXPLAIN(val1->name, change, STRUCTURAL_CHANGE, "type change",
546 val1->type, val2->type);
547 change = max(change, STRUCTURAL_CHANGE);
548 val1->type = val2->type;
550 if (safe_strcmp(val1->name, val2->name)) {
551 EXPLAIN(val1->name, change, STRUCTURAL_CHANGE, "name change",
552 val1->name, val2->name);
553 change = max(change, STRUCTURAL_CHANGE);
554 safe_free_str(val1->name);
555 val1->name = safe_strdup(val2->name);
557 if (safe_strcmp(val1->value, val2->value)) {
558 EXPLAIN(val1->name, change, VISIBLE_CHANGE, "value change",
559 val1->value, val2->value);
560 change = max(change, VISIBLE_CHANGE);
561 safe_free_str(val1->value);
562 val1->value = safe_strdup(val2->value);
564 if (safe_strcmp(val1->key, val2->key)) {
565 EXPLAIN(val1->name, change, VISIBLE_CHANGE, "key change",
566 val1->key, val2->key);
567 change = max(change, VISIBLE_CHANGE);
568 safe_free_str(val1->key);
569 val1->key = safe_strdup(val2->key);
571 if (val1->accel != val2->accel) {
572 EXPLAIN(val1->name, change, VISIBLE_CHANGE,
573 "accelerator change", val1->accel, val2->accel);
574 change = max(change, VISIBLE_CHANGE);
575 val1->accel = val2->accel;
577 if (val1->enabled != val2->enabled) {
578 EXPLAIN(val1->name, change, VISIBLE_CHANGE, "enablement change",
579 val1->enabled, val2->enabled);
580 change = max(change, VISIBLE_CHANGE);
581 val1->enabled = val2->enabled;
583 if (val1->selected != val2->selected) {
584 EXPLAIN(val1->name, change, VISIBLE_CHANGE, "selection change",
585 val1->selected, val2->selected);
586 change = max(change, VISIBLE_CHANGE);
587 val1->selected = val2->selected;
589 if (val1->call_data != val2->call_data) {
590 EXPLAIN(val1->name, change, INVISIBLE_CHANGE,
591 "call-data change", val1->call_data, val2->call_data);
592 change = max(change, INVISIBLE_CHANGE);
593 val1->call_data = val2->call_data;
596 if (merge_widget_value_args(val1, val2)) {
597 EXPLAIN(val1->name, change, VISIBLE_CHANGE, "widget change", 0,
599 change = max(change, VISIBLE_CHANGE);
603 #ifdef NEED_SCROLLBARS
604 if (merge_scrollbar_values(val1, val2)) {
605 EXPLAIN(val1->name, change, VISIBLE_CHANGE, "scrollbar change",
607 change = max(change, VISIBLE_CHANGE);
613 merge_widget_value(val1->contents, val2->contents,
616 if (val1->contents && !merged_contents) {
617 EXPLAIN(val1->name, change, INVISIBLE_CHANGE,
618 "(contents gone)", 0, 0);
619 change = max(change, INVISIBLE_CHANGE);
620 } else if (merged_contents
621 && merged_contents->change != NO_CHANGE) {
622 EXPLAIN(val1->name, change, INVISIBLE_CHANGE,
623 "(contents change)", 0, 0);
624 change = max(change, INVISIBLE_CHANGE);
627 val1->contents = merged_contents;
630 merged_next = merge_widget_value(val1->next, val2->next, level);
632 if (val1->next && !merged_next) {
633 EXPLAIN(val1->name, change, STRUCTURAL_CHANGE,
634 "(following gone)", 0, 0);
635 change = max(change, STRUCTURAL_CHANGE);
636 } else if (merged_next) {
637 if (merged_next->change) {
638 EXPLAIN(val1->name, change, merged_next->change,
639 "(following change)", 0, 0);
641 change = max(change, merged_next->change);
644 val1->next = merged_next;
646 val1->change = change;
648 if (change > NO_CHANGE && val1->toolkit_data) {
649 if (val1->free_toolkit_data)
650 XtFree((char *)val1->toolkit_data);
651 val1->toolkit_data = NULL;
657 /* modifying the widgets */
658 static Widget name_to_widget(widget_instance * instance, const char *name)
660 Widget widget = NULL;
662 if (!instance->widget)
665 if (!strcmp(XtName(instance->widget), name))
666 widget = instance->widget;
668 int length = strlen(name) + 2;
669 char *real_name = (char *)alloca(length);
671 strcpy(real_name + 1, name);
673 widget = XtNameToWidget(instance->widget, real_name);
679 set_one_value(widget_instance * instance, widget_value * val, Boolean deep_p)
681 Widget widget = name_to_widget(instance, val->name);
685 if (lw_lucid_widget_p(instance->widget))
686 xlw_update_one_widget(instance, widget, val, deep_p);
689 if (lw_motif_widget_p(instance->widget))
690 xm_update_one_widget(instance, widget, val, deep_p);
693 if (lw_xaw_widget_p(instance->widget))
694 xaw_update_one_widget(instance, widget, val, deep_p);
700 update_one_widget_instance(widget_instance * instance, Boolean deep_p)
704 if (!instance->widget)
705 /* the widget was destroyed */
708 for (val = instance->info->val; val; val = val->next)
709 if (val->change != NO_CHANGE)
710 set_one_value(instance, val, deep_p);
713 static void update_all_widget_values(widget_info * info, Boolean deep_p)
715 widget_instance *instance;
718 for (instance = info->instances; instance; instance = instance->next)
719 update_one_widget_instance(instance, deep_p);
721 for (val = info->val; val; val = val->next) {
722 val->change = NO_CHANGE;
724 val->args->args_changed = False;
728 void lw_modify_all_widgets(LWLIB_ID id, widget_value * val, Boolean deep_p)
730 widget_info *info = get_widget_info(id, False);
731 widget_value *new_val;
732 widget_value *next_new_val;
741 for (new_val = val; new_val; new_val = new_val->next) {
742 next_new_val = new_val->next;
743 new_val->next = NULL;
745 for (prev = NULL, cur = info->val; cur;
746 prev = cur, cur = cur->next)
747 if (!strcmp(cur->name, new_val->name)) {
752 merge_widget_value(cur, new_val,
755 prev->next = cur ? cur : next;
757 info->val = cur ? cur : next;
763 /* Could not find it, add it */
766 copy_widget_value_tree(new_val,
770 copy_widget_value_tree(new_val,
773 new_val->next = next_new_val;
776 update_all_widget_values(info, deep_p);
779 /* creating the widgets */
781 static void initialize_widget_instance(widget_instance * instance)
785 for (val = instance->info->val; val; val = val->next)
786 val->change = STRUCTURAL_CHANGE;
788 update_one_widget_instance(instance, True);
790 for (val = instance->info->val; val; val = val->next) {
791 val->change = NO_CHANGE;
793 val->args->args_changed = False;
797 /* strcasecmp() is not sufficiently portable or standard,
798 and it's easier just to write our own. */
799 static int ascii_strcasecmp(const char *s1, const char *s2)
804 if (c1 >= 'A' && c1 <= 'Z')
806 if (c2 >= 'A' && c2 <= 'Z')
815 static widget_creation_function
816 find_in_table(const char *type, const widget_creation_entry table[])
818 const widget_creation_entry *cur;
819 for (cur = table; cur->type; cur++)
820 if (!ascii_strcasecmp(type, cur->type))
821 return cur->function;
825 static Boolean dialog_spec_p(const char *name)
827 /* return True if name matches [EILPQeilpq][1-9][Bb] or
828 [EILPQeilpq][1-9][Bb][Rr][1-9] */
843 if (name[1] >= '0' && name[1] <= '9') {
844 if (name[2] != 'B' && name[2] != 'b')
848 if ((name[3] == 'T' || name[3] == 't') && !name[4])
850 if ((name[3] == 'R' || name[3] == 'r')
851 && name[4] >= '0' && name[4] <= '9' && !name[5])
862 static void instantiate_widget_instance(widget_instance * instance)
864 widget_creation_function function = NULL;
869 find_in_table(instance->info->type, xlw_creation_table);
874 find_in_table(instance->info->type, xm_creation_table);
879 find_in_table(instance->info->type, xaw_creation_table);
883 if (dialog_spec_p(instance->info->type)) {
884 #ifdef LWLIB_DIALOGS_MOTIF
886 function = xm_create_dialog;
888 #ifdef LWLIB_DIALOGS_ATHENA
890 function = xaw_create_dialog;
896 fprintf(stderr, "No creation function for widget type %s\n",
897 instance->info->type);
901 instance->widget = (*function) (instance);
903 if (!instance->widget)
906 /* XtRealizeWidget (instance->widget); */
910 lw_register_widget(const char *type, const char *name,
911 LWLIB_ID id, widget_value * val,
912 lw_callback pre_activate_cb, lw_callback selection_cb,
913 lw_callback post_activate_cb)
915 if (!get_widget_info(id, False))
916 allocate_widget_info(type, name, id, val, pre_activate_cb,
917 selection_cb, post_activate_cb);
920 Widget lw_get_widget(LWLIB_ID id, Widget parent, Boolean pop_up_p)
922 widget_instance *instance = find_instance(id, parent, pop_up_p);
923 return instance ? instance->widget : NULL;
926 Widget lw_make_widget(LWLIB_ID id, Widget parent, Boolean pop_up_p)
928 widget_instance *instance = find_instance(id, parent, pop_up_p);
931 widget_info *info = get_widget_info(id, False);
934 instance = allocate_widget_instance(info, parent, pop_up_p);
935 initialize_widget_instance(instance);
937 if (!instance->widget)
939 return instance->widget;
943 lw_create_widget(const char *type, const char *name,
944 LWLIB_ID id, widget_value * val,
945 Widget parent, Boolean pop_up_p, lw_callback pre_activate_cb,
946 lw_callback selection_cb, lw_callback post_activate_cb)
948 lw_register_widget(type, name, id, val, pre_activate_cb, selection_cb,
950 return lw_make_widget(id, parent, pop_up_p);
953 /* destroying the widgets */
954 static void destroy_one_instance(widget_instance * instance)
956 /* Remove the destroy callback on the widget; that callback will try to
957 dereference the instance object (to set its widget slot to 0, since the
958 widget is dead.) Since the instance is now dead, we don't have to worry
959 about the fact that its widget is dead too.
961 This happens in the Phase2Destroy of the widget, so this callback would
962 not have been run until arbitrarily long after the instance was freed.
964 if (instance->widget)
965 XtRemoveCallback(instance->widget, XtNdestroyCallback,
966 mark_widget_destroyed, (XtPointer) instance);
968 if (instance->widget) {
969 /* The else are pretty tricky here, including the empty statement
970 at the end because it would be very bad to destroy a widget
973 if (lw_lucid_widget_p(instance->widget))
974 xlw_destroy_instance(instance);
978 if (lw_motif_widget_p(instance->widget))
979 xm_destroy_instance(instance);
983 if (lw_xaw_widget_p(instance->widget))
984 xaw_destroy_instance(instance);
988 /* do not remove the empty statement */
993 free_widget_instance(instance);
996 void lw_destroy_widget(Widget w)
998 widget_instance *instance = get_widget_instance(w, True);
1001 widget_info *info = instance->info;
1002 /* instance has already been removed from the list; free it */
1003 destroy_one_instance(instance);
1004 /* if there are no instances left, free the info too */
1005 if (!info->instances)
1006 lw_destroy_all_widgets(info->id);
1010 void lw_destroy_all_widgets(LWLIB_ID id)
1012 widget_info *info = get_widget_info(id, True);
1013 widget_instance *instance;
1014 widget_instance *next;
1017 for (instance = info->instances; instance;) {
1018 next = instance->next;
1019 destroy_one_instance(instance);
1022 free_widget_info(info);
1026 void lw_destroy_everything(void)
1028 while (all_widget_info)
1029 lw_destroy_all_widgets(all_widget_info->id);
1032 void lw_destroy_all_pop_ups(void)
1036 widget_instance *instance;
1038 for (info = all_widget_info; info; info = next) {
1040 instance = info->instances;
1041 if (instance && instance->pop_up_p)
1042 lw_destroy_all_widgets(info->id);
1046 Widget lw_raise_all_pop_up_widgets(void)
1049 widget_instance *instance;
1050 Widget result = NULL;
1052 for (info = all_widget_info; info; info = info->next)
1053 for (instance = info->instances; instance;
1054 instance = instance->next)
1055 if (instance->pop_up_p) {
1056 Widget widget = instance->widget;
1058 if (XtIsManaged(widget)
1060 /* What a complete load of crap!!!!
1061 When a dialogShell is on the screen, it is not managed!
1064 (lw_motif_widget_p(instance->widget)
1066 XtIsManaged(first_child(widget)))
1071 XMapRaised(XtDisplay(widget),
1079 static void lw_pop_all_widgets(LWLIB_ID id, Boolean up)
1081 widget_info *info = get_widget_info(id, False);
1082 widget_instance *instance;
1085 for (instance = info->instances; instance;
1086 instance = instance->next)
1087 if (instance->pop_up_p && instance->widget) {
1089 if (lw_lucid_widget_p(instance->widget)) {
1090 XtRealizeWidget(instance->widget);
1091 xlw_pop_instance(instance, up);
1095 if (lw_motif_widget_p(instance->widget)) {
1096 XtRealizeWidget(instance->widget);
1097 xm_pop_instance(instance, up);
1101 if (lw_xaw_widget_p(instance->widget)) {
1102 XtRealizeWidget(XtParent
1103 (instance->widget));
1104 XtRealizeWidget(instance->widget);
1105 xaw_pop_instance(instance, up);
1111 void lw_pop_up_all_widgets(LWLIB_ID id)
1113 lw_pop_all_widgets(id, True);
1116 void lw_pop_down_all_widgets(LWLIB_ID id)
1118 lw_pop_all_widgets(id, False);
1121 void lw_popup_menu(Widget widget, XEvent * event)
1123 #ifdef LWLIB_MENUBARS_LUCID
1124 if (lw_lucid_widget_p(widget))
1125 xlw_popup_menu(widget, event);
1127 #ifdef LWLIB_MENUBARS_MOTIF
1128 if (lw_motif_widget_p(widget))
1129 xm_popup_menu(widget, event);
1131 #ifdef LWLIB_MENUBARS_ATHENA
1132 if (lw_xaw_widget_p(widget))
1133 xaw_popup_menu(widget, event); /* not implemented */
1137 /* get the values back */
1138 static Boolean get_one_value(widget_instance * instance, widget_value * val)
1140 Widget widget = name_to_widget(instance, val->name);
1144 if (lw_lucid_widget_p(instance->widget))
1145 xlw_update_one_value(instance, widget, val);
1148 if (lw_motif_widget_p(instance->widget))
1149 xm_update_one_value(instance, widget, val);
1152 if (lw_xaw_widget_p(instance->widget))
1153 xaw_update_one_value(instance, widget, val);
1160 Boolean lw_get_some_values(LWLIB_ID id, widget_value * val_out)
1162 widget_info *info = get_widget_info(id, False);
1163 widget_instance *instance;
1165 Boolean result = False;
1170 instance = info->instances;
1174 for (val = val_out; val; val = val->next)
1175 if (get_one_value(instance, val))
1181 widget_value *lw_get_all_values(LWLIB_ID id)
1183 widget_info *info = get_widget_info(id, False);
1184 widget_value *val = info->val;
1185 if (lw_get_some_values(id, val))
1191 /* internal function used by the library dependent implementation to get the
1192 widget_value for a given widget in an instance */
1193 widget_value *lw_get_widget_value_for_widget(widget_instance * instance,
1196 char *name = XtName(w);
1198 for (cur = instance->info->val; cur; cur = cur->next)
1199 if (!strcmp(cur->name, name))
1204 /* update other instances value when one thing changed */
1205 /* This function can be used as a an XtCallback for the widgets that get
1206 modified to update other instances of the widgets. Closure should be the
1209 lw_internal_update_other_instances(Widget widget, XtPointer closure,
1210 XtPointer call_data)
1212 /* To forbid recursive calls */
1213 static Boolean updating;
1215 widget_instance *instance = (widget_instance *) closure;
1216 char *name = XtName(widget);
1218 widget_instance *cur;
1221 /* never recurse as this could cause infinite recursions. */
1225 /* protect against the widget being destroyed */
1226 if (XtWidgetBeingDestroyedP(widget))
1229 /* Return immediately if there are no other instances */
1230 info = instance->info;
1231 if (!info->instances->next)
1236 for (val = info->val; val && strcmp(val->name, name); val = val->next) ;
1238 if (val && get_one_value(instance, val))
1239 for (cur = info->instances; cur; cur = cur->next)
1240 if (cur != instance)
1241 set_one_value(cur, val, True);
1248 LWLIB_ID lw_get_widget_id(Widget w)
1250 widget_instance *instance = get_widget_instance(w, False);
1252 return instance ? instance->info->id : 0;
1255 /* set the keyboard focus */
1256 void lw_set_keyboard_focus(Widget parent, Widget w)
1258 #if defined(NEED_MOTIF) && !defined(LESSTIF_VERSION)
1259 /* This loses with Lesstif v0.75a */
1260 xm_set_keyboard_focus(parent, w);
1262 XtSetKeyboardFocus(parent, w);
1267 static void show_one_widget_busy(Widget w, Boolean flag)
1269 Pixel foreground = 0;
1270 Pixel background = 1;
1271 Widget widget_to_invert = XtNameToWidget(w, "*sheet");
1274 if (!widget_to_invert)
1275 widget_to_invert = w;
1277 XtSetArg(al[0], XtNforeground, &foreground);
1278 XtSetArg(al[1], XtNbackground, &background);
1279 XtGetValues(widget_to_invert, al, 2);
1281 XtSetArg(al[0], XtNforeground, background);
1282 XtSetArg(al[1], XtNbackground, foreground);
1283 XtSetValues(widget_to_invert, al, 2);
1286 void lw_show_busy(Widget w, Boolean busy)
1288 widget_instance *instance = get_widget_instance(w, False);
1290 widget_instance *next;
1293 info = instance->info;
1294 if (info->busy != busy) {
1295 for (next = info->instances; next; next = next->next)
1297 show_one_widget_busy(next->widget,
1304 void lw_add_value_args_to_args(widget_value * wv, ArgList addto, int *offset)
1307 if (wv->args && wv->args->nargs) {
1308 for (i = 0; i < wv->args->nargs; i++) {
1309 addto[i + *offset] = wv->args->args[i];
1311 *offset += wv->args->nargs;
1315 XtArgVal lw_get_value_arg(widget_value * wv, String name)
1319 for (i = 0; i < wv->args->nargs; i++) {
1320 if (!strcmp(wv->args->args[i].name, name)) {
1321 return wv->args->args[i].value;
1325 return (XtArgVal) 0;
1328 void lw_add_widget_value_arg(widget_value * wv, String name, XtArgVal value)
1332 wv->args = (widget_args *) xmalloc(sizeof(widget_args));
1333 memset(wv->args, '\0', sizeof(widget_args));
1334 wv->args->ref_count = 1;
1335 wv->args->nargs = 0;
1336 wv->args->args = (ArgList) xmalloc(sizeof(Arg) * 10);
1337 memset(wv->args->args, '\0', sizeof(Arg) * 10);
1340 if (wv->args->nargs > 10)
1343 /* Register the change. */
1344 wv->args->args_changed = True;
1345 /* If the arg is already there then we must replace it. */
1346 for (i = 0; i < wv->args->nargs; i++) {
1347 if (!strcmp(wv->args->args[i].name, name)) {
1348 XtSetArg(wv->args->args[i], name, value);
1352 if (i >= wv->args->nargs) {
1353 XtSetArg(wv->args->args[wv->args->nargs], name, value);
1358 static void free_widget_value_args(widget_value * wv)
1361 if (--wv->args->ref_count <= 0) {
1362 #ifdef LWLIB_WIDGETS_MOTIF
1364 for (i = 0; i < wv->args->nargs; i++) {
1366 (wv->args->args[i].name, XmNfontList))
1367 XmFontListFree((XmFontList) wv->args->
1371 xfree(wv->args->args);
1378 void lw_copy_widget_value_args(widget_value * val, widget_value * copy)
1380 if (val == copy || val->args == copy->args)
1384 free_widget_value_args(copy);
1388 copy->args = val->args;
1389 copy->args->ref_count++;
1393 /* Remove %_ and convert %% to %. We can do this in-place because we
1394 are always shortening, never lengthening, the string. */
1395 void lw_remove_accelerator_spec(char *val)
1397 char *foo = val, *bar = val;
1400 if (*bar == '%' && *(bar + 1) == '_')
1402 else if (*bar == '%' && *(bar + 1) == '%') {