Fix bug #13515 with processing DBCS file names on MS-Windows.
[emacs.git] / lwlib / lwlib.c
blob7d9920e8bce3e24de0ad862b0306e700151b523b
1 /* A general interface to the widgets of different toolkits.
3 Copyright (C) 1992, 1993 Lucid, Inc.
4 Copyright (C) 1994-1996, 1999-2013 Free Software Foundation, Inc.
6 This file is part of the Lucid Widget Library.
8 The Lucid Widget Library is free software; you can redistribute it and/or
9 modify it under the terms of the GNU General Public License as published by
10 the Free Software Foundation; either version 2, or (at your option)
11 any later version.
13 The Lucid Widget Library is distributed in the hope that it will be useful,
14 but WITHOUT ANY WARRANTY; without even the implied warranty of
15 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 GNU General Public License for more details.
18 You should have received a copy of the GNU General Public License
19 along with GNU Emacs. If not, see <http://www.gnu.org/licenses/>. */
21 #include <config.h>
23 #include <setjmp.h>
24 #include <lisp.h>
25 #include <c-strcase.h>
27 #include <sys/types.h>
28 #include <stdio.h>
29 #include "lwlib-int.h"
30 #include "lwlib-utils.h"
31 #include <X11/StringDefs.h>
33 #if defined (USE_LUCID)
34 #include "lwlib-Xlw.h"
35 #endif
36 #if defined (USE_MOTIF)
37 #include "lwlib-Xm.h"
38 #else /* not USE_MOTIF */
39 #if defined (USE_LUCID)
40 #define USE_XAW
41 #endif /* not USE_MOTIF && USE_LUCID */
42 #endif
43 #if defined (USE_XAW)
44 #ifdef HAVE_XAW3D
45 #include <X11/Xaw3d/Paned.h>
46 #else /* !HAVE_XAW3D */
47 #include <X11/Xaw/Paned.h>
48 #endif /* HAVE_XAW3D */
49 #include "lwlib-Xaw.h"
50 #endif
52 #if !defined (USE_LUCID) && !defined (USE_MOTIF)
53 #error At least one of USE_LUCID or USE_MOTIF must be defined.
54 #endif
56 #ifndef max
57 #define max(x, y) ((x) > (y) ? (x) : (y))
58 #endif
60 /* List of all widgets managed by the library. */
61 static widget_info*
62 all_widget_info = NULL;
64 #ifdef USE_MOTIF
65 const char *lwlib_toolkit_type = "motif";
66 #else
67 const char *lwlib_toolkit_type = "lucid";
68 #endif
70 static widget_value *merge_widget_value (widget_value *,
71 widget_value *,
72 int, int *);
73 static void instantiate_widget_instance (widget_instance *);
74 static void safe_free_str (char *);
75 static void free_widget_value_tree (widget_value *);
76 static widget_value *copy_widget_value_tree (widget_value *,
77 change_type);
78 static widget_info *allocate_widget_info (const char *, const char *, LWLIB_ID,
79 widget_value *,
80 lw_callback, lw_callback,
81 lw_callback, lw_callback);
82 static void free_widget_info (widget_info *);
83 static void mark_widget_destroyed (Widget, XtPointer, XtPointer);
84 static widget_instance *allocate_widget_instance (widget_info *,
85 Widget, Boolean);
86 static void free_widget_instance (widget_instance *);
87 static widget_info *get_widget_info (LWLIB_ID, Boolean);
88 static widget_instance *get_widget_instance (Widget, Boolean);
89 static widget_instance *find_instance (LWLIB_ID, Widget, Boolean);
90 static Boolean safe_strcmp (const char *, const char *);
91 static Widget name_to_widget (widget_instance *, const char *);
92 static void set_one_value (widget_instance *, widget_value *, Boolean);
93 static void update_one_widget_instance (widget_instance *, Boolean);
94 static void update_all_widget_values (widget_info *, Boolean);
95 static void initialize_widget_instance (widget_instance *);
96 static widget_creation_function find_in_table (const char *, const widget_creation_entry *);
97 static Boolean dialog_spec_p (const char *);
98 static void destroy_one_instance (widget_instance *);
99 static void lw_pop_all_widgets (LWLIB_ID, Boolean);
100 static Boolean get_one_value (widget_instance *, widget_value *);
101 static void show_one_widget_busy (Widget, Boolean);
102 \f/* utility functions for widget_instance and widget_info */
103 char *
104 safe_strdup (const char *s)
106 char *result;
107 if (! s) return 0;
108 result = (char *) xmalloc (strlen (s) + 1);
109 strcpy (result, s);
110 return result;
113 static void
114 safe_free_str (char *s)
116 xfree (s);
119 static widget_value *widget_value_free_list = 0;
120 static int malloc_cpt = 0;
122 widget_value *
123 malloc_widget_value (void)
125 widget_value *wv;
126 if (widget_value_free_list)
128 wv = widget_value_free_list;
129 widget_value_free_list = wv->free_list;
130 wv->free_list = 0;
132 else
134 wv = (widget_value *) xmalloc (sizeof (widget_value));
135 malloc_cpt++;
137 memset ((void*) wv, 0, sizeof (widget_value));
138 return wv;
141 /* this is analogous to free(). It frees only what was allocated
142 by malloc_widget_value(), and no substructures.
144 void
145 free_widget_value (widget_value *wv)
147 if (wv->free_list)
148 abort ();
150 if (malloc_cpt > 25)
152 /* When the number of already allocated cells is too big,
153 We free it. */
154 xfree (wv);
155 malloc_cpt--;
157 else
159 wv->free_list = widget_value_free_list;
160 widget_value_free_list = wv;
164 static void
165 free_widget_value_tree (widget_value *wv)
167 if (!wv)
168 return;
170 xfree (wv->name);
171 xfree (wv->value);
172 xfree (wv->key);
174 wv->name = wv->value = wv->key = (char *) 0xDEADBEEF;
176 if (wv->toolkit_data && wv->free_toolkit_data)
178 XtFree (wv->toolkit_data);
179 wv->toolkit_data = (void *) 0xDEADBEEF;
182 if (wv->contents && (wv->contents != (widget_value*)1))
184 free_widget_value_tree (wv->contents);
185 wv->contents = (widget_value *) 0xDEADBEEF;
187 if (wv->next)
189 free_widget_value_tree (wv->next);
190 wv->next = (widget_value *) 0xDEADBEEF;
192 free_widget_value (wv);
195 static widget_value *
196 copy_widget_value_tree (widget_value *val, change_type change)
198 widget_value* copy;
200 if (!val)
201 return NULL;
202 if (val == (widget_value *) 1)
203 return val;
205 copy = malloc_widget_value ();
206 copy->name = safe_strdup (val->name);
207 copy->value = safe_strdup (val->value);
208 copy->key = safe_strdup (val->key);
209 copy->help = val->help;
210 copy->enabled = val->enabled;
211 copy->button_type = val->button_type;
212 copy->selected = val->selected;
213 copy->edited = False;
214 copy->change = change;
215 copy->this_one_change = change;
216 copy->contents = copy_widget_value_tree (val->contents, change);
217 copy->call_data = val->call_data;
218 copy->next = copy_widget_value_tree (val->next, change);
219 copy->toolkit_data = NULL;
220 copy->free_toolkit_data = False;
221 return copy;
224 static widget_info *
225 allocate_widget_info (const char* type,
226 const char* name,
227 LWLIB_ID id,
228 widget_value* val,
229 lw_callback pre_activate_cb,
230 lw_callback selection_cb,
231 lw_callback post_activate_cb,
232 lw_callback highlight_cb)
234 widget_info* info = (widget_info*) xmalloc (sizeof (widget_info));
235 info->type = safe_strdup (type);
236 info->name = safe_strdup (name);
237 info->id = id;
238 info->val = copy_widget_value_tree (val, STRUCTURAL_CHANGE);
239 info->busy = False;
240 info->pre_activate_cb = pre_activate_cb;
241 info->selection_cb = selection_cb;
242 info->post_activate_cb = post_activate_cb;
243 info->highlight_cb = highlight_cb;
244 info->instances = NULL;
246 info->next = all_widget_info;
247 all_widget_info = info;
249 return info;
252 static void
253 free_widget_info (widget_info *info)
255 safe_free_str (info->type);
256 safe_free_str (info->name);
257 free_widget_value_tree (info->val);
258 memset ((void*)info, 0xDEADBEEF, sizeof (widget_info));
259 xfree (info);
262 static void
263 mark_widget_destroyed (Widget widget, XtPointer closure, XtPointer call_data)
265 widget_instance* instance = (widget_instance*)closure;
267 /* be very conservative */
268 if (instance->widget == widget)
269 instance->widget = NULL;
272 static widget_instance *
273 allocate_widget_instance (widget_info* info, Widget parent, Boolean pop_up_p)
275 widget_instance* instance =
276 (widget_instance*) xmalloc (sizeof (widget_instance));
277 memset (instance, 0, sizeof *instance);
278 instance->parent = parent;
279 instance->pop_up_p = pop_up_p;
280 instance->info = info;
281 instance->next = info->instances;
282 info->instances = instance;
284 instantiate_widget_instance (instance);
286 XtAddCallback (instance->widget, XtNdestroyCallback,
287 mark_widget_destroyed, (XtPointer)instance);
288 return instance;
291 static void
292 free_widget_instance (widget_instance *instance)
294 memset ((void*)instance, 0xDEADBEEF, sizeof (widget_instance));
295 xfree (instance);
298 static widget_info *
299 get_widget_info (LWLIB_ID id, Boolean remove_p)
301 widget_info* info;
302 widget_info* prev;
303 for (prev = NULL, info = all_widget_info;
304 info;
305 prev = info, info = info->next)
306 if (info->id == id)
308 if (remove_p)
310 if (prev)
311 prev->next = info->next;
312 else
313 all_widget_info = info->next;
315 return info;
317 return NULL;
320 /* Internal function used by the library dependent implementation to get the
321 widget_value for a given widget in an instance */
322 widget_info *
323 lw_get_widget_info (LWLIB_ID id)
325 return get_widget_info (id, 0);
328 static widget_instance *
329 get_widget_instance (Widget widget, Boolean remove_p)
331 widget_info* info;
332 widget_instance* instance;
333 widget_instance* prev;
334 for (info = all_widget_info; info; info = info->next)
335 for (prev = NULL, instance = info->instances;
336 instance;
337 prev = instance, instance = instance->next)
338 if (instance->widget == widget)
340 if (remove_p)
342 if (prev)
343 prev->next = instance->next;
344 else
345 info->instances = instance->next;
347 return instance;
349 return (widget_instance *) 0;
352 /* Value is a pointer to the widget_instance corresponding to
353 WIDGET, or null if WIDGET is not a lwlib widget. */
355 widget_instance *
356 lw_get_widget_instance (Widget widget)
358 return get_widget_instance (widget, False);
361 static widget_instance*
362 find_instance (LWLIB_ID id, Widget parent, Boolean pop_up_p)
364 widget_info* info = get_widget_info (id, False);
365 widget_instance* instance;
367 if (info)
368 for (instance = info->instances; instance; instance = instance->next)
369 if (instance->parent == parent && instance->pop_up_p == pop_up_p)
370 return instance;
372 return NULL;
376 /* utility function for widget_value */
377 static Boolean
378 safe_strcmp (const char *s1, const char *s2)
380 if (!!s1 ^ !!s2) return True;
381 return (s1 && s2) ? strcmp (s1, s2) : s1 ? False : !!s2;
385 #if 0
386 # define EXPLAIN(name, oc, nc, desc, a1, a2) \
387 printf ("Change: \"%s\"\tmax(%s=%d,%s=%d)\t%s %d %d\n", \
388 name, \
389 (oc == NO_CHANGE ? "none" : \
390 (oc == INVISIBLE_CHANGE ? "invisible" : \
391 (oc == VISIBLE_CHANGE ? "visible" : \
392 (oc == STRUCTURAL_CHANGE ? "structural" : "???")))), \
393 oc, \
394 (nc == NO_CHANGE ? "none" : \
395 (nc == INVISIBLE_CHANGE ? "invisible" : \
396 (nc == VISIBLE_CHANGE ? "visible" : \
397 (nc == STRUCTURAL_CHANGE ? "structural" : "???")))), \
398 nc, desc, a1, a2)
399 #else
400 # define EXPLAIN(name, oc, nc, desc, a1, a2) ((void) 0)
401 #endif
404 static widget_value *
405 merge_widget_value (widget_value *val1,
406 widget_value *val2,
407 int level,
408 int *change_p)
410 change_type change, this_one_change;
411 widget_value* merged_next;
412 widget_value* merged_contents;
414 if (!val1)
416 if (val2)
418 *change_p = 1;
419 return copy_widget_value_tree (val2, STRUCTURAL_CHANGE);
421 else
422 return NULL;
424 if (!val2)
426 *change_p = 1;
427 free_widget_value_tree (val1);
428 return NULL;
431 change = NO_CHANGE;
433 if (safe_strcmp (val1->name, val2->name))
435 EXPLAIN (val1->name, change, STRUCTURAL_CHANGE, "name change",
436 val1->name, val2->name);
437 change = max (change, STRUCTURAL_CHANGE);
438 safe_free_str (val1->name);
439 val1->name = safe_strdup (val2->name);
441 if (safe_strcmp (val1->value, val2->value))
443 EXPLAIN (val1->name, change, VISIBLE_CHANGE, "value change",
444 val1->value, val2->value);
445 change = max (change, VISIBLE_CHANGE);
446 safe_free_str (val1->value);
447 val1->value = safe_strdup (val2->value);
449 if (safe_strcmp (val1->key, val2->key))
451 EXPLAIN (val1->name, change, VISIBLE_CHANGE, "key change",
452 val1->key, val2->key);
453 change = max (change, VISIBLE_CHANGE);
454 safe_free_str (val1->key);
455 val1->key = safe_strdup (val2->key);
457 if (! EQ (val1->help, val2->help))
459 EXPLAIN (val1->name, change, VISIBLE_CHANGE, "help change",
460 val1->help, val2->help);
461 change = max (change, VISIBLE_CHANGE);
462 val1->help = val2->help;
464 if (val1->enabled != val2->enabled)
466 EXPLAIN (val1->name, change, VISIBLE_CHANGE, "enablement change",
467 val1->enabled, val2->enabled);
468 change = max (change, VISIBLE_CHANGE);
469 val1->enabled = val2->enabled;
471 if (val1->button_type != val2->button_type)
473 EXPLAIN (val1->name, change, VISIBLE_CHANGE, "button type change",
474 val1->button_type, val2->button_type);
475 change = max (change, VISIBLE_CHANGE);
476 val1->button_type = val2->button_type;
478 if (val1->selected != val2->selected)
480 EXPLAIN (val1->name, change, VISIBLE_CHANGE, "selection change",
481 val1->selected, val2->selected);
482 change = max (change, VISIBLE_CHANGE);
483 val1->selected = val2->selected;
485 if (val1->call_data != val2->call_data)
487 EXPLAIN (val1->name, change, INVISIBLE_CHANGE, "call-data change",
488 val1->call_data, val2->call_data);
489 change = max (change, INVISIBLE_CHANGE);
490 val1->call_data = val2->call_data;
493 if (level > 0)
495 merged_contents =
496 merge_widget_value (val1->contents, val2->contents, level - 1,
497 change_p);
499 if (val1->contents && !merged_contents)
501 /* This used to say INVISIBLE_CHANGE,
502 but it is visible and vitally important when
503 the contents of the menu bar itself are entirely deleted.
505 But maybe it doesn't matter. This fails to fix the bug. */
506 EXPLAIN (val1->name, change, STRUCTURAL_CHANGE, "(contents gone)",
507 0, 0);
508 change = max (change, STRUCTURAL_CHANGE);
510 else if (merged_contents && merged_contents->change != NO_CHANGE)
512 EXPLAIN (val1->name, change, INVISIBLE_CHANGE, "(contents change)",
513 0, 0);
514 change = max (change, INVISIBLE_CHANGE);
515 #if 0 /* This was replaced by the August 9 1996 change in lwlib-Xm.c. */
516 #ifdef USE_MOTIF
517 change = max (merged_contents->change, change);
518 #endif
519 #endif
522 val1->contents = merged_contents;
525 this_one_change = change;
527 merged_next = merge_widget_value (val1->next, val2->next, level, change_p);
529 if (val1->next && !merged_next)
531 EXPLAIN (val1->name, change, STRUCTURAL_CHANGE, "(following gone)",
532 0, 0);
533 change = max (change, STRUCTURAL_CHANGE);
535 else if (merged_next)
537 if (merged_next->change)
538 EXPLAIN (val1->name, change, merged_next->change, "(following change)",
539 0, 0);
540 change = max (change, merged_next->change);
543 val1->next = merged_next;
545 val1->this_one_change = this_one_change;
546 val1->change = change;
548 if (change > NO_CHANGE && val1->toolkit_data)
550 *change_p = 1;
551 if (val1->free_toolkit_data)
552 XtFree (val1->toolkit_data);
553 val1->toolkit_data = NULL;
556 return val1;
560 /* modifying the widgets */
561 static Widget
562 name_to_widget (widget_instance *instance, const char *name)
564 Widget widget = NULL;
566 if (!instance->widget)
567 return NULL;
569 if (!strcmp (XtName (instance->widget), name))
570 widget = instance->widget;
571 else
573 int length = strlen (name) + 2;
574 char* real_name = (char *) xmalloc (length);
575 real_name [0] = '*';
576 strcpy (real_name + 1, name);
578 widget = XtNameToWidget (instance->widget, real_name);
580 xfree (real_name);
582 return widget;
585 static void
586 set_one_value (widget_instance* instance, widget_value* val, Boolean deep_p)
588 Widget widget = name_to_widget (instance, val->name);
590 if (widget)
592 #if defined (USE_LUCID)
593 if (lw_lucid_widget_p (instance->widget))
594 xlw_update_one_widget (instance, widget, val, deep_p);
595 #endif
596 #if defined (USE_MOTIF)
597 if (lw_motif_widget_p (instance->widget))
598 xm_update_one_widget (instance, widget, val, deep_p);
599 #endif
600 #if defined (USE_XAW)
601 if (lw_xaw_widget_p (instance->widget))
602 xaw_update_one_widget (instance, widget, val, deep_p);
603 #endif
607 static void
608 update_one_widget_instance (widget_instance* instance, Boolean deep_p)
610 widget_value *val;
612 if (!instance->widget)
613 /* the widget was destroyed */
614 return;
616 for (val = instance->info->val; val; val = val->next)
617 if (val->change != NO_CHANGE)
618 set_one_value (instance, val, deep_p);
621 static void
622 update_all_widget_values (widget_info* info, Boolean deep_p)
624 widget_instance* instance;
625 widget_value* val;
627 for (instance = info->instances; instance; instance = instance->next)
628 update_one_widget_instance (instance, deep_p);
630 for (val = info->val; val; val = val->next)
631 val->change = NO_CHANGE;
635 lw_modify_all_widgets (LWLIB_ID id, widget_value* val, Boolean deep_p)
637 widget_info* info = get_widget_info (id, False);
638 widget_value* new_val;
639 widget_value* next_new_val;
640 widget_value* cur;
641 widget_value* prev;
642 widget_value* next;
643 int found;
644 int change_p = 0;
646 if (!info)
647 return 0;
649 for (new_val = val; new_val; new_val = new_val->next)
651 next_new_val = new_val->next;
652 new_val->next = NULL;
653 found = False;
654 for (prev = NULL, cur = info->val; cur; prev = cur, cur = cur->next)
655 if (!strcmp (cur->name, new_val->name))
657 found = True;
658 next = cur->next;
659 cur->next = NULL;
660 cur = merge_widget_value (cur, new_val, deep_p ? 1000 : 1,
661 &change_p);
662 if (prev)
663 prev->next = cur ? cur : next;
664 else
665 info->val = cur ? cur : next;
666 if (cur)
667 cur->next = next;
668 break;
670 if (!found)
672 /* Could not find it, add it */
673 if (prev)
674 prev->next = copy_widget_value_tree (new_val, STRUCTURAL_CHANGE);
675 else
676 info->val = copy_widget_value_tree (new_val, STRUCTURAL_CHANGE);
677 change_p = 1;
679 new_val->next = next_new_val;
682 update_all_widget_values (info, deep_p);
683 return change_p;
687 /* creating the widgets */
689 static void
690 initialize_widget_instance (widget_instance *instance)
692 widget_value* val;
694 for (val = instance->info->val; val; val = val->next)
695 val->change = STRUCTURAL_CHANGE;
697 update_one_widget_instance (instance, True);
699 for (val = instance->info->val; val; val = val->next)
700 val->change = NO_CHANGE;
704 static widget_creation_function
705 find_in_table (const char *type, const widget_creation_entry *table)
707 const widget_creation_entry* cur;
708 for (cur = table; cur->type; cur++)
709 if (!c_strcasecmp (type, cur->type))
710 return cur->function;
711 return NULL;
714 static Boolean
715 dialog_spec_p (const char *name)
717 /* return True if name matches [EILPQeilpq][1-9][Bb] or
718 [EILPQeilpq][1-9][Bb][Rr][1-9] */
719 if (!name)
720 return False;
722 switch (name [0])
724 case 'E': case 'I': case 'L': case 'P': case 'Q':
725 case 'e': case 'i': case 'l': case 'p': case 'q':
726 if (name [1] >= '0' && name [1] <= '9')
728 if (name [2] != 'B' && name [2] != 'b')
729 return False;
730 if (!name [3])
731 return True;
732 if ((name [3] == 'T' || name [3] == 't') && !name [4])
733 return True;
734 if ((name [3] == 'R' || name [3] == 'r')
735 && name [4] >= '0' && name [4] <= '9' && !name [5])
736 return True;
737 return False;
739 else
740 return False;
742 default:
743 return False;
747 static void
748 instantiate_widget_instance (widget_instance *instance)
750 widget_creation_function function = NULL;
752 #if defined (USE_LUCID)
753 if (!function)
754 function = find_in_table (instance->info->type, xlw_creation_table);
755 #endif
756 #if defined(USE_MOTIF)
757 if (!function)
758 function = find_in_table (instance->info->type, xm_creation_table);
759 #endif
760 #if defined (USE_XAW)
761 if (!function)
762 function = find_in_table (instance->info->type, xaw_creation_table);
763 #endif
765 if (!function)
767 if (dialog_spec_p (instance->info->type))
769 #if defined (USE_LUCID)
770 /* not yet */
771 #endif
772 #if defined(USE_MOTIF)
773 if (!function)
774 function = xm_create_dialog;
775 #endif
776 #if defined (USE_XAW)
777 if (!function)
778 function = xaw_create_dialog;
779 #endif
783 if (!function)
785 printf ("No creation function for widget type %s\n",
786 instance->info->type);
787 abort ();
790 instance->widget = (*function) (instance);
792 if (!instance->widget)
793 abort ();
795 /* XtRealizeWidget (instance->widget);*/
798 void
799 lw_register_widget (const char* type,
800 const char* name,
801 LWLIB_ID id,
802 widget_value* val,
803 lw_callback pre_activate_cb,
804 lw_callback selection_cb,
805 lw_callback post_activate_cb,
806 lw_callback highlight_cb)
808 if (!get_widget_info (id, False))
809 allocate_widget_info (type, name, id, val, pre_activate_cb, selection_cb,
810 post_activate_cb, highlight_cb);
813 Widget
814 lw_get_widget (LWLIB_ID id, Widget parent, Boolean pop_up_p)
816 widget_instance* instance;
818 instance = find_instance (id, parent, pop_up_p);
819 return instance ? instance->widget : NULL;
822 Widget
823 lw_make_widget (LWLIB_ID id, Widget parent, Boolean pop_up_p)
825 widget_instance* instance;
826 widget_info* info;
828 instance = find_instance (id, parent, pop_up_p);
829 if (!instance)
831 info = get_widget_info (id, False);
832 if (!info)
833 return NULL;
834 instance = allocate_widget_instance (info, parent, pop_up_p);
835 initialize_widget_instance (instance);
837 if (!instance->widget)
838 abort ();
839 return instance->widget;
842 Widget
843 lw_create_widget (const char* type, const char* name, LWLIB_ID id, widget_value* val,
844 Widget parent, Boolean pop_up_p,
845 lw_callback pre_activate_cb, lw_callback selection_cb,
846 lw_callback post_activate_cb, lw_callback highlight_cb)
848 lw_register_widget (type, name, id, val, pre_activate_cb, selection_cb,
849 post_activate_cb, highlight_cb);
850 return lw_make_widget (id, parent, pop_up_p);
854 /* destroying the widgets */
855 static void
856 destroy_one_instance (widget_instance *instance)
858 /* Remove the destroy callback on the widget; that callback will try to
859 dereference the instance object (to set its widget slot to 0, since the
860 widget is dead.) Since the instance is now dead, we don't have to worry
861 about the fact that its widget is dead too.
863 This happens in the Phase2Destroy of the widget, so this callback would
864 not have been run until arbitrarily long after the instance was freed.
866 if (instance->widget)
867 XtRemoveCallback (instance->widget, XtNdestroyCallback,
868 mark_widget_destroyed, (XtPointer)instance);
870 if (instance->widget)
872 /* The else are pretty tricky here, including the empty statement
873 at the end because it would be very bad to destroy a widget
874 twice. */
875 #if defined (USE_LUCID)
876 if (lw_lucid_widget_p (instance->widget))
877 xlw_destroy_instance (instance);
878 else
879 #endif
880 #if defined (USE_MOTIF)
881 if (lw_motif_widget_p (instance->widget))
882 xm_destroy_instance (instance);
883 else
884 #endif
885 #if defined (USE_XAW)
886 if (lw_xaw_widget_p (instance->widget))
887 xaw_destroy_instance (instance);
888 else
889 #endif
891 /* Empty compound statement to terminate if-then-else chain. */
895 free_widget_instance (instance);
898 void
899 lw_destroy_widget (Widget w)
901 widget_instance* instance = get_widget_instance (w, True);
903 if (instance)
905 widget_info *info = instance->info;
906 /* instance has already been removed from the list; free it */
907 destroy_one_instance (instance);
908 /* if there are no instances left, free the info too */
909 if (!info->instances)
910 lw_destroy_all_widgets (info->id);
914 void
915 lw_destroy_all_widgets (LWLIB_ID id)
917 widget_info* info = get_widget_info (id, True);
918 widget_instance* instance;
919 widget_instance* next;
921 if (info)
923 for (instance = info->instances; instance; )
925 next = instance->next;
926 destroy_one_instance (instance);
927 instance = next;
929 free_widget_info (info);
933 void
934 lw_destroy_everything (void)
936 while (all_widget_info)
937 lw_destroy_all_widgets (all_widget_info->id);
940 void
941 lw_destroy_all_pop_ups (void)
943 widget_info* info;
944 widget_info* next;
945 widget_instance* instance;
947 for (info = all_widget_info; info; info = next)
949 next = info->next;
950 instance = info->instances;
951 if (instance && instance->pop_up_p)
952 lw_destroy_all_widgets (info->id);
956 #ifdef USE_MOTIF
957 extern Widget first_child (Widget); /* garbage */
958 #endif
960 Widget
961 lw_raise_all_pop_up_widgets (void)
963 widget_info* info;
964 widget_instance* instance;
965 Widget result = NULL;
967 for (info = all_widget_info; info; info = info->next)
968 for (instance = info->instances; instance; instance = instance->next)
969 if (instance->pop_up_p)
971 Widget widget = instance->widget;
972 if (widget)
974 if (XtIsManaged (widget)
975 #ifdef USE_MOTIF
976 /* What a complete load of crap!!!!
977 When a dialogShell is on the screen, it is not managed!
979 || (lw_motif_widget_p (instance->widget) &&
980 XtIsManaged (first_child (widget)))
981 #endif
984 if (!result)
985 result = widget;
986 XMapRaised (XtDisplay (widget), XtWindow (widget));
990 return result;
993 static void
994 lw_pop_all_widgets (LWLIB_ID id, Boolean up)
996 widget_info* info = get_widget_info (id, False);
997 widget_instance* instance;
999 if (info)
1000 for (instance = info->instances; instance; instance = instance->next)
1001 if (instance->pop_up_p && instance->widget)
1003 #if defined (USE_LUCID)
1004 if (lw_lucid_widget_p (instance->widget))
1006 XtRealizeWidget (instance->widget);
1007 xlw_pop_instance (instance, up);
1009 #endif
1010 #if defined (USE_MOTIF)
1011 if (lw_motif_widget_p (instance->widget))
1013 XtRealizeWidget (instance->widget);
1014 xm_pop_instance (instance, up);
1016 #endif
1017 #if defined (USE_XAW)
1018 if (lw_xaw_widget_p (instance->widget))
1020 XtRealizeWidget (XtParent (instance->widget));
1021 XtRealizeWidget (instance->widget);
1022 xaw_pop_instance (instance, up);
1024 #endif
1028 void
1029 lw_pop_up_all_widgets (LWLIB_ID id)
1031 lw_pop_all_widgets (id, True);
1034 void
1035 lw_pop_down_all_widgets (LWLIB_ID id)
1037 lw_pop_all_widgets (id, False);
1040 void
1041 lw_popup_menu (Widget widget, XEvent *event)
1043 #if defined (USE_LUCID)
1044 if (lw_lucid_widget_p (widget))
1045 xlw_popup_menu (widget, event);
1046 #endif
1047 #if defined (USE_MOTIF)
1048 if (lw_motif_widget_p (widget))
1049 xm_popup_menu (widget, event);
1050 #endif
1051 #if defined (USE_XAW)
1052 if (lw_xaw_widget_p (widget))
1053 xaw_popup_menu (widget, event);
1054 #endif
1057 \f/* get the values back */
1058 static Boolean
1059 get_one_value (widget_instance *instance, widget_value *val)
1061 Widget widget = name_to_widget (instance, val->name);
1063 if (widget)
1065 #if defined (USE_LUCID)
1066 if (lw_lucid_widget_p (instance->widget))
1067 xlw_update_one_value (instance, widget, val);
1068 #endif
1069 #if defined (USE_MOTIF)
1070 if (lw_motif_widget_p (instance->widget))
1071 xm_update_one_value (instance, widget, val);
1072 #endif
1073 #if defined (USE_XAW)
1074 if (lw_xaw_widget_p (instance->widget))
1075 xaw_update_one_value (instance, widget, val);
1076 #endif
1077 return True;
1079 else
1080 return False;
1083 Boolean
1084 lw_get_some_values (LWLIB_ID id, widget_value *val_out)
1086 widget_info* info = get_widget_info (id, False);
1087 widget_instance* instance;
1088 widget_value* val;
1089 Boolean result = False;
1091 if (!info)
1092 return False;
1094 instance = info->instances;
1095 if (!instance)
1096 return False;
1098 for (val = val_out; val; val = val->next)
1099 if (get_one_value (instance, val))
1100 result = True;
1102 return result;
1105 widget_value*
1106 lw_get_all_values (LWLIB_ID id)
1108 widget_info* info = get_widget_info (id, False);
1109 widget_value* val = info->val;
1110 if (lw_get_some_values (id, val))
1111 return val;
1112 else
1113 return NULL;
1116 /* internal function used by the library dependent implementation to get the
1117 widget_value for a given widget in an instance */
1118 widget_value*
1119 lw_get_widget_value_for_widget (widget_instance *instance, Widget w)
1121 char* name = XtName (w);
1122 widget_value* cur;
1123 for (cur = instance->info->val; cur; cur = cur->next)
1124 if (!strcmp (cur->name, name))
1125 return cur;
1126 return NULL;
1129 \f/* update other instances value when one thing changed */
1131 /* To forbid recursive calls */
1132 static Boolean lwlib_updating;
1134 /* This function can be used as an XtCallback for the widgets that get
1135 modified to update other instances of the widgets. Closure should be the
1136 widget_instance. */
1137 void
1138 lw_internal_update_other_instances (Widget widget,
1139 XtPointer closure,
1140 XtPointer call_data)
1142 widget_instance* instance = (widget_instance*)closure;
1143 char* name = XtName (widget);
1144 widget_info* info;
1145 widget_instance* cur;
1146 widget_value* val;
1148 /* Avoid possibly infinite recursion. */
1149 if (lwlib_updating)
1150 return;
1152 /* protect against the widget being destroyed */
1153 if (XtWidgetBeingDestroyedP (widget))
1154 return;
1156 /* Return immediately if there are no other instances */
1157 info = instance->info;
1158 if (!info->instances->next)
1159 return;
1161 lwlib_updating = True;
1163 for (val = info->val; val && strcmp (val->name, name); val = val->next);
1165 if (val && get_one_value (instance, val))
1166 for (cur = info->instances; cur; cur = cur->next)
1167 if (cur != instance)
1168 set_one_value (cur, val, True);
1170 lwlib_updating = False;
1174 \f/* get the id */
1176 LWLIB_ID
1177 lw_get_widget_id (Widget w)
1179 widget_instance* instance = get_widget_instance (w, False);
1181 return instance ? instance->info->id : 0;
1184 \f/* set the keyboard focus */
1185 void
1186 lw_set_keyboard_focus (Widget parent, Widget w)
1188 #if defined (USE_MOTIF)
1189 xm_set_keyboard_focus (parent, w);
1190 #else
1191 XtSetKeyboardFocus (parent, w);
1192 #endif
1195 \f/* Show busy */
1196 static void
1197 show_one_widget_busy (Widget w, Boolean flag)
1199 Pixel foreground = 0;
1200 Pixel background = 1;
1201 Widget widget_to_invert = XtNameToWidget (w, "*sheet");
1202 if (!widget_to_invert)
1203 widget_to_invert = w;
1205 XtVaGetValues (widget_to_invert,
1206 XtNforeground, &foreground,
1207 XtNbackground, &background,
1208 NULL);
1209 XtVaSetValues (widget_to_invert,
1210 XtNforeground, background,
1211 XtNbackground, foreground,
1212 NULL);
1215 void
1216 lw_show_busy (Widget w, Boolean busy)
1218 widget_instance* instance = get_widget_instance (w, False);
1219 widget_info* info;
1220 widget_instance* next;
1222 if (instance)
1224 info = instance->info;
1225 if (info->busy != busy)
1227 for (next = info->instances; next; next = next->next)
1228 if (next->widget)
1229 show_one_widget_busy (next->widget, busy);
1230 info->busy = busy;
1235 /* This hack exists because Lucid/Athena need to execute the strange
1236 function below to support geometry management. */
1237 void
1238 lw_refigure_widget (Widget w, Boolean doit)
1240 #if defined (USE_XAW)
1241 XawPanedSetRefigureMode (w, doit);
1242 #endif
1243 #if defined (USE_MOTIF)
1244 if (doit)
1245 XtManageChild (w);
1246 else
1247 XtUnmanageChild (w);
1248 #endif
1251 /* Toolkit independent way of determining if an event window is in the
1252 menubar. */
1253 Boolean
1254 lw_window_is_in_menubar (Window win, Widget menubar_widget)
1256 return menubar_widget
1257 #if defined (USE_LUCID)
1258 && XtWindow (menubar_widget) == win;
1259 #endif
1260 #if defined (USE_MOTIF)
1261 && ((XtWindow (menubar_widget) == win)
1262 || (XtWindowToWidget (XtDisplay (menubar_widget), win)
1263 && (XtParent (XtWindowToWidget (XtDisplay (menubar_widget), win))
1264 == menubar_widget)));
1265 #endif
1268 /* Motif hack to set the main window areas. */
1269 void
1270 lw_set_main_areas (Widget parent, Widget menubar, Widget work_area)
1272 #if defined (USE_MOTIF)
1273 xm_set_main_areas (parent, menubar, work_area);
1274 #endif
1277 /* Manage resizing for Motif. This disables resizing when the menubar
1278 is about to be modified. */
1279 void
1280 lw_allow_resizing (Widget w, Boolean flag)
1282 #if defined (USE_MOTIF)
1283 xm_manage_resizing (w, flag);
1284 #endif
1288 /* Value is non-zero if LABEL is a menu separator. If it is, *TYPE is
1289 set to an appropriate enumerator of type enum menu_separator.
1290 MOTIF_P non-zero means map separator types not supported by Motif
1291 to similar ones that are supported. */
1294 lw_separator_p (const char *label, enum menu_separator *type, int motif_p)
1296 int separator_p = 0;
1298 if (strlen (label) >= 3
1299 && memcmp (label, "--:", 3) == 0)
1301 static struct separator_table
1303 const char *name;
1304 enum menu_separator type;
1306 separator_names[] =
1308 {"space", SEPARATOR_NO_LINE},
1309 {"noLine", SEPARATOR_NO_LINE},
1310 {"singleLine", SEPARATOR_SINGLE_LINE},
1311 {"doubleLine", SEPARATOR_DOUBLE_LINE},
1312 {"singleDashedLine", SEPARATOR_SINGLE_DASHED_LINE},
1313 {"doubleDashedLine", SEPARATOR_DOUBLE_DASHED_LINE},
1314 {"shadowEtchedIn", SEPARATOR_SHADOW_ETCHED_IN},
1315 {"shadowEtchedOut", SEPARATOR_SHADOW_ETCHED_OUT},
1316 {"shadowEtchedInDash", SEPARATOR_SHADOW_ETCHED_IN_DASH},
1317 {"shadowEtchedOutDash", SEPARATOR_SHADOW_ETCHED_OUT_DASH},
1318 {"shadowDoubleEtchedIn", SEPARATOR_SHADOW_DOUBLE_ETCHED_IN},
1319 {"shadowDoubleEtchedOut", SEPARATOR_SHADOW_DOUBLE_ETCHED_OUT},
1320 {"shadowDoubleEtchedInDash", SEPARATOR_SHADOW_DOUBLE_ETCHED_IN_DASH},
1321 {"shadowDoubleEtchedOutDash", SEPARATOR_SHADOW_DOUBLE_ETCHED_OUT_DASH},
1322 {0,0}
1325 int i;
1327 label += 3;
1328 for (i = 0; separator_names[i].name; ++i)
1329 if (strcmp (label, separator_names[i].name) == 0)
1331 separator_p = 1;
1332 *type = separator_names[i].type;
1334 /* If separator type is not supported under Motif,
1335 use a similar one. */
1336 if (motif_p && *type >= SEPARATOR_SHADOW_DOUBLE_ETCHED_IN)
1337 *type -= 4;
1338 break;
1341 else if (strlen (label) > 3
1342 && memcmp (label, "--", 2) == 0
1343 && label[2] != '-')
1345 /* Alternative, more Emacs-style names. */
1346 static struct separator_table
1348 const char *name;
1349 enum menu_separator type;
1351 separator_names[] =
1353 {"space", SEPARATOR_NO_LINE},
1354 {"no-line", SEPARATOR_NO_LINE},
1355 {"single-line", SEPARATOR_SINGLE_LINE},
1356 {"double-line", SEPARATOR_DOUBLE_LINE},
1357 {"single-dashed-line", SEPARATOR_SINGLE_DASHED_LINE},
1358 {"double-dashed-line", SEPARATOR_DOUBLE_DASHED_LINE},
1359 {"shadow-etched-in", SEPARATOR_SHADOW_ETCHED_IN},
1360 {"shadow-etched-out", SEPARATOR_SHADOW_ETCHED_OUT},
1361 {"shadow-etched-in-dash", SEPARATOR_SHADOW_ETCHED_IN_DASH},
1362 {"shadow-etched-out-dash", SEPARATOR_SHADOW_ETCHED_OUT_DASH},
1363 {"shadow-double-etched-in", SEPARATOR_SHADOW_DOUBLE_ETCHED_IN},
1364 {"shadow-double-etched-out", SEPARATOR_SHADOW_DOUBLE_ETCHED_OUT},
1365 {"shadow-double-etched-in-dash", SEPARATOR_SHADOW_DOUBLE_ETCHED_IN_DASH},
1366 {"shadow-double-etched-out-dash",SEPARATOR_SHADOW_DOUBLE_ETCHED_OUT_DASH},
1367 {0,0}
1370 int i;
1372 label += 2;
1373 for (i = 0; separator_names[i].name; ++i)
1374 if (strcmp (label, separator_names[i].name) == 0)
1376 separator_p = 1;
1377 *type = separator_names[i].type;
1379 /* If separator type is not supported under Motif,
1380 use a similar one. */
1381 if (motif_p && *type >= SEPARATOR_SHADOW_DOUBLE_ETCHED_IN)
1382 *type -= 4;
1383 break;
1386 else
1388 /* Old-style separator, maybe. It's a separator if it contains
1389 only dashes. */
1390 while (*label == '-')
1391 ++label;
1392 separator_p = *label == 0;
1393 *type = SEPARATOR_SHADOW_ETCHED_IN;
1396 return separator_p;