Merge from emacs-24
[bpt/emacs.git] / lwlib / lwlib.c
1 /* A general interface to the widgets of different toolkits.
2
3 Copyright (C) 1992, 1993 Lucid, Inc.
4 Copyright (C) 1994-1996, 1999-2012 Free Software Foundation, Inc.
5
6 This file is part of the Lucid Widget Library.
7
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.
12
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.
17
18 You should have received a copy of the GNU General Public License
19 along with GNU Emacs; see the file COPYING. If not, write to
20 the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
21 Boston, MA 02110-1301, USA. */
22
23 #include <config.h>
24
25 #include <setjmp.h>
26 #include <lisp.h>
27 #include <c-strcase.h>
28
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>
35
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
54
55 #if !defined (USE_LUCID) && !defined (USE_MOTIF)
56 #error At least one of USE_LUCID or USE_MOTIF must be defined.
57 #endif
58
59 #ifndef max
60 #define max(x, y) ((x) > (y) ? (x) : (y))
61 #endif
62
63 /* List of all widgets managed by the library. */
64 static widget_info*
65 all_widget_info = NULL;
66
67 #ifdef USE_MOTIF
68 const char *lwlib_toolkit_type = "motif";
69 #else
70 const char *lwlib_toolkit_type = "lucid";
71 #endif
72
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 void safe_free_str (char *);
78 static void free_widget_value_tree (widget_value *);
79 static widget_value *copy_widget_value_tree (widget_value *,
80 change_type);
81 static widget_info *allocate_widget_info (const char *, const char *, LWLIB_ID,
82 widget_value *,
83 lw_callback, lw_callback,
84 lw_callback, lw_callback);
85 static void free_widget_info (widget_info *);
86 static void mark_widget_destroyed (Widget, XtPointer, XtPointer);
87 static widget_instance *allocate_widget_instance (widget_info *,
88 Widget, Boolean);
89 static void free_widget_instance (widget_instance *);
90 static widget_info *get_widget_info (LWLIB_ID, Boolean);
91 static widget_instance *get_widget_instance (Widget, Boolean);
92 static widget_instance *find_instance (LWLIB_ID, Widget, Boolean);
93 static Boolean safe_strcmp (const char *, const char *);
94 static Widget name_to_widget (widget_instance *, const char *);
95 static void set_one_value (widget_instance *, widget_value *, Boolean);
96 static void update_one_widget_instance (widget_instance *, Boolean);
97 static void update_all_widget_values (widget_info *, Boolean);
98 static void initialize_widget_instance (widget_instance *);
99 static widget_creation_function find_in_table (const char *, const widget_creation_entry *);
100 static Boolean dialog_spec_p (const char *);
101 static void destroy_one_instance (widget_instance *);
102 static void lw_pop_all_widgets (LWLIB_ID, Boolean);
103 static Boolean get_one_value (widget_instance *, widget_value *);
104 static void show_one_widget_busy (Widget, Boolean);
105 \f/* utility functions for widget_instance and widget_info */
106 char *
107 safe_strdup (const char *s)
108 {
109 char *result;
110 if (! s) return 0;
111 result = (char *) xmalloc (strlen (s) + 1);
112 strcpy (result, s);
113 return result;
114 }
115
116 static void
117 safe_free_str (char *s)
118 {
119 xfree (s);
120 }
121
122 static widget_value *widget_value_free_list = 0;
123 static int malloc_cpt = 0;
124
125 widget_value *
126 malloc_widget_value (void)
127 {
128 widget_value *wv;
129 if (widget_value_free_list)
130 {
131 wv = widget_value_free_list;
132 widget_value_free_list = wv->free_list;
133 wv->free_list = 0;
134 }
135 else
136 {
137 wv = (widget_value *) xmalloc (sizeof (widget_value));
138 malloc_cpt++;
139 }
140 memset ((void*) wv, 0, sizeof (widget_value));
141 return wv;
142 }
143
144 /* this is analogous to free(). It frees only what was allocated
145 by malloc_widget_value(), and no substructures.
146 */
147 void
148 free_widget_value (widget_value *wv)
149 {
150 if (wv->free_list)
151 abort ();
152
153 if (malloc_cpt > 25)
154 {
155 /* When the number of already allocated cells is too big,
156 We free it. */
157 xfree (wv);
158 malloc_cpt--;
159 }
160 else
161 {
162 wv->free_list = widget_value_free_list;
163 widget_value_free_list = wv;
164 }
165 }
166
167 static void
168 free_widget_value_tree (widget_value *wv)
169 {
170 if (!wv)
171 return;
172
173 xfree (wv->name);
174 xfree (wv->value);
175 xfree (wv->key);
176
177 wv->name = wv->value = wv->key = (char *) 0xDEADBEEF;
178
179 if (wv->toolkit_data && wv->free_toolkit_data)
180 {
181 XtFree (wv->toolkit_data);
182 wv->toolkit_data = (void *) 0xDEADBEEF;
183 }
184
185 if (wv->contents && (wv->contents != (widget_value*)1))
186 {
187 free_widget_value_tree (wv->contents);
188 wv->contents = (widget_value *) 0xDEADBEEF;
189 }
190 if (wv->next)
191 {
192 free_widget_value_tree (wv->next);
193 wv->next = (widget_value *) 0xDEADBEEF;
194 }
195 free_widget_value (wv);
196 }
197
198 static widget_value *
199 copy_widget_value_tree (widget_value *val, change_type change)
200 {
201 widget_value* copy;
202
203 if (!val)
204 return NULL;
205 if (val == (widget_value *) 1)
206 return val;
207
208 copy = malloc_widget_value ();
209 copy->name = safe_strdup (val->name);
210 copy->value = safe_strdup (val->value);
211 copy->key = safe_strdup (val->key);
212 copy->help = val->help;
213 copy->enabled = val->enabled;
214 copy->button_type = val->button_type;
215 copy->selected = val->selected;
216 copy->edited = False;
217 copy->change = change;
218 copy->this_one_change = change;
219 copy->contents = copy_widget_value_tree (val->contents, change);
220 copy->call_data = val->call_data;
221 copy->next = copy_widget_value_tree (val->next, change);
222 copy->toolkit_data = NULL;
223 copy->free_toolkit_data = False;
224 return copy;
225 }
226
227 static widget_info *
228 allocate_widget_info (const char* type,
229 const char* name,
230 LWLIB_ID id,
231 widget_value* val,
232 lw_callback pre_activate_cb,
233 lw_callback selection_cb,
234 lw_callback post_activate_cb,
235 lw_callback highlight_cb)
236 {
237 widget_info* info = (widget_info*) xmalloc (sizeof (widget_info));
238 info->type = safe_strdup (type);
239 info->name = safe_strdup (name);
240 info->id = id;
241 info->val = copy_widget_value_tree (val, STRUCTURAL_CHANGE);
242 info->busy = False;
243 info->pre_activate_cb = pre_activate_cb;
244 info->selection_cb = selection_cb;
245 info->post_activate_cb = post_activate_cb;
246 info->highlight_cb = highlight_cb;
247 info->instances = NULL;
248
249 info->next = all_widget_info;
250 all_widget_info = info;
251
252 return info;
253 }
254
255 static void
256 free_widget_info (widget_info *info)
257 {
258 safe_free_str (info->type);
259 safe_free_str (info->name);
260 free_widget_value_tree (info->val);
261 memset ((void*)info, 0xDEADBEEF, sizeof (widget_info));
262 xfree (info);
263 }
264
265 static void
266 mark_widget_destroyed (Widget widget, XtPointer closure, XtPointer call_data)
267 {
268 widget_instance* instance = (widget_instance*)closure;
269
270 /* be very conservative */
271 if (instance->widget == widget)
272 instance->widget = NULL;
273 }
274
275 static widget_instance *
276 allocate_widget_instance (widget_info* info, Widget parent, Boolean pop_up_p)
277 {
278 widget_instance* instance =
279 (widget_instance*) xmalloc (sizeof (widget_instance));
280 memset (instance, 0, sizeof *instance);
281 instance->parent = parent;
282 instance->pop_up_p = pop_up_p;
283 instance->info = info;
284 instance->next = info->instances;
285 info->instances = instance;
286
287 instantiate_widget_instance (instance);
288
289 XtAddCallback (instance->widget, XtNdestroyCallback,
290 mark_widget_destroyed, (XtPointer)instance);
291 return instance;
292 }
293
294 static void
295 free_widget_instance (widget_instance *instance)
296 {
297 memset ((void*)instance, 0xDEADBEEF, sizeof (widget_instance));
298 xfree (instance);
299 }
300
301 static widget_info *
302 get_widget_info (LWLIB_ID id, Boolean remove_p)
303 {
304 widget_info* info;
305 widget_info* prev;
306 for (prev = NULL, info = all_widget_info;
307 info;
308 prev = info, info = info->next)
309 if (info->id == id)
310 {
311 if (remove_p)
312 {
313 if (prev)
314 prev->next = info->next;
315 else
316 all_widget_info = info->next;
317 }
318 return info;
319 }
320 return NULL;
321 }
322
323 /* Internal function used by the library dependent implementation to get the
324 widget_value for a given widget in an instance */
325 widget_info *
326 lw_get_widget_info (LWLIB_ID id)
327 {
328 return get_widget_info (id, 0);
329 }
330
331 static widget_instance *
332 get_widget_instance (Widget widget, Boolean remove_p)
333 {
334 widget_info* info;
335 widget_instance* instance;
336 widget_instance* prev;
337 for (info = all_widget_info; info; info = info->next)
338 for (prev = NULL, instance = info->instances;
339 instance;
340 prev = instance, instance = instance->next)
341 if (instance->widget == widget)
342 {
343 if (remove_p)
344 {
345 if (prev)
346 prev->next = instance->next;
347 else
348 info->instances = instance->next;
349 }
350 return instance;
351 }
352 return (widget_instance *) 0;
353 }
354
355 /* Value is a pointer to the widget_instance corresponding to
356 WIDGET, or null if WIDGET is not a lwlib widget. */
357
358 widget_instance *
359 lw_get_widget_instance (Widget widget)
360 {
361 return get_widget_instance (widget, False);
362 }
363
364 static widget_instance*
365 find_instance (LWLIB_ID id, Widget parent, Boolean pop_up_p)
366 {
367 widget_info* info = get_widget_info (id, False);
368 widget_instance* instance;
369
370 if (info)
371 for (instance = info->instances; instance; instance = instance->next)
372 if (instance->parent == parent && instance->pop_up_p == pop_up_p)
373 return instance;
374
375 return NULL;
376 }
377
378 \f
379 /* utility function for widget_value */
380 static Boolean
381 safe_strcmp (const char *s1, const char *s2)
382 {
383 if (!!s1 ^ !!s2) return True;
384 return (s1 && s2) ? strcmp (s1, s2) : s1 ? False : !!s2;
385 }
386
387
388 #if 0
389 # define EXPLAIN(name, oc, nc, desc, a1, a2) \
390 printf ("Change: \"%s\"\tmax(%s=%d,%s=%d)\t%s %d %d\n", \
391 name, \
392 (oc == NO_CHANGE ? "none" : \
393 (oc == INVISIBLE_CHANGE ? "invisible" : \
394 (oc == VISIBLE_CHANGE ? "visible" : \
395 (oc == STRUCTURAL_CHANGE ? "structural" : "???")))), \
396 oc, \
397 (nc == NO_CHANGE ? "none" : \
398 (nc == INVISIBLE_CHANGE ? "invisible" : \
399 (nc == VISIBLE_CHANGE ? "visible" : \
400 (nc == STRUCTURAL_CHANGE ? "structural" : "???")))), \
401 nc, desc, a1, a2)
402 #else
403 # define EXPLAIN(name, oc, nc, desc, a1, a2) ((void) 0)
404 #endif
405
406
407 static widget_value *
408 merge_widget_value (widget_value *val1,
409 widget_value *val2,
410 int level,
411 int *change_p)
412 {
413 change_type change, this_one_change;
414 widget_value* merged_next;
415 widget_value* merged_contents;
416
417 if (!val1)
418 {
419 if (val2)
420 {
421 *change_p = 1;
422 return copy_widget_value_tree (val2, STRUCTURAL_CHANGE);
423 }
424 else
425 return NULL;
426 }
427 if (!val2)
428 {
429 *change_p = 1;
430 free_widget_value_tree (val1);
431 return NULL;
432 }
433
434 change = NO_CHANGE;
435
436 if (safe_strcmp (val1->name, val2->name))
437 {
438 EXPLAIN (val1->name, change, STRUCTURAL_CHANGE, "name change",
439 val1->name, val2->name);
440 change = max (change, STRUCTURAL_CHANGE);
441 safe_free_str (val1->name);
442 val1->name = safe_strdup (val2->name);
443 }
444 if (safe_strcmp (val1->value, val2->value))
445 {
446 EXPLAIN (val1->name, change, VISIBLE_CHANGE, "value change",
447 val1->value, val2->value);
448 change = max (change, VISIBLE_CHANGE);
449 safe_free_str (val1->value);
450 val1->value = safe_strdup (val2->value);
451 }
452 if (safe_strcmp (val1->key, val2->key))
453 {
454 EXPLAIN (val1->name, change, VISIBLE_CHANGE, "key change",
455 val1->key, val2->key);
456 change = max (change, VISIBLE_CHANGE);
457 safe_free_str (val1->key);
458 val1->key = safe_strdup (val2->key);
459 }
460 if (! EQ (val1->help, val2->help))
461 {
462 EXPLAIN (val1->name, change, VISIBLE_CHANGE, "help change",
463 val1->help, val2->help);
464 change = max (change, VISIBLE_CHANGE);
465 val1->help = val2->help;
466 }
467 if (val1->enabled != val2->enabled)
468 {
469 EXPLAIN (val1->name, change, VISIBLE_CHANGE, "enablement change",
470 val1->enabled, val2->enabled);
471 change = max (change, VISIBLE_CHANGE);
472 val1->enabled = val2->enabled;
473 }
474 if (val1->button_type != val2->button_type)
475 {
476 EXPLAIN (val1->name, change, VISIBLE_CHANGE, "button type change",
477 val1->button_type, val2->button_type);
478 change = max (change, VISIBLE_CHANGE);
479 val1->button_type = val2->button_type;
480 }
481 if (val1->selected != val2->selected)
482 {
483 EXPLAIN (val1->name, change, VISIBLE_CHANGE, "selection change",
484 val1->selected, val2->selected);
485 change = max (change, VISIBLE_CHANGE);
486 val1->selected = val2->selected;
487 }
488 if (val1->call_data != val2->call_data)
489 {
490 EXPLAIN (val1->name, change, INVISIBLE_CHANGE, "call-data change",
491 val1->call_data, val2->call_data);
492 change = max (change, INVISIBLE_CHANGE);
493 val1->call_data = val2->call_data;
494 }
495
496 if (level > 0)
497 {
498 merged_contents =
499 merge_widget_value (val1->contents, val2->contents, level - 1,
500 change_p);
501
502 if (val1->contents && !merged_contents)
503 {
504 /* This used to say INVISIBLE_CHANGE,
505 but it is visible and vitally important when
506 the contents of the menu bar itself are entirely deleted.
507
508 But maybe it doesn't matter. This fails to fix the bug. */
509 EXPLAIN (val1->name, change, STRUCTURAL_CHANGE, "(contents gone)",
510 0, 0);
511 change = max (change, STRUCTURAL_CHANGE);
512 }
513 else if (merged_contents && merged_contents->change != NO_CHANGE)
514 {
515 EXPLAIN (val1->name, change, INVISIBLE_CHANGE, "(contents change)",
516 0, 0);
517 change = max (change, INVISIBLE_CHANGE);
518 #if 0 /* This was replaced by the August 9 1996 change in lwlib-Xm.c. */
519 #ifdef USE_MOTIF
520 change = max (merged_contents->change, change);
521 #endif
522 #endif
523 }
524
525 val1->contents = merged_contents;
526 }
527
528 this_one_change = change;
529
530 merged_next = merge_widget_value (val1->next, val2->next, level, change_p);
531
532 if (val1->next && !merged_next)
533 {
534 EXPLAIN (val1->name, change, STRUCTURAL_CHANGE, "(following gone)",
535 0, 0);
536 change = max (change, STRUCTURAL_CHANGE);
537 }
538 else if (merged_next)
539 {
540 if (merged_next->change)
541 EXPLAIN (val1->name, change, merged_next->change, "(following change)",
542 0, 0);
543 change = max (change, merged_next->change);
544 }
545
546 val1->next = merged_next;
547
548 val1->this_one_change = this_one_change;
549 val1->change = change;
550
551 if (change > NO_CHANGE && val1->toolkit_data)
552 {
553 *change_p = 1;
554 if (val1->free_toolkit_data)
555 XtFree (val1->toolkit_data);
556 val1->toolkit_data = NULL;
557 }
558
559 return val1;
560 }
561
562 \f
563 /* modifying the widgets */
564 static Widget
565 name_to_widget (widget_instance *instance, const char *name)
566 {
567 Widget widget = NULL;
568
569 if (!instance->widget)
570 return NULL;
571
572 if (!strcmp (XtName (instance->widget), name))
573 widget = instance->widget;
574 else
575 {
576 int length = strlen (name) + 2;
577 char* real_name = (char *) xmalloc (length);
578 real_name [0] = '*';
579 strcpy (real_name + 1, name);
580
581 widget = XtNameToWidget (instance->widget, real_name);
582
583 xfree (real_name);
584 }
585 return widget;
586 }
587
588 static void
589 set_one_value (widget_instance* instance, widget_value* val, Boolean deep_p)
590 {
591 Widget widget = name_to_widget (instance, val->name);
592
593 if (widget)
594 {
595 #if defined (USE_LUCID)
596 if (lw_lucid_widget_p (instance->widget))
597 xlw_update_one_widget (instance, widget, val, deep_p);
598 #endif
599 #if defined (USE_MOTIF)
600 if (lw_motif_widget_p (instance->widget))
601 xm_update_one_widget (instance, widget, val, deep_p);
602 #endif
603 #if defined (USE_XAW)
604 if (lw_xaw_widget_p (instance->widget))
605 xaw_update_one_widget (instance, widget, val, deep_p);
606 #endif
607 }
608 }
609
610 static void
611 update_one_widget_instance (widget_instance* instance, Boolean deep_p)
612 {
613 widget_value *val;
614
615 if (!instance->widget)
616 /* the widget was destroyed */
617 return;
618
619 for (val = instance->info->val; val; val = val->next)
620 if (val->change != NO_CHANGE)
621 set_one_value (instance, val, deep_p);
622 }
623
624 static void
625 update_all_widget_values (widget_info* info, Boolean deep_p)
626 {
627 widget_instance* instance;
628 widget_value* val;
629
630 for (instance = info->instances; instance; instance = instance->next)
631 update_one_widget_instance (instance, deep_p);
632
633 for (val = info->val; val; val = val->next)
634 val->change = NO_CHANGE;
635 }
636
637 int
638 lw_modify_all_widgets (LWLIB_ID id, widget_value* val, Boolean deep_p)
639 {
640 widget_info* info = get_widget_info (id, False);
641 widget_value* new_val;
642 widget_value* next_new_val;
643 widget_value* cur;
644 widget_value* prev;
645 widget_value* next;
646 int found;
647 int change_p = 0;
648
649 if (!info)
650 return 0;
651
652 for (new_val = val; new_val; new_val = new_val->next)
653 {
654 next_new_val = new_val->next;
655 new_val->next = NULL;
656 found = False;
657 for (prev = NULL, cur = info->val; cur; prev = cur, cur = cur->next)
658 if (!strcmp (cur->name, new_val->name))
659 {
660 found = True;
661 next = cur->next;
662 cur->next = NULL;
663 cur = merge_widget_value (cur, new_val, deep_p ? 1000 : 1,
664 &change_p);
665 if (prev)
666 prev->next = cur ? cur : next;
667 else
668 info->val = cur ? cur : next;
669 if (cur)
670 cur->next = next;
671 break;
672 }
673 if (!found)
674 {
675 /* Could not find it, add it */
676 if (prev)
677 prev->next = copy_widget_value_tree (new_val, STRUCTURAL_CHANGE);
678 else
679 info->val = copy_widget_value_tree (new_val, STRUCTURAL_CHANGE);
680 change_p = 1;
681 }
682 new_val->next = next_new_val;
683 }
684
685 update_all_widget_values (info, deep_p);
686 return change_p;
687 }
688
689 \f
690 /* creating the widgets */
691
692 static void
693 initialize_widget_instance (widget_instance *instance)
694 {
695 widget_value* val;
696
697 for (val = instance->info->val; val; val = val->next)
698 val->change = STRUCTURAL_CHANGE;
699
700 update_one_widget_instance (instance, True);
701
702 for (val = instance->info->val; val; val = val->next)
703 val->change = NO_CHANGE;
704 }
705
706
707 static widget_creation_function
708 find_in_table (const char *type, const widget_creation_entry *table)
709 {
710 const widget_creation_entry* cur;
711 for (cur = table; cur->type; cur++)
712 if (!c_strcasecmp (type, cur->type))
713 return cur->function;
714 return NULL;
715 }
716
717 static Boolean
718 dialog_spec_p (const char *name)
719 {
720 /* return True if name matches [EILPQeilpq][1-9][Bb] or
721 [EILPQeilpq][1-9][Bb][Rr][1-9] */
722 if (!name)
723 return False;
724
725 switch (name [0])
726 {
727 case 'E': case 'I': case 'L': case 'P': case 'Q':
728 case 'e': case 'i': case 'l': case 'p': case 'q':
729 if (name [1] >= '0' && name [1] <= '9')
730 {
731 if (name [2] != 'B' && name [2] != 'b')
732 return False;
733 if (!name [3])
734 return True;
735 if ((name [3] == 'T' || name [3] == 't') && !name [4])
736 return True;
737 if ((name [3] == 'R' || name [3] == 'r')
738 && name [4] >= '0' && name [4] <= '9' && !name [5])
739 return True;
740 return False;
741 }
742 else
743 return False;
744
745 default:
746 return False;
747 }
748 }
749
750 static void
751 instantiate_widget_instance (widget_instance *instance)
752 {
753 widget_creation_function function = NULL;
754
755 #if defined (USE_LUCID)
756 if (!function)
757 function = find_in_table (instance->info->type, xlw_creation_table);
758 #endif
759 #if defined(USE_MOTIF)
760 if (!function)
761 function = find_in_table (instance->info->type, xm_creation_table);
762 #endif
763 #if defined (USE_XAW)
764 if (!function)
765 function = find_in_table (instance->info->type, xaw_creation_table);
766 #endif
767
768 if (!function)
769 {
770 if (dialog_spec_p (instance->info->type))
771 {
772 #if defined (USE_LUCID)
773 /* not yet */
774 #endif
775 #if defined(USE_MOTIF)
776 if (!function)
777 function = xm_create_dialog;
778 #endif
779 #if defined (USE_XAW)
780 if (!function)
781 function = xaw_create_dialog;
782 #endif
783 }
784 }
785
786 if (!function)
787 {
788 printf ("No creation function for widget type %s\n",
789 instance->info->type);
790 abort ();
791 }
792
793 instance->widget = (*function) (instance);
794
795 if (!instance->widget)
796 abort ();
797
798 /* XtRealizeWidget (instance->widget);*/
799 }
800
801 void
802 lw_register_widget (const char* type,
803 const char* name,
804 LWLIB_ID id,
805 widget_value* val,
806 lw_callback pre_activate_cb,
807 lw_callback selection_cb,
808 lw_callback post_activate_cb,
809 lw_callback highlight_cb)
810 {
811 if (!get_widget_info (id, False))
812 allocate_widget_info (type, name, id, val, pre_activate_cb, selection_cb,
813 post_activate_cb, highlight_cb);
814 }
815
816 Widget
817 lw_get_widget (LWLIB_ID id, Widget parent, Boolean pop_up_p)
818 {
819 widget_instance* instance;
820
821 instance = find_instance (id, parent, pop_up_p);
822 return instance ? instance->widget : NULL;
823 }
824
825 Widget
826 lw_make_widget (LWLIB_ID id, Widget parent, Boolean pop_up_p)
827 {
828 widget_instance* instance;
829 widget_info* info;
830
831 instance = find_instance (id, parent, pop_up_p);
832 if (!instance)
833 {
834 info = get_widget_info (id, False);
835 if (!info)
836 return NULL;
837 instance = allocate_widget_instance (info, parent, pop_up_p);
838 initialize_widget_instance (instance);
839 }
840 if (!instance->widget)
841 abort ();
842 return instance->widget;
843 }
844
845 Widget
846 lw_create_widget (const char* type, const char* name, LWLIB_ID id, widget_value* val,
847 Widget parent, Boolean pop_up_p,
848 lw_callback pre_activate_cb, lw_callback selection_cb,
849 lw_callback post_activate_cb, lw_callback highlight_cb)
850 {
851 lw_register_widget (type, name, id, val, pre_activate_cb, selection_cb,
852 post_activate_cb, highlight_cb);
853 return lw_make_widget (id, parent, pop_up_p);
854 }
855
856 \f
857 /* destroying the widgets */
858 static void
859 destroy_one_instance (widget_instance *instance)
860 {
861 /* Remove the destroy callback on the widget; that callback will try to
862 dereference the instance object (to set its widget slot to 0, since the
863 widget is dead.) Since the instance is now dead, we don't have to worry
864 about the fact that its widget is dead too.
865
866 This happens in the Phase2Destroy of the widget, so this callback would
867 not have been run until arbitrarily long after the instance was freed.
868 */
869 if (instance->widget)
870 XtRemoveCallback (instance->widget, XtNdestroyCallback,
871 mark_widget_destroyed, (XtPointer)instance);
872
873 if (instance->widget)
874 {
875 /* The else are pretty tricky here, including the empty statement
876 at the end because it would be very bad to destroy a widget
877 twice. */
878 #if defined (USE_LUCID)
879 if (lw_lucid_widget_p (instance->widget))
880 xlw_destroy_instance (instance);
881 else
882 #endif
883 #if defined (USE_MOTIF)
884 if (lw_motif_widget_p (instance->widget))
885 xm_destroy_instance (instance);
886 else
887 #endif
888 #if defined (USE_XAW)
889 if (lw_xaw_widget_p (instance->widget))
890 xaw_destroy_instance (instance);
891 else
892 #endif
893 {
894 /* Empty compound statement to terminate if-then-else chain. */
895 }
896 }
897
898 free_widget_instance (instance);
899 }
900
901 void
902 lw_destroy_widget (Widget w)
903 {
904 widget_instance* instance = get_widget_instance (w, True);
905
906 if (instance)
907 {
908 widget_info *info = instance->info;
909 /* instance has already been removed from the list; free it */
910 destroy_one_instance (instance);
911 /* if there are no instances left, free the info too */
912 if (!info->instances)
913 lw_destroy_all_widgets (info->id);
914 }
915 }
916
917 void
918 lw_destroy_all_widgets (LWLIB_ID id)
919 {
920 widget_info* info = get_widget_info (id, True);
921 widget_instance* instance;
922 widget_instance* next;
923
924 if (info)
925 {
926 for (instance = info->instances; instance; )
927 {
928 next = instance->next;
929 destroy_one_instance (instance);
930 instance = next;
931 }
932 free_widget_info (info);
933 }
934 }
935
936 void
937 lw_destroy_everything (void)
938 {
939 while (all_widget_info)
940 lw_destroy_all_widgets (all_widget_info->id);
941 }
942
943 void
944 lw_destroy_all_pop_ups (void)
945 {
946 widget_info* info;
947 widget_info* next;
948 widget_instance* instance;
949
950 for (info = all_widget_info; info; info = next)
951 {
952 next = info->next;
953 instance = info->instances;
954 if (instance && instance->pop_up_p)
955 lw_destroy_all_widgets (info->id);
956 }
957 }
958
959 #ifdef USE_MOTIF
960 extern Widget first_child (Widget); /* garbage */
961 #endif
962
963 Widget
964 lw_raise_all_pop_up_widgets (void)
965 {
966 widget_info* info;
967 widget_instance* instance;
968 Widget result = NULL;
969
970 for (info = all_widget_info; info; info = info->next)
971 for (instance = info->instances; instance; instance = instance->next)
972 if (instance->pop_up_p)
973 {
974 Widget widget = instance->widget;
975 if (widget)
976 {
977 if (XtIsManaged (widget)
978 #ifdef USE_MOTIF
979 /* What a complete load of crap!!!!
980 When a dialogShell is on the screen, it is not managed!
981 */
982 || (lw_motif_widget_p (instance->widget) &&
983 XtIsManaged (first_child (widget)))
984 #endif
985 )
986 {
987 if (!result)
988 result = widget;
989 XMapRaised (XtDisplay (widget), XtWindow (widget));
990 }
991 }
992 }
993 return result;
994 }
995
996 static void
997 lw_pop_all_widgets (LWLIB_ID id, Boolean up)
998 {
999 widget_info* info = get_widget_info (id, False);
1000 widget_instance* instance;
1001
1002 if (info)
1003 for (instance = info->instances; instance; instance = instance->next)
1004 if (instance->pop_up_p && instance->widget)
1005 {
1006 #if defined (USE_LUCID)
1007 if (lw_lucid_widget_p (instance->widget))
1008 {
1009 XtRealizeWidget (instance->widget);
1010 xlw_pop_instance (instance, up);
1011 }
1012 #endif
1013 #if defined (USE_MOTIF)
1014 if (lw_motif_widget_p (instance->widget))
1015 {
1016 XtRealizeWidget (instance->widget);
1017 xm_pop_instance (instance, up);
1018 }
1019 #endif
1020 #if defined (USE_XAW)
1021 if (lw_xaw_widget_p (instance->widget))
1022 {
1023 XtRealizeWidget (XtParent (instance->widget));
1024 XtRealizeWidget (instance->widget);
1025 xaw_pop_instance (instance, up);
1026 }
1027 #endif
1028 }
1029 }
1030
1031 void
1032 lw_pop_up_all_widgets (LWLIB_ID id)
1033 {
1034 lw_pop_all_widgets (id, True);
1035 }
1036
1037 void
1038 lw_pop_down_all_widgets (LWLIB_ID id)
1039 {
1040 lw_pop_all_widgets (id, False);
1041 }
1042
1043 void
1044 lw_popup_menu (Widget widget, XEvent *event)
1045 {
1046 #if defined (USE_LUCID)
1047 if (lw_lucid_widget_p (widget))
1048 xlw_popup_menu (widget, event);
1049 #endif
1050 #if defined (USE_MOTIF)
1051 if (lw_motif_widget_p (widget))
1052 xm_popup_menu (widget, event);
1053 #endif
1054 #if defined (USE_XAW)
1055 if (lw_xaw_widget_p (widget))
1056 xaw_popup_menu (widget, event);
1057 #endif
1058 }
1059
1060 \f/* get the values back */
1061 static Boolean
1062 get_one_value (widget_instance *instance, widget_value *val)
1063 {
1064 Widget widget = name_to_widget (instance, val->name);
1065
1066 if (widget)
1067 {
1068 #if defined (USE_LUCID)
1069 if (lw_lucid_widget_p (instance->widget))
1070 xlw_update_one_value (instance, widget, val);
1071 #endif
1072 #if defined (USE_MOTIF)
1073 if (lw_motif_widget_p (instance->widget))
1074 xm_update_one_value (instance, widget, val);
1075 #endif
1076 #if defined (USE_XAW)
1077 if (lw_xaw_widget_p (instance->widget))
1078 xaw_update_one_value (instance, widget, val);
1079 #endif
1080 return True;
1081 }
1082 else
1083 return False;
1084 }
1085
1086 Boolean
1087 lw_get_some_values (LWLIB_ID id, widget_value *val_out)
1088 {
1089 widget_info* info = get_widget_info (id, False);
1090 widget_instance* instance;
1091 widget_value* val;
1092 Boolean result = False;
1093
1094 if (!info)
1095 return False;
1096
1097 instance = info->instances;
1098 if (!instance)
1099 return False;
1100
1101 for (val = val_out; val; val = val->next)
1102 if (get_one_value (instance, val))
1103 result = True;
1104
1105 return result;
1106 }
1107
1108 widget_value*
1109 lw_get_all_values (LWLIB_ID id)
1110 {
1111 widget_info* info = get_widget_info (id, False);
1112 widget_value* val = info->val;
1113 if (lw_get_some_values (id, val))
1114 return val;
1115 else
1116 return NULL;
1117 }
1118
1119 /* internal function used by the library dependent implementation to get the
1120 widget_value for a given widget in an instance */
1121 widget_value*
1122 lw_get_widget_value_for_widget (widget_instance *instance, Widget w)
1123 {
1124 char* name = XtName (w);
1125 widget_value* cur;
1126 for (cur = instance->info->val; cur; cur = cur->next)
1127 if (!strcmp (cur->name, name))
1128 return cur;
1129 return NULL;
1130 }
1131
1132 \f/* update other instances value when one thing changed */
1133
1134 /* To forbid recursive calls */
1135 static Boolean lwlib_updating;
1136
1137 /* This function can be used as an XtCallback for the widgets that get
1138 modified to update other instances of the widgets. Closure should be the
1139 widget_instance. */
1140 void
1141 lw_internal_update_other_instances (Widget widget,
1142 XtPointer closure,
1143 XtPointer call_data)
1144 {
1145 widget_instance* instance = (widget_instance*)closure;
1146 char* name = XtName (widget);
1147 widget_info* info;
1148 widget_instance* cur;
1149 widget_value* val;
1150
1151 /* Avoid possibly infinite recursion. */
1152 if (lwlib_updating)
1153 return;
1154
1155 /* protect against the widget being destroyed */
1156 if (XtWidgetBeingDestroyedP (widget))
1157 return;
1158
1159 /* Return immediately if there are no other instances */
1160 info = instance->info;
1161 if (!info->instances->next)
1162 return;
1163
1164 lwlib_updating = True;
1165
1166 for (val = info->val; val && strcmp (val->name, name); val = val->next);
1167
1168 if (val && get_one_value (instance, val))
1169 for (cur = info->instances; cur; cur = cur->next)
1170 if (cur != instance)
1171 set_one_value (cur, val, True);
1172
1173 lwlib_updating = False;
1174 }
1175
1176
1177 \f/* get the id */
1178
1179 LWLIB_ID
1180 lw_get_widget_id (Widget w)
1181 {
1182 widget_instance* instance = get_widget_instance (w, False);
1183
1184 return instance ? instance->info->id : 0;
1185 }
1186
1187 \f/* set the keyboard focus */
1188 void
1189 lw_set_keyboard_focus (Widget parent, Widget w)
1190 {
1191 #if defined (USE_MOTIF)
1192 xm_set_keyboard_focus (parent, w);
1193 #else
1194 XtSetKeyboardFocus (parent, w);
1195 #endif
1196 }
1197
1198 \f/* Show busy */
1199 static void
1200 show_one_widget_busy (Widget w, Boolean flag)
1201 {
1202 Pixel foreground = 0;
1203 Pixel background = 1;
1204 Widget widget_to_invert = XtNameToWidget (w, "*sheet");
1205 if (!widget_to_invert)
1206 widget_to_invert = w;
1207
1208 XtVaGetValues (widget_to_invert,
1209 XtNforeground, &foreground,
1210 XtNbackground, &background,
1211 NULL);
1212 XtVaSetValues (widget_to_invert,
1213 XtNforeground, background,
1214 XtNbackground, foreground,
1215 NULL);
1216 }
1217
1218 void
1219 lw_show_busy (Widget w, Boolean busy)
1220 {
1221 widget_instance* instance = get_widget_instance (w, False);
1222 widget_info* info;
1223 widget_instance* next;
1224
1225 if (instance)
1226 {
1227 info = instance->info;
1228 if (info->busy != busy)
1229 {
1230 for (next = info->instances; next; next = next->next)
1231 if (next->widget)
1232 show_one_widget_busy (next->widget, busy);
1233 info->busy = busy;
1234 }
1235 }
1236 }
1237
1238 /* This hack exists because Lucid/Athena need to execute the strange
1239 function below to support geometry management. */
1240 void
1241 lw_refigure_widget (Widget w, Boolean doit)
1242 {
1243 #if defined (USE_XAW)
1244 XawPanedSetRefigureMode (w, doit);
1245 #endif
1246 #if defined (USE_MOTIF)
1247 if (doit)
1248 XtManageChild (w);
1249 else
1250 XtUnmanageChild (w);
1251 #endif
1252 }
1253
1254 /* Toolkit independent way of determining if an event window is in the
1255 menubar. */
1256 Boolean
1257 lw_window_is_in_menubar (Window win, Widget menubar_widget)
1258 {
1259 return menubar_widget
1260 #if defined (USE_LUCID)
1261 && XtWindow (menubar_widget) == win;
1262 #endif
1263 #if defined (USE_MOTIF)
1264 && ((XtWindow (menubar_widget) == win)
1265 || (XtWindowToWidget (XtDisplay (menubar_widget), win)
1266 && (XtParent (XtWindowToWidget (XtDisplay (menubar_widget), win))
1267 == menubar_widget)));
1268 #endif
1269 }
1270
1271 /* Motif hack to set the main window areas. */
1272 void
1273 lw_set_main_areas (Widget parent, Widget menubar, Widget work_area)
1274 {
1275 #if defined (USE_MOTIF)
1276 xm_set_main_areas (parent, menubar, work_area);
1277 #endif
1278 }
1279
1280 /* Manage resizing for Motif. This disables resizing when the menubar
1281 is about to be modified. */
1282 void
1283 lw_allow_resizing (Widget w, Boolean flag)
1284 {
1285 #if defined (USE_MOTIF)
1286 xm_manage_resizing (w, flag);
1287 #endif
1288 }
1289
1290
1291 /* Value is non-zero if LABEL is a menu separator. If it is, *TYPE is
1292 set to an appropriate enumerator of type enum menu_separator.
1293 MOTIF_P non-zero means map separator types not supported by Motif
1294 to similar ones that are supported. */
1295
1296 int
1297 lw_separator_p (const char *label, enum menu_separator *type, int motif_p)
1298 {
1299 int separator_p = 0;
1300
1301 if (strlen (label) >= 3
1302 && memcmp (label, "--:", 3) == 0)
1303 {
1304 static struct separator_table
1305 {
1306 const char *name;
1307 enum menu_separator type;
1308 }
1309 separator_names[] =
1310 {
1311 {"space", SEPARATOR_NO_LINE},
1312 {"noLine", SEPARATOR_NO_LINE},
1313 {"singleLine", SEPARATOR_SINGLE_LINE},
1314 {"doubleLine", SEPARATOR_DOUBLE_LINE},
1315 {"singleDashedLine", SEPARATOR_SINGLE_DASHED_LINE},
1316 {"doubleDashedLine", SEPARATOR_DOUBLE_DASHED_LINE},
1317 {"shadowEtchedIn", SEPARATOR_SHADOW_ETCHED_IN},
1318 {"shadowEtchedOut", SEPARATOR_SHADOW_ETCHED_OUT},
1319 {"shadowEtchedInDash", SEPARATOR_SHADOW_ETCHED_IN_DASH},
1320 {"shadowEtchedOutDash", SEPARATOR_SHADOW_ETCHED_OUT_DASH},
1321 {"shadowDoubleEtchedIn", SEPARATOR_SHADOW_DOUBLE_ETCHED_IN},
1322 {"shadowDoubleEtchedOut", SEPARATOR_SHADOW_DOUBLE_ETCHED_OUT},
1323 {"shadowDoubleEtchedInDash", SEPARATOR_SHADOW_DOUBLE_ETCHED_IN_DASH},
1324 {"shadowDoubleEtchedOutDash", SEPARATOR_SHADOW_DOUBLE_ETCHED_OUT_DASH},
1325 {0,0}
1326 };
1327
1328 int i;
1329
1330 label += 3;
1331 for (i = 0; separator_names[i].name; ++i)
1332 if (strcmp (label, separator_names[i].name) == 0)
1333 {
1334 separator_p = 1;
1335 *type = separator_names[i].type;
1336
1337 /* If separator type is not supported under Motif,
1338 use a similar one. */
1339 if (motif_p && *type >= SEPARATOR_SHADOW_DOUBLE_ETCHED_IN)
1340 *type -= 4;
1341 break;
1342 }
1343 }
1344 else if (strlen (label) > 3
1345 && memcmp (label, "--", 2) == 0
1346 && label[2] != '-')
1347 {
1348 /* Alternative, more Emacs-style names. */
1349 static struct separator_table
1350 {
1351 const char *name;
1352 enum menu_separator type;
1353 }
1354 separator_names[] =
1355 {
1356 {"space", SEPARATOR_NO_LINE},
1357 {"no-line", SEPARATOR_NO_LINE},
1358 {"single-line", SEPARATOR_SINGLE_LINE},
1359 {"double-line", SEPARATOR_DOUBLE_LINE},
1360 {"single-dashed-line", SEPARATOR_SINGLE_DASHED_LINE},
1361 {"double-dashed-line", SEPARATOR_DOUBLE_DASHED_LINE},
1362 {"shadow-etched-in", SEPARATOR_SHADOW_ETCHED_IN},
1363 {"shadow-etched-out", SEPARATOR_SHADOW_ETCHED_OUT},
1364 {"shadow-etched-in-dash", SEPARATOR_SHADOW_ETCHED_IN_DASH},
1365 {"shadow-etched-out-dash", SEPARATOR_SHADOW_ETCHED_OUT_DASH},
1366 {"shadow-double-etched-in", SEPARATOR_SHADOW_DOUBLE_ETCHED_IN},
1367 {"shadow-double-etched-out", SEPARATOR_SHADOW_DOUBLE_ETCHED_OUT},
1368 {"shadow-double-etched-in-dash", SEPARATOR_SHADOW_DOUBLE_ETCHED_IN_DASH},
1369 {"shadow-double-etched-out-dash",SEPARATOR_SHADOW_DOUBLE_ETCHED_OUT_DASH},
1370 {0,0}
1371 };
1372
1373 int i;
1374
1375 label += 2;
1376 for (i = 0; separator_names[i].name; ++i)
1377 if (strcmp (label, separator_names[i].name) == 0)
1378 {
1379 separator_p = 1;
1380 *type = separator_names[i].type;
1381
1382 /* If separator type is not supported under Motif,
1383 use a similar one. */
1384 if (motif_p && *type >= SEPARATOR_SHADOW_DOUBLE_ETCHED_IN)
1385 *type -= 4;
1386 break;
1387 }
1388 }
1389 else
1390 {
1391 /* Old-style separator, maybe. It's a separator if it contains
1392 only dashes. */
1393 while (*label == '-')
1394 ++label;
1395 separator_p = *label == 0;
1396 *type = SEPARATOR_SHADOW_ETCHED_IN;
1397 }
1398
1399 return separator_p;
1400 }