Rudimentary support for vc-pull and vc-merge in Git and Mercurial.
[emacs.git] / lwlib / lwlib.c
blob677516a6b1c842a993c1b462de92372679b23f4b
1 /* A general interface to the widgets of different toolkits.
2 Copyright (C) 1992, 1993 Lucid, Inc.
3 Copyright (C) 1994-1996, 1999-2011 Free Software Foundation, Inc.
5 This file is part of the Lucid Widget Library.
7 The Lucid Widget Library is free software; you can redistribute it and/or
8 modify it under the terms of the GNU General Public License as published by
9 the Free Software Foundation; either version 2, or (at your option)
10 any later version.
12 The Lucid Widget Library is distributed in the hope that it will be useful,
13 but WITHOUT ANY WARRANTY; without even the implied warranty of
14 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 GNU General Public License for more details.
17 You should have received a copy of the GNU General Public License
18 along with GNU Emacs; see the file COPYING. If not, write to
19 the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
20 Boston, MA 02110-1301, USA. */
22 #ifdef HAVE_CONFIG_H
23 #include <config.h>
24 #endif
26 #include <setjmp.h>
27 #include "../src/lisp.h"
29 #include <sys/types.h>
30 #include <stdio.h>
31 #include <ctype.h>
32 #include "lwlib-int.h"
33 #include "lwlib-utils.h"
34 #include <X11/StringDefs.h>
36 #if defined (USE_LUCID)
37 #include "lwlib-Xlw.h"
38 #endif
39 #if defined (USE_MOTIF)
40 #include "lwlib-Xm.h"
41 #else /* not USE_MOTIF */
42 #if defined (USE_LUCID)
43 #define USE_XAW
44 #endif /* not USE_MOTIF && USE_LUCID */
45 #endif
46 #if defined (USE_XAW)
47 #ifdef HAVE_XAW3D
48 #include <X11/Xaw3d/Paned.h>
49 #else /* !HAVE_XAW3D */
50 #include <X11/Xaw/Paned.h>
51 #endif /* HAVE_XAW3D */
52 #include "lwlib-Xaw.h"
53 #endif
55 #if !defined (USE_LUCID) && !defined (USE_MOTIF)
56 #error At least one of USE_LUCID or USE_MOTIF must be defined.
57 #endif
59 #ifndef max
60 #define max(x, y) ((x) > (y) ? (x) : (y))
61 #endif
63 /* List of all widgets managed by the library. */
64 static widget_info*
65 all_widget_info = NULL;
67 #ifdef USE_MOTIF
68 const char *lwlib_toolkit_type = "motif";
69 #else
70 const char *lwlib_toolkit_type = "lucid";
71 #endif
73 static widget_value *merge_widget_value (widget_value *,
74 widget_value *,
75 int, int *);
76 static void instantiate_widget_instance (widget_instance *);
77 static int my_strcasecmp (const char *, const char *);
78 static void safe_free_str (char *);
79 static void free_widget_value_tree (widget_value *);
80 static widget_value *copy_widget_value_tree (widget_value *,
81 change_type);
82 static widget_info *allocate_widget_info (const char *, const char *, LWLIB_ID,
83 widget_value *,
84 lw_callback, lw_callback,
85 lw_callback, lw_callback);
86 static void free_widget_info (widget_info *);
87 static void mark_widget_destroyed (Widget, XtPointer, XtPointer);
88 static widget_instance *allocate_widget_instance (widget_info *,
89 Widget, Boolean);
90 static void free_widget_instance (widget_instance *);
91 static widget_info *get_widget_info (LWLIB_ID, Boolean);
92 static widget_instance *get_widget_instance (Widget, Boolean);
93 static widget_instance *find_instance (LWLIB_ID, Widget, Boolean);
94 static Boolean safe_strcmp (const char *, const char *);
95 static Widget name_to_widget (widget_instance *, const char *);
96 static void set_one_value (widget_instance *, widget_value *, Boolean);
97 static void update_one_widget_instance (widget_instance *, Boolean);
98 static void update_all_widget_values (widget_info *, Boolean);
99 static void initialize_widget_instance (widget_instance *);
100 static widget_creation_function find_in_table (const char *, const widget_creation_entry *);
101 static Boolean dialog_spec_p (const char *);
102 static void destroy_one_instance (widget_instance *);
103 static void lw_pop_all_widgets (LWLIB_ID, Boolean);
104 static Boolean get_one_value (widget_instance *, widget_value *);
105 static void show_one_widget_busy (Widget, Boolean);
106 \f/* utility functions for widget_instance and widget_info */
107 char *
108 safe_strdup (const char *s)
110 char *result;
111 if (! s) return 0;
112 result = (char *) malloc (strlen (s) + 1);
113 if (! result)
114 return 0;
115 strcpy (result, s);
116 return result;
119 /* Like strcmp but ignore differences in case. */
121 static int
122 my_strcasecmp (const char *s1, const char *s2)
124 while (1)
126 int c1 = *s1++;
127 int c2 = *s2++;
128 if (isupper (c1))
129 c1 = tolower (c1);
130 if (isupper (c2))
131 c2 = tolower (c2);
132 if (c1 != c2)
133 return (c1 > c2 ? 1 : -1);
134 if (c1 == 0)
135 return 0;
139 static void
140 safe_free_str (char *s)
142 free (s);
145 static widget_value *widget_value_free_list = 0;
146 static int malloc_cpt = 0;
148 widget_value *
149 malloc_widget_value (void)
151 widget_value *wv;
152 if (widget_value_free_list)
154 wv = widget_value_free_list;
155 widget_value_free_list = wv->free_list;
156 wv->free_list = 0;
158 else
160 wv = (widget_value *) malloc (sizeof (widget_value));
161 malloc_cpt++;
163 memset ((void*) wv, 0, sizeof (widget_value));
164 return wv;
167 /* this is analogous to free(). It frees only what was allocated
168 by malloc_widget_value(), and no substructures.
170 void
171 free_widget_value (widget_value *wv)
173 if (wv->free_list)
174 abort ();
176 if (malloc_cpt > 25)
178 /* When the number of already allocated cells is too big,
179 We free it. */
180 free (wv);
181 malloc_cpt--;
183 else
185 wv->free_list = widget_value_free_list;
186 widget_value_free_list = wv;
190 static void
191 free_widget_value_tree (widget_value *wv)
193 if (!wv)
194 return;
196 free (wv->name);
197 free (wv->value);
198 free (wv->key);
200 wv->name = wv->value = wv->key = (char *) 0xDEADBEEF;
202 if (wv->toolkit_data && wv->free_toolkit_data)
204 XtFree (wv->toolkit_data);
205 wv->toolkit_data = (void *) 0xDEADBEEF;
208 if (wv->contents && (wv->contents != (widget_value*)1))
210 free_widget_value_tree (wv->contents);
211 wv->contents = (widget_value *) 0xDEADBEEF;
213 if (wv->next)
215 free_widget_value_tree (wv->next);
216 wv->next = (widget_value *) 0xDEADBEEF;
218 free_widget_value (wv);
221 static widget_value *
222 copy_widget_value_tree (widget_value *val, change_type change)
224 widget_value* copy;
226 if (!val)
227 return NULL;
228 if (val == (widget_value *) 1)
229 return val;
231 copy = malloc_widget_value ();
232 copy->name = safe_strdup (val->name);
233 copy->value = safe_strdup (val->value);
234 copy->key = safe_strdup (val->key);
235 copy->help = val->help;
236 copy->enabled = val->enabled;
237 copy->button_type = val->button_type;
238 copy->selected = val->selected;
239 copy->edited = False;
240 copy->change = change;
241 copy->this_one_change = change;
242 copy->contents = copy_widget_value_tree (val->contents, change);
243 copy->call_data = val->call_data;
244 copy->next = copy_widget_value_tree (val->next, change);
245 copy->toolkit_data = NULL;
246 copy->free_toolkit_data = False;
247 return copy;
250 static widget_info *
251 allocate_widget_info (const char* type,
252 const char* name,
253 LWLIB_ID id,
254 widget_value* val,
255 lw_callback pre_activate_cb,
256 lw_callback selection_cb,
257 lw_callback post_activate_cb,
258 lw_callback highlight_cb)
260 widget_info* info = (widget_info*)malloc (sizeof (widget_info));
261 info->type = safe_strdup (type);
262 info->name = safe_strdup (name);
263 info->id = id;
264 info->val = copy_widget_value_tree (val, STRUCTURAL_CHANGE);
265 info->busy = False;
266 info->pre_activate_cb = pre_activate_cb;
267 info->selection_cb = selection_cb;
268 info->post_activate_cb = post_activate_cb;
269 info->highlight_cb = highlight_cb;
270 info->instances = NULL;
272 info->next = all_widget_info;
273 all_widget_info = info;
275 return info;
278 static void
279 free_widget_info (widget_info *info)
281 safe_free_str (info->type);
282 safe_free_str (info->name);
283 free_widget_value_tree (info->val);
284 memset ((void*)info, 0xDEADBEEF, sizeof (widget_info));
285 free (info);
288 static void
289 mark_widget_destroyed (Widget widget, XtPointer closure, XtPointer call_data)
291 widget_instance* instance = (widget_instance*)closure;
293 /* be very conservative */
294 if (instance->widget == widget)
295 instance->widget = NULL;
298 static widget_instance *
299 allocate_widget_instance (widget_info* info, Widget parent, Boolean pop_up_p)
301 widget_instance* instance =
302 (widget_instance*)malloc (sizeof (widget_instance));
303 memset (instance, 0, sizeof *instance);
304 instance->parent = parent;
305 instance->pop_up_p = pop_up_p;
306 instance->info = info;
307 instance->next = info->instances;
308 info->instances = instance;
310 instantiate_widget_instance (instance);
312 XtAddCallback (instance->widget, XtNdestroyCallback,
313 mark_widget_destroyed, (XtPointer)instance);
314 return instance;
317 static void
318 free_widget_instance (widget_instance *instance)
320 memset ((void*)instance, 0xDEADBEEF, sizeof (widget_instance));
321 free (instance);
324 static widget_info *
325 get_widget_info (LWLIB_ID id, Boolean remove_p)
327 widget_info* info;
328 widget_info* prev;
329 for (prev = NULL, info = all_widget_info;
330 info;
331 prev = info, info = info->next)
332 if (info->id == id)
334 if (remove_p)
336 if (prev)
337 prev->next = info->next;
338 else
339 all_widget_info = info->next;
341 return info;
343 return NULL;
346 /* Internal function used by the library dependent implementation to get the
347 widget_value for a given widget in an instance */
348 widget_info *
349 lw_get_widget_info (LWLIB_ID id)
351 return get_widget_info (id, 0);
354 static widget_instance *
355 get_widget_instance (Widget widget, Boolean remove_p)
357 widget_info* info;
358 widget_instance* instance;
359 widget_instance* prev;
360 for (info = all_widget_info; info; info = info->next)
361 for (prev = NULL, instance = info->instances;
362 instance;
363 prev = instance, instance = instance->next)
364 if (instance->widget == widget)
366 if (remove_p)
368 if (prev)
369 prev->next = instance->next;
370 else
371 info->instances = instance->next;
373 return instance;
375 return (widget_instance *) 0;
378 /* Value is a pointer to the widget_instance corresponding to
379 WIDGET, or null if WIDGET is not a lwlib widget. */
381 widget_instance *
382 lw_get_widget_instance (Widget widget)
384 return get_widget_instance (widget, False);
387 static widget_instance*
388 find_instance (LWLIB_ID id, Widget parent, Boolean pop_up_p)
390 widget_info* info = get_widget_info (id, False);
391 widget_instance* instance;
393 if (info)
394 for (instance = info->instances; instance; instance = instance->next)
395 if (instance->parent == parent && instance->pop_up_p == pop_up_p)
396 return instance;
398 return NULL;
402 /* utility function for widget_value */
403 static Boolean
404 safe_strcmp (const char *s1, const char *s2)
406 if (!!s1 ^ !!s2) return True;
407 return (s1 && s2) ? strcmp (s1, s2) : s1 ? False : !!s2;
411 #if 0
412 # define EXPLAIN(name, oc, nc, desc, a1, a2) \
413 printf ("Change: \"%s\"\tmax(%s=%d,%s=%d)\t%s %d %d\n", \
414 name, \
415 (oc == NO_CHANGE ? "none" : \
416 (oc == INVISIBLE_CHANGE ? "invisible" : \
417 (oc == VISIBLE_CHANGE ? "visible" : \
418 (oc == STRUCTURAL_CHANGE ? "structural" : "???")))), \
419 oc, \
420 (nc == NO_CHANGE ? "none" : \
421 (nc == INVISIBLE_CHANGE ? "invisible" : \
422 (nc == VISIBLE_CHANGE ? "visible" : \
423 (nc == STRUCTURAL_CHANGE ? "structural" : "???")))), \
424 nc, desc, a1, a2)
425 #else
426 # define EXPLAIN(name, oc, nc, desc, a1, a2)
427 #endif
430 static widget_value *
431 merge_widget_value (widget_value *val1,
432 widget_value *val2,
433 int level,
434 int *change_p)
436 change_type change, this_one_change;
437 widget_value* merged_next;
438 widget_value* merged_contents;
440 if (!val1)
442 if (val2)
444 *change_p = 1;
445 return copy_widget_value_tree (val2, STRUCTURAL_CHANGE);
447 else
448 return NULL;
450 if (!val2)
452 *change_p = 1;
453 free_widget_value_tree (val1);
454 return NULL;
457 change = NO_CHANGE;
459 if (safe_strcmp (val1->name, val2->name))
461 EXPLAIN (val1->name, change, STRUCTURAL_CHANGE, "name change",
462 val1->name, val2->name);
463 change = max (change, STRUCTURAL_CHANGE);
464 safe_free_str (val1->name);
465 val1->name = safe_strdup (val2->name);
467 if (safe_strcmp (val1->value, val2->value))
469 EXPLAIN (val1->name, change, VISIBLE_CHANGE, "value change",
470 val1->value, val2->value);
471 change = max (change, VISIBLE_CHANGE);
472 safe_free_str (val1->value);
473 val1->value = safe_strdup (val2->value);
475 if (safe_strcmp (val1->key, val2->key))
477 EXPLAIN (val1->name, change, VISIBLE_CHANGE, "key change",
478 val1->key, val2->key);
479 change = max (change, VISIBLE_CHANGE);
480 safe_free_str (val1->key);
481 val1->key = safe_strdup (val2->key);
483 if (! EQ (val1->help, val2->help))
485 EXPLAIN (val1->name, change, VISIBLE_CHANGE, "help change",
486 val1->help, val2->help);
487 change = max (change, VISIBLE_CHANGE);
488 val1->help = val2->help;
490 if (val1->enabled != val2->enabled)
492 EXPLAIN (val1->name, change, VISIBLE_CHANGE, "enablement change",
493 val1->enabled, val2->enabled);
494 change = max (change, VISIBLE_CHANGE);
495 val1->enabled = val2->enabled;
497 if (val1->button_type != val2->button_type)
499 EXPLAIN (val1->name, change, VISIBLE_CHANGE, "button type change",
500 val1->button_type, val2->button_type);
501 change = max (change, VISIBLE_CHANGE);
502 val1->button_type = val2->button_type;
504 if (val1->selected != val2->selected)
506 EXPLAIN (val1->name, change, VISIBLE_CHANGE, "selection change",
507 val1->selected, val2->selected);
508 change = max (change, VISIBLE_CHANGE);
509 val1->selected = val2->selected;
511 if (val1->call_data != val2->call_data)
513 EXPLAIN (val1->name, change, INVISIBLE_CHANGE, "call-data change",
514 val1->call_data, val2->call_data);
515 change = max (change, INVISIBLE_CHANGE);
516 val1->call_data = val2->call_data;
519 if (level > 0)
521 merged_contents =
522 merge_widget_value (val1->contents, val2->contents, level - 1,
523 change_p);
525 if (val1->contents && !merged_contents)
527 /* This used to say INVISIBLE_CHANGE,
528 but it is visible and vitally important when
529 the contents of the menu bar itself are entirely deleted.
531 But maybe it doesn't matter. This fails to fix the bug. */
532 EXPLAIN (val1->name, change, STRUCTURAL_CHANGE, "(contents gone)",
533 0, 0);
534 change = max (change, STRUCTURAL_CHANGE);
536 else if (merged_contents && merged_contents->change != NO_CHANGE)
538 EXPLAIN (val1->name, change, INVISIBLE_CHANGE, "(contents change)",
539 0, 0);
540 change = max (change, INVISIBLE_CHANGE);
541 #if 0 /* This was replaced by the August 9 1996 change in lwlib-Xm.c. */
542 #ifdef USE_MOTIF
543 change = max (merged_contents->change, change);
544 #endif
545 #endif
548 val1->contents = merged_contents;
551 this_one_change = change;
553 merged_next = merge_widget_value (val1->next, val2->next, level, change_p);
555 if (val1->next && !merged_next)
557 EXPLAIN (val1->name, change, STRUCTURAL_CHANGE, "(following gone)",
558 0, 0);
559 change = max (change, STRUCTURAL_CHANGE);
561 else if (merged_next)
563 if (merged_next->change)
564 EXPLAIN (val1->name, change, merged_next->change, "(following change)",
565 0, 0);
566 change = max (change, merged_next->change);
569 val1->next = merged_next;
571 val1->this_one_change = this_one_change;
572 val1->change = change;
574 if (change > NO_CHANGE && val1->toolkit_data)
576 *change_p = 1;
577 if (val1->free_toolkit_data)
578 XtFree (val1->toolkit_data);
579 val1->toolkit_data = NULL;
582 return val1;
586 /* modifying the widgets */
587 static Widget
588 name_to_widget (widget_instance *instance, const char *name)
590 Widget widget = NULL;
592 if (!instance->widget)
593 return NULL;
595 if (!strcmp (XtName (instance->widget), name))
596 widget = instance->widget;
597 else
599 int length = strlen (name) + 2;
600 char* real_name = (char *) xmalloc (length);
601 real_name [0] = '*';
602 strcpy (real_name + 1, name);
604 widget = XtNameToWidget (instance->widget, real_name);
606 free (real_name);
608 return widget;
611 static void
612 set_one_value (widget_instance* instance, widget_value* val, Boolean deep_p)
614 Widget widget = name_to_widget (instance, val->name);
616 if (widget)
618 #if defined (USE_LUCID)
619 if (lw_lucid_widget_p (instance->widget))
620 xlw_update_one_widget (instance, widget, val, deep_p);
621 #endif
622 #if defined (USE_MOTIF)
623 if (lw_motif_widget_p (instance->widget))
624 xm_update_one_widget (instance, widget, val, deep_p);
625 #endif
626 #if defined (USE_XAW)
627 if (lw_xaw_widget_p (instance->widget))
628 xaw_update_one_widget (instance, widget, val, deep_p);
629 #endif
633 static void
634 update_one_widget_instance (widget_instance* instance, Boolean deep_p)
636 widget_value *val;
638 if (!instance->widget)
639 /* the widget was destroyed */
640 return;
642 for (val = instance->info->val; val; val = val->next)
643 if (val->change != NO_CHANGE)
644 set_one_value (instance, val, deep_p);
647 static void
648 update_all_widget_values (widget_info* info, Boolean deep_p)
650 widget_instance* instance;
651 widget_value* val;
653 for (instance = info->instances; instance; instance = instance->next)
654 update_one_widget_instance (instance, deep_p);
656 for (val = info->val; val; val = val->next)
657 val->change = NO_CHANGE;
661 lw_modify_all_widgets (LWLIB_ID id, widget_value* val, Boolean deep_p)
663 widget_info* info = get_widget_info (id, False);
664 widget_value* new_val;
665 widget_value* next_new_val;
666 widget_value* cur;
667 widget_value* prev;
668 widget_value* next;
669 int found;
670 int change_p = 0;
672 if (!info)
673 return 0;
675 for (new_val = val; new_val; new_val = new_val->next)
677 next_new_val = new_val->next;
678 new_val->next = NULL;
679 found = False;
680 for (prev = NULL, cur = info->val; cur; prev = cur, cur = cur->next)
681 if (!strcmp (cur->name, new_val->name))
683 found = True;
684 next = cur->next;
685 cur->next = NULL;
686 cur = merge_widget_value (cur, new_val, deep_p ? 1000 : 1,
687 &change_p);
688 if (prev)
689 prev->next = cur ? cur : next;
690 else
691 info->val = cur ? cur : next;
692 if (cur)
693 cur->next = next;
694 break;
696 if (!found)
698 /* Could not find it, add it */
699 if (prev)
700 prev->next = copy_widget_value_tree (new_val, STRUCTURAL_CHANGE);
701 else
702 info->val = copy_widget_value_tree (new_val, STRUCTURAL_CHANGE);
703 change_p = 1;
705 new_val->next = next_new_val;
708 update_all_widget_values (info, deep_p);
709 return change_p;
713 /* creating the widgets */
715 static void
716 initialize_widget_instance (widget_instance *instance)
718 widget_value* val;
720 for (val = instance->info->val; val; val = val->next)
721 val->change = STRUCTURAL_CHANGE;
723 update_one_widget_instance (instance, True);
725 for (val = instance->info->val; val; val = val->next)
726 val->change = NO_CHANGE;
730 static widget_creation_function
731 find_in_table (const char *type, const widget_creation_entry *table)
733 const widget_creation_entry* cur;
734 for (cur = table; cur->type; cur++)
735 if (!my_strcasecmp (type, cur->type))
736 return cur->function;
737 return NULL;
740 static Boolean
741 dialog_spec_p (const char *name)
743 /* return True if name matches [EILPQeilpq][1-9][Bb] or
744 [EILPQeilpq][1-9][Bb][Rr][1-9] */
745 if (!name)
746 return False;
748 switch (name [0])
750 case 'E': case 'I': case 'L': case 'P': case 'Q':
751 case 'e': case 'i': case 'l': case 'p': case 'q':
752 if (name [1] >= '0' && name [1] <= '9')
754 if (name [2] != 'B' && name [2] != 'b')
755 return False;
756 if (!name [3])
757 return True;
758 if ((name [3] == 'T' || name [3] == 't') && !name [4])
759 return True;
760 if ((name [3] == 'R' || name [3] == 'r')
761 && name [4] >= '0' && name [4] <= '9' && !name [5])
762 return True;
763 return False;
765 else
766 return False;
768 default:
769 return False;
773 static void
774 instantiate_widget_instance (widget_instance *instance)
776 widget_creation_function function = NULL;
778 #if defined (USE_LUCID)
779 if (!function)
780 function = find_in_table (instance->info->type, xlw_creation_table);
781 #endif
782 #if defined(USE_MOTIF)
783 if (!function)
784 function = find_in_table (instance->info->type, xm_creation_table);
785 #endif
786 #if defined (USE_XAW)
787 if (!function)
788 function = find_in_table (instance->info->type, xaw_creation_table);
789 #endif
791 if (!function)
793 if (dialog_spec_p (instance->info->type))
795 #if defined (USE_LUCID)
796 /* not yet */
797 #endif
798 #if defined(USE_MOTIF)
799 if (!function)
800 function = xm_create_dialog;
801 #endif
802 #if defined (USE_XAW)
803 if (!function)
804 function = xaw_create_dialog;
805 #endif
809 if (!function)
811 printf ("No creation function for widget type %s\n",
812 instance->info->type);
813 abort ();
816 instance->widget = (*function) (instance);
818 if (!instance->widget)
819 abort ();
821 /* XtRealizeWidget (instance->widget);*/
824 void
825 lw_register_widget (const char* type,
826 const char* name,
827 LWLIB_ID id,
828 widget_value* val,
829 lw_callback pre_activate_cb,
830 lw_callback selection_cb,
831 lw_callback post_activate_cb,
832 lw_callback highlight_cb)
834 if (!get_widget_info (id, False))
835 allocate_widget_info (type, name, id, val, pre_activate_cb, selection_cb,
836 post_activate_cb, highlight_cb);
839 Widget
840 lw_get_widget (LWLIB_ID id, Widget parent, Boolean pop_up_p)
842 widget_instance* instance;
844 instance = find_instance (id, parent, pop_up_p);
845 return instance ? instance->widget : NULL;
848 Widget
849 lw_make_widget (LWLIB_ID id, Widget parent, Boolean pop_up_p)
851 widget_instance* instance;
852 widget_info* info;
854 instance = find_instance (id, parent, pop_up_p);
855 if (!instance)
857 info = get_widget_info (id, False);
858 if (!info)
859 return NULL;
860 instance = allocate_widget_instance (info, parent, pop_up_p);
861 initialize_widget_instance (instance);
863 if (!instance->widget)
864 abort ();
865 return instance->widget;
868 Widget
869 lw_create_widget (const char* type, const char* name, LWLIB_ID id, widget_value* val,
870 Widget parent, Boolean pop_up_p,
871 lw_callback pre_activate_cb, lw_callback selection_cb,
872 lw_callback post_activate_cb, lw_callback highlight_cb)
874 lw_register_widget (type, name, id, val, pre_activate_cb, selection_cb,
875 post_activate_cb, highlight_cb);
876 return lw_make_widget (id, parent, pop_up_p);
880 /* destroying the widgets */
881 static void
882 destroy_one_instance (widget_instance *instance)
884 /* Remove the destroy callback on the widget; that callback will try to
885 dereference the instance object (to set its widget slot to 0, since the
886 widget is dead.) Since the instance is now dead, we don't have to worry
887 about the fact that its widget is dead too.
889 This happens in the Phase2Destroy of the widget, so this callback would
890 not have been run until arbitrarily long after the instance was freed.
892 if (instance->widget)
893 XtRemoveCallback (instance->widget, XtNdestroyCallback,
894 mark_widget_destroyed, (XtPointer)instance);
896 if (instance->widget)
898 /* The else are pretty tricky here, including the empty statement
899 at the end because it would be very bad to destroy a widget
900 twice. */
901 #if defined (USE_LUCID)
902 if (lw_lucid_widget_p (instance->widget))
903 xlw_destroy_instance (instance);
904 else
905 #endif
906 #if defined (USE_MOTIF)
907 if (lw_motif_widget_p (instance->widget))
908 xm_destroy_instance (instance);
909 else
910 #endif
911 #if defined (USE_XAW)
912 if (lw_xaw_widget_p (instance->widget))
913 xaw_destroy_instance (instance);
914 else
915 #endif
916 /* do not remove the empty statement */
920 free_widget_instance (instance);
923 void
924 lw_destroy_widget (Widget w)
926 widget_instance* instance = get_widget_instance (w, True);
928 if (instance)
930 widget_info *info = instance->info;
931 /* instance has already been removed from the list; free it */
932 destroy_one_instance (instance);
933 /* if there are no instances left, free the info too */
934 if (!info->instances)
935 lw_destroy_all_widgets (info->id);
939 void
940 lw_destroy_all_widgets (LWLIB_ID id)
942 widget_info* info = get_widget_info (id, True);
943 widget_instance* instance;
944 widget_instance* next;
946 if (info)
948 for (instance = info->instances; instance; )
950 next = instance->next;
951 destroy_one_instance (instance);
952 instance = next;
954 free_widget_info (info);
958 void
959 lw_destroy_everything (void)
961 while (all_widget_info)
962 lw_destroy_all_widgets (all_widget_info->id);
965 void
966 lw_destroy_all_pop_ups (void)
968 widget_info* info;
969 widget_info* next;
970 widget_instance* instance;
972 for (info = all_widget_info; info; info = next)
974 next = info->next;
975 instance = info->instances;
976 if (instance && instance->pop_up_p)
977 lw_destroy_all_widgets (info->id);
981 #ifdef USE_MOTIF
982 extern Widget first_child (/* Widget */); /* garbage */
983 #endif
985 Widget
986 lw_raise_all_pop_up_widgets (void)
988 widget_info* info;
989 widget_instance* instance;
990 Widget result = NULL;
992 for (info = all_widget_info; info; info = info->next)
993 for (instance = info->instances; instance; instance = instance->next)
994 if (instance->pop_up_p)
996 Widget widget = instance->widget;
997 if (widget)
999 if (XtIsManaged (widget)
1000 #ifdef USE_MOTIF
1001 /* What a complete load of crap!!!!
1002 When a dialogShell is on the screen, it is not managed!
1004 || (lw_motif_widget_p (instance->widget) &&
1005 XtIsManaged (first_child (widget)))
1006 #endif
1009 if (!result)
1010 result = widget;
1011 XMapRaised (XtDisplay (widget), XtWindow (widget));
1015 return result;
1018 static void
1019 lw_pop_all_widgets (LWLIB_ID id, Boolean up)
1021 widget_info* info = get_widget_info (id, False);
1022 widget_instance* instance;
1024 if (info)
1025 for (instance = info->instances; instance; instance = instance->next)
1026 if (instance->pop_up_p && instance->widget)
1028 #if defined (USE_LUCID)
1029 if (lw_lucid_widget_p (instance->widget))
1031 XtRealizeWidget (instance->widget);
1032 xlw_pop_instance (instance, up);
1034 #endif
1035 #if defined (USE_MOTIF)
1036 if (lw_motif_widget_p (instance->widget))
1038 XtRealizeWidget (instance->widget);
1039 xm_pop_instance (instance, up);
1041 #endif
1042 #if defined (USE_XAW)
1043 if (lw_xaw_widget_p (instance->widget))
1045 XtRealizeWidget (XtParent (instance->widget));
1046 XtRealizeWidget (instance->widget);
1047 xaw_pop_instance (instance, up);
1049 #endif
1053 void
1054 lw_pop_up_all_widgets (LWLIB_ID id)
1056 lw_pop_all_widgets (id, True);
1059 void
1060 lw_pop_down_all_widgets (LWLIB_ID id)
1062 lw_pop_all_widgets (id, False);
1065 void
1066 lw_popup_menu (Widget widget, XEvent *event)
1068 #if defined (USE_LUCID)
1069 if (lw_lucid_widget_p (widget))
1070 xlw_popup_menu (widget, event);
1071 #endif
1072 #if defined (USE_MOTIF)
1073 if (lw_motif_widget_p (widget))
1074 xm_popup_menu (widget, event);
1075 #endif
1076 #if defined (USE_XAW)
1077 if (lw_xaw_widget_p (widget))
1078 xaw_popup_menu (widget, event);
1079 #endif
1082 \f/* get the values back */
1083 static Boolean
1084 get_one_value (widget_instance *instance, widget_value *val)
1086 Widget widget = name_to_widget (instance, val->name);
1088 if (widget)
1090 #if defined (USE_LUCID)
1091 if (lw_lucid_widget_p (instance->widget))
1092 xlw_update_one_value (instance, widget, val);
1093 #endif
1094 #if defined (USE_MOTIF)
1095 if (lw_motif_widget_p (instance->widget))
1096 xm_update_one_value (instance, widget, val);
1097 #endif
1098 #if defined (USE_XAW)
1099 if (lw_xaw_widget_p (instance->widget))
1100 xaw_update_one_value (instance, widget, val);
1101 #endif
1102 return True;
1104 else
1105 return False;
1108 Boolean
1109 lw_get_some_values (LWLIB_ID id, widget_value *val_out)
1111 widget_info* info = get_widget_info (id, False);
1112 widget_instance* instance;
1113 widget_value* val;
1114 Boolean result = False;
1116 if (!info)
1117 return False;
1119 instance = info->instances;
1120 if (!instance)
1121 return False;
1123 for (val = val_out; val; val = val->next)
1124 if (get_one_value (instance, val))
1125 result = True;
1127 return result;
1130 widget_value*
1131 lw_get_all_values (LWLIB_ID id)
1133 widget_info* info = get_widget_info (id, False);
1134 widget_value* val = info->val;
1135 if (lw_get_some_values (id, val))
1136 return val;
1137 else
1138 return NULL;
1141 /* internal function used by the library dependent implementation to get the
1142 widget_value for a given widget in an instance */
1143 widget_value*
1144 lw_get_widget_value_for_widget (widget_instance *instance, Widget w)
1146 char* name = XtName (w);
1147 widget_value* cur;
1148 for (cur = instance->info->val; cur; cur = cur->next)
1149 if (!strcmp (cur->name, name))
1150 return cur;
1151 return NULL;
1154 \f/* update other instances value when one thing changed */
1156 /* To forbid recursive calls */
1157 static Boolean lwlib_updating;
1159 /* This function can be used as a an XtCallback for the widgets that get
1160 modified to update other instances of the widgets. Closure should be the
1161 widget_instance. */
1162 void
1163 lw_internal_update_other_instances (Widget widget,
1164 XtPointer closure,
1165 XtPointer call_data)
1167 widget_instance* instance = (widget_instance*)closure;
1168 char* name = XtName (widget);
1169 widget_info* info;
1170 widget_instance* cur;
1171 widget_value* val;
1173 /* Avoid possibly infinite recursion. */
1174 if (lwlib_updating)
1175 return;
1177 /* protect against the widget being destroyed */
1178 if (XtWidgetBeingDestroyedP (widget))
1179 return;
1181 /* Return immediately if there are no other instances */
1182 info = instance->info;
1183 if (!info->instances->next)
1184 return;
1186 lwlib_updating = True;
1188 for (val = info->val; val && strcmp (val->name, name); val = val->next);
1190 if (val && get_one_value (instance, val))
1191 for (cur = info->instances; cur; cur = cur->next)
1192 if (cur != instance)
1193 set_one_value (cur, val, True);
1195 lwlib_updating = False;
1199 \f/* get the id */
1201 LWLIB_ID
1202 lw_get_widget_id (Widget w)
1204 widget_instance* instance = get_widget_instance (w, False);
1206 return instance ? instance->info->id : 0;
1209 \f/* set the keyboard focus */
1210 void
1211 lw_set_keyboard_focus (Widget parent, Widget w)
1213 #if defined (USE_MOTIF)
1214 xm_set_keyboard_focus (parent, w);
1215 #else
1216 XtSetKeyboardFocus (parent, w);
1217 #endif
1220 \f/* Show busy */
1221 static void
1222 show_one_widget_busy (Widget w, Boolean flag)
1224 Pixel foreground = 0;
1225 Pixel background = 1;
1226 Widget widget_to_invert = XtNameToWidget (w, "*sheet");
1227 if (!widget_to_invert)
1228 widget_to_invert = w;
1230 XtVaGetValues (widget_to_invert,
1231 XtNforeground, &foreground,
1232 XtNbackground, &background,
1233 NULL);
1234 XtVaSetValues (widget_to_invert,
1235 XtNforeground, background,
1236 XtNbackground, foreground,
1237 NULL);
1240 void
1241 lw_show_busy (Widget w, Boolean busy)
1243 widget_instance* instance = get_widget_instance (w, False);
1244 widget_info* info;
1245 widget_instance* next;
1247 if (instance)
1249 info = instance->info;
1250 if (info->busy != busy)
1252 for (next = info->instances; next; next = next->next)
1253 if (next->widget)
1254 show_one_widget_busy (next->widget, busy);
1255 info->busy = busy;
1260 /* This hack exists because Lucid/Athena need to execute the strange
1261 function below to support geometry management. */
1262 void
1263 lw_refigure_widget (Widget w, Boolean doit)
1265 #if defined (USE_XAW)
1266 XawPanedSetRefigureMode (w, doit);
1267 #endif
1268 #if defined (USE_MOTIF)
1269 if (doit)
1270 XtManageChild (w);
1271 else
1272 XtUnmanageChild (w);
1273 #endif
1276 /* Toolkit independent way of determining if an event window is in the
1277 menubar. */
1278 Boolean
1279 lw_window_is_in_menubar (Window win, Widget menubar_widget)
1281 return menubar_widget
1282 #if defined (USE_LUCID)
1283 && XtWindow (menubar_widget) == win;
1284 #endif
1285 #if defined (USE_MOTIF)
1286 && ((XtWindow (menubar_widget) == win)
1287 || (XtWindowToWidget (XtDisplay (menubar_widget), win)
1288 && (XtParent (XtWindowToWidget (XtDisplay (menubar_widget), win))
1289 == menubar_widget)));
1290 #endif
1293 /* Motif hack to set the main window areas. */
1294 void
1295 lw_set_main_areas (Widget parent, Widget menubar, Widget work_area)
1297 #if defined (USE_MOTIF)
1298 xm_set_main_areas (parent, menubar, work_area);
1299 #endif
1302 /* Manage resizing for Motif. This disables resizing when the menubar
1303 is about to be modified. */
1304 void
1305 lw_allow_resizing (Widget w, Boolean flag)
1307 #if defined (USE_MOTIF)
1308 xm_manage_resizing (w, flag);
1309 #endif
1313 /* Value is non-zero if LABEL is a menu separator. If it is, *TYPE is
1314 set to an appropriate enumerator of type enum menu_separator.
1315 MOTIF_P non-zero means map separator types not supported by Motif
1316 to similar ones that are supported. */
1319 lw_separator_p (const char *label, enum menu_separator *type, int motif_p)
1321 int separator_p = 0;
1323 if (strlen (label) >= 3
1324 && memcmp (label, "--:", 3) == 0)
1326 static struct separator_table
1328 const char *name;
1329 enum menu_separator type;
1331 separator_names[] =
1333 {"space", SEPARATOR_NO_LINE},
1334 {"noLine", SEPARATOR_NO_LINE},
1335 {"singleLine", SEPARATOR_SINGLE_LINE},
1336 {"doubleLine", SEPARATOR_DOUBLE_LINE},
1337 {"singleDashedLine", SEPARATOR_SINGLE_DASHED_LINE},
1338 {"doubleDashedLine", SEPARATOR_DOUBLE_DASHED_LINE},
1339 {"shadowEtchedIn", SEPARATOR_SHADOW_ETCHED_IN},
1340 {"shadowEtchedOut", SEPARATOR_SHADOW_ETCHED_OUT},
1341 {"shadowEtchedInDash", SEPARATOR_SHADOW_ETCHED_IN_DASH},
1342 {"shadowEtchedOutDash", SEPARATOR_SHADOW_ETCHED_OUT_DASH},
1343 {"shadowDoubleEtchedIn", SEPARATOR_SHADOW_DOUBLE_ETCHED_IN},
1344 {"shadowDoubleEtchedOut", SEPARATOR_SHADOW_DOUBLE_ETCHED_OUT},
1345 {"shadowDoubleEtchedInDash", SEPARATOR_SHADOW_DOUBLE_ETCHED_IN_DASH},
1346 {"shadowDoubleEtchedOutDash", SEPARATOR_SHADOW_DOUBLE_ETCHED_OUT_DASH},
1347 {0,0}
1350 int i;
1352 label += 3;
1353 for (i = 0; separator_names[i].name; ++i)
1354 if (strcmp (label, separator_names[i].name) == 0)
1356 separator_p = 1;
1357 *type = separator_names[i].type;
1359 /* If separator type is not supported under Motif,
1360 use a similar one. */
1361 if (motif_p && *type >= SEPARATOR_SHADOW_DOUBLE_ETCHED_IN)
1362 *type -= 4;
1363 break;
1366 else if (strlen (label) > 3
1367 && memcmp (label, "--", 2) == 0
1368 && label[2] != '-')
1370 /* Alternative, more Emacs-style names. */
1371 static struct separator_table
1373 const char *name;
1374 enum menu_separator type;
1376 separator_names[] =
1378 {"space", SEPARATOR_NO_LINE},
1379 {"no-line", SEPARATOR_NO_LINE},
1380 {"single-line", SEPARATOR_SINGLE_LINE},
1381 {"double-line", SEPARATOR_DOUBLE_LINE},
1382 {"single-dashed-line", SEPARATOR_SINGLE_DASHED_LINE},
1383 {"double-dashed-line", SEPARATOR_DOUBLE_DASHED_LINE},
1384 {"shadow-etched-in", SEPARATOR_SHADOW_ETCHED_IN},
1385 {"shadow-etched-out", SEPARATOR_SHADOW_ETCHED_OUT},
1386 {"shadow-etched-in-dash", SEPARATOR_SHADOW_ETCHED_IN_DASH},
1387 {"shadow-etched-out-dash", SEPARATOR_SHADOW_ETCHED_OUT_DASH},
1388 {"shadow-double-etched-in", SEPARATOR_SHADOW_DOUBLE_ETCHED_IN},
1389 {"shadow-double-etched-out", SEPARATOR_SHADOW_DOUBLE_ETCHED_OUT},
1390 {"shadow-double-etched-in-dash", SEPARATOR_SHADOW_DOUBLE_ETCHED_IN_DASH},
1391 {"shadow-double-etched-out-dash",SEPARATOR_SHADOW_DOUBLE_ETCHED_OUT_DASH},
1392 {0,0}
1395 int i;
1397 label += 2;
1398 for (i = 0; separator_names[i].name; ++i)
1399 if (strcmp (label, separator_names[i].name) == 0)
1401 separator_p = 1;
1402 *type = separator_names[i].type;
1404 /* If separator type is not supported under Motif,
1405 use a similar one. */
1406 if (motif_p && *type >= SEPARATOR_SHADOW_DOUBLE_ETCHED_IN)
1407 *type -= 4;
1408 break;
1411 else
1413 /* Old-style separator, maybe. It's a separator if it contains
1414 only dashes. */
1415 while (*label == '-')
1416 ++label;
1417 separator_p = *label == 0;
1418 *type = SEPARATOR_SHADOW_ETCHED_IN;
1421 return separator_p;