Remove alternative K&R declarations.
[bpt/emacs.git] / lwlib / lwlib.c
1 /* A general interface to the widgets of different toolkits.
2 Copyright (C) 1992, 1993 Lucid, Inc.
3 Copyright (C) 1994, 1995, 1996, 1999, 2000, 2001, 2002, 2003, 2004,
4 2005, 2006, 2007, 2008, 2009, 2010 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 #ifdef HAVE_CONFIG_H
24 #include <config.h>
25 #endif
26
27 #include <setjmp.h>
28 #include "../src/lisp.h"
29
30 #include <sys/types.h>
31 #include <stdio.h>
32 #include <ctype.h>
33 #include "lwlib-int.h"
34 #include "lwlib-utils.h"
35 #include <X11/StringDefs.h>
36
37 #if defined (USE_LUCID)
38 #include "lwlib-Xlw.h"
39 #endif
40 #if defined (USE_MOTIF)
41 #include "lwlib-Xm.h"
42 #else /* not USE_MOTIF */
43 #if defined (USE_LUCID)
44 #define USE_XAW
45 #endif /* not USE_MOTIF && USE_LUCID */
46 #endif
47 #if defined (USE_XAW)
48 #ifdef HAVE_XAW3D
49 #include <X11/Xaw3d/Paned.h>
50 #else /* !HAVE_XAW3D */
51 #include <X11/Xaw/Paned.h>
52 #endif /* HAVE_XAW3D */
53 #include "lwlib-Xaw.h"
54 #endif
55
56 #if !defined (USE_LUCID) && !defined (USE_MOTIF)
57 #error At least one of USE_LUCID or USE_MOTIF must be defined.
58 #endif
59
60 #ifndef max
61 #define max(x, y) ((x) > (y) ? (x) : (y))
62 #endif
63
64 /* List of all widgets managed by the library. */
65 static widget_info*
66 all_widget_info = NULL;
67
68 #ifdef USE_MOTIF
69 char *lwlib_toolkit_type = "motif";
70 #else
71 char *lwlib_toolkit_type = "lucid";
72 #endif
73
74 static widget_value *merge_widget_value (widget_value *,
75 widget_value *,
76 int, int *);
77 static void instantiate_widget_instance (widget_instance *);
78 static int my_strcasecmp (char *, char *);
79 static void safe_free_str (char *);
80 static void free_widget_value_tree (widget_value *);
81 static widget_value *copy_widget_value_tree (widget_value *,
82 change_type);
83 static widget_info *allocate_widget_info (char *, char *, LWLIB_ID,
84 widget_value *,
85 lw_callback, lw_callback,
86 lw_callback, lw_callback);
87 static void free_widget_info (widget_info *);
88 static void mark_widget_destroyed (Widget, XtPointer, XtPointer);
89 static widget_instance *allocate_widget_instance (widget_info *,
90 Widget, Boolean);
91 static void free_widget_instance (widget_instance *);
92 static widget_info *get_widget_info (LWLIB_ID, Boolean);
93 static widget_instance *get_widget_instance (Widget, Boolean);
94 static widget_instance *find_instance (LWLIB_ID, Widget, Boolean);
95 static Boolean safe_strcmp (char *, char *);
96 static Widget name_to_widget (widget_instance *, char *);
97 static void set_one_value (widget_instance *, widget_value *, Boolean);
98 static void update_one_widget_instance (widget_instance *, Boolean);
99 static void update_all_widget_values (widget_info *, Boolean);
100 static void initialize_widget_instance (widget_instance *);
101 static widget_creation_function find_in_table (char *, widget_creation_entry *);
102 static Boolean dialog_spec_p (char *);
103 static void destroy_one_instance (widget_instance *);
104 static void lw_pop_all_widgets (LWLIB_ID, Boolean);
105 static Boolean get_one_value (widget_instance *, widget_value *);
106 static void show_one_widget_busy (Widget, Boolean);
107 \f/* utility functions for widget_instance and widget_info */
108 char *
109 safe_strdup (const char *s)
110 {
111 char *result;
112 if (! s) return 0;
113 result = (char *) malloc (strlen (s) + 1);
114 if (! result)
115 return 0;
116 strcpy (result, s);
117 return result;
118 }
119
120 /* Like strcmp but ignore differences in case. */
121
122 static int
123 my_strcasecmp (char *s1, char *s2)
124 {
125 while (1)
126 {
127 int c1 = *s1++;
128 int c2 = *s2++;
129 if (isupper (c1))
130 c1 = tolower (c1);
131 if (isupper (c2))
132 c2 = tolower (c2);
133 if (c1 != c2)
134 return (c1 > c2 ? 1 : -1);
135 if (c1 == 0)
136 return 0;
137 }
138 }
139
140 static void
141 safe_free_str (char *s)
142 {
143 free (s);
144 }
145
146 static widget_value *widget_value_free_list = 0;
147 static int malloc_cpt = 0;
148
149 widget_value *
150 malloc_widget_value (void)
151 {
152 widget_value *wv;
153 if (widget_value_free_list)
154 {
155 wv = widget_value_free_list;
156 widget_value_free_list = wv->free_list;
157 wv->free_list = 0;
158 }
159 else
160 {
161 wv = (widget_value *) malloc (sizeof (widget_value));
162 malloc_cpt++;
163 }
164 memset ((void*) wv, 0, sizeof (widget_value));
165 return wv;
166 }
167
168 /* this is analogous to free(). It frees only what was allocated
169 by malloc_widget_value(), and no substructures.
170 */
171 void
172 free_widget_value (widget_value *wv)
173 {
174 if (wv->free_list)
175 abort ();
176
177 if (malloc_cpt > 25)
178 {
179 /* When the number of already allocated cells is too big,
180 We free it. */
181 free (wv);
182 malloc_cpt--;
183 }
184 else
185 {
186 wv->free_list = widget_value_free_list;
187 widget_value_free_list = wv;
188 }
189 }
190
191 static void
192 free_widget_value_tree (widget_value *wv)
193 {
194 if (!wv)
195 return;
196
197 free (wv->name);
198 free (wv->value);
199 free (wv->key);
200
201 wv->name = wv->value = wv->key = (char *) 0xDEADBEEF;
202
203 if (wv->toolkit_data && wv->free_toolkit_data)
204 {
205 XtFree (wv->toolkit_data);
206 wv->toolkit_data = (void *) 0xDEADBEEF;
207 }
208
209 if (wv->contents && (wv->contents != (widget_value*)1))
210 {
211 free_widget_value_tree (wv->contents);
212 wv->contents = (widget_value *) 0xDEADBEEF;
213 }
214 if (wv->next)
215 {
216 free_widget_value_tree (wv->next);
217 wv->next = (widget_value *) 0xDEADBEEF;
218 }
219 free_widget_value (wv);
220 }
221
222 static widget_value *
223 copy_widget_value_tree (widget_value *val, change_type change)
224 {
225 widget_value* copy;
226
227 if (!val)
228 return NULL;
229 if (val == (widget_value *) 1)
230 return val;
231
232 copy = malloc_widget_value ();
233 copy->name = safe_strdup (val->name);
234 copy->value = safe_strdup (val->value);
235 copy->key = safe_strdup (val->key);
236 copy->help = val->help;
237 copy->enabled = val->enabled;
238 copy->button_type = val->button_type;
239 copy->selected = val->selected;
240 copy->edited = False;
241 copy->change = change;
242 copy->this_one_change = change;
243 copy->contents = copy_widget_value_tree (val->contents, change);
244 copy->call_data = val->call_data;
245 copy->next = copy_widget_value_tree (val->next, change);
246 copy->toolkit_data = NULL;
247 copy->free_toolkit_data = False;
248 return copy;
249 }
250
251 static widget_info *
252 allocate_widget_info (type, name, id, val, pre_activate_cb,
253 selection_cb, post_activate_cb, highlight_cb)
254 char* type;
255 char* name;
256 LWLIB_ID id;
257 widget_value* val;
258 lw_callback pre_activate_cb;
259 lw_callback selection_cb;
260 lw_callback post_activate_cb;
261 lw_callback highlight_cb;
262 {
263 widget_info* info = (widget_info*)malloc (sizeof (widget_info));
264 info->type = safe_strdup (type);
265 info->name = safe_strdup (name);
266 info->id = id;
267 info->val = copy_widget_value_tree (val, STRUCTURAL_CHANGE);
268 info->busy = False;
269 info->pre_activate_cb = pre_activate_cb;
270 info->selection_cb = selection_cb;
271 info->post_activate_cb = post_activate_cb;
272 info->highlight_cb = highlight_cb;
273 info->instances = NULL;
274
275 info->next = all_widget_info;
276 all_widget_info = info;
277
278 return info;
279 }
280
281 static void
282 free_widget_info (widget_info *info)
283 {
284 safe_free_str (info->type);
285 safe_free_str (info->name);
286 free_widget_value_tree (info->val);
287 memset ((void*)info, 0xDEADBEEF, sizeof (widget_info));
288 free (info);
289 }
290
291 static void
292 mark_widget_destroyed (Widget widget, XtPointer closure, XtPointer call_data)
293 {
294 widget_instance* instance = (widget_instance*)closure;
295
296 /* be very conservative */
297 if (instance->widget == widget)
298 instance->widget = NULL;
299 }
300
301 static widget_instance *
302 allocate_widget_instance (widget_info* info, Widget parent, Boolean pop_up_p)
303 {
304 widget_instance* instance =
305 (widget_instance*)malloc (sizeof (widget_instance));
306 memset (instance, 0, sizeof *instance);
307 instance->parent = parent;
308 instance->pop_up_p = pop_up_p;
309 instance->info = info;
310 instance->next = info->instances;
311 info->instances = instance;
312
313 instantiate_widget_instance (instance);
314
315 XtAddCallback (instance->widget, XtNdestroyCallback,
316 mark_widget_destroyed, (XtPointer)instance);
317 return instance;
318 }
319
320 static void
321 free_widget_instance (widget_instance *instance)
322 {
323 memset ((void*)instance, 0xDEADBEEF, sizeof (widget_instance));
324 free (instance);
325 }
326
327 static widget_info *
328 get_widget_info (LWLIB_ID id, Boolean remove_p)
329 {
330 widget_info* info;
331 widget_info* prev;
332 for (prev = NULL, info = all_widget_info;
333 info;
334 prev = info, info = info->next)
335 if (info->id == id)
336 {
337 if (remove_p)
338 {
339 if (prev)
340 prev->next = info->next;
341 else
342 all_widget_info = info->next;
343 }
344 return info;
345 }
346 return NULL;
347 }
348
349 /* Internal function used by the library dependent implementation to get the
350 widget_value for a given widget in an instance */
351 widget_info *
352 lw_get_widget_info (LWLIB_ID id)
353 {
354 return get_widget_info (id, 0);
355 }
356
357 static widget_instance *
358 get_widget_instance (Widget widget, Boolean remove_p)
359 {
360 widget_info* info;
361 widget_instance* instance;
362 widget_instance* prev;
363 for (info = all_widget_info; info; info = info->next)
364 for (prev = NULL, instance = info->instances;
365 instance;
366 prev = instance, instance = instance->next)
367 if (instance->widget == widget)
368 {
369 if (remove_p)
370 {
371 if (prev)
372 prev->next = instance->next;
373 else
374 info->instances = instance->next;
375 }
376 return instance;
377 }
378 return (widget_instance *) 0;
379 }
380
381 /* Value is a pointer to the widget_instance corresponding to
382 WIDGET, or null if WIDGET is not a lwlib widget. */
383
384 widget_instance *
385 lw_get_widget_instance (Widget widget)
386 {
387 return get_widget_instance (widget, False);
388 }
389
390 static widget_instance*
391 find_instance (LWLIB_ID id, Widget parent, Boolean pop_up_p)
392 {
393 widget_info* info = get_widget_info (id, False);
394 widget_instance* instance;
395
396 if (info)
397 for (instance = info->instances; instance; instance = instance->next)
398 if (instance->parent == parent && instance->pop_up_p == pop_up_p)
399 return instance;
400
401 return NULL;
402 }
403
404 \f
405 /* utility function for widget_value */
406 static Boolean
407 safe_strcmp (char *s1, char *s2)
408 {
409 if (!!s1 ^ !!s2) return True;
410 return (s1 && s2) ? strcmp (s1, s2) : s1 ? False : !!s2;
411 }
412
413
414 #if 0
415 # define EXPLAIN(name, oc, nc, desc, a1, a2) \
416 printf ("Change: \"%s\"\tmax(%s=%d,%s=%d)\t%s %d %d\n", \
417 name, \
418 (oc == NO_CHANGE ? "none" : \
419 (oc == INVISIBLE_CHANGE ? "invisible" : \
420 (oc == VISIBLE_CHANGE ? "visible" : \
421 (oc == STRUCTURAL_CHANGE ? "structural" : "???")))), \
422 oc, \
423 (nc == NO_CHANGE ? "none" : \
424 (nc == INVISIBLE_CHANGE ? "invisible" : \
425 (nc == VISIBLE_CHANGE ? "visible" : \
426 (nc == STRUCTURAL_CHANGE ? "structural" : "???")))), \
427 nc, desc, a1, a2)
428 #else
429 # define EXPLAIN(name, oc, nc, desc, a1, a2)
430 #endif
431
432
433 static widget_value *
434 merge_widget_value (widget_value *val1, widget_value *val2, int level, int *change_p)
435 {
436 change_type change, this_one_change;
437 widget_value* merged_next;
438 widget_value* merged_contents;
439
440 if (!val1)
441 {
442 if (val2)
443 {
444 *change_p = 1;
445 return copy_widget_value_tree (val2, STRUCTURAL_CHANGE);
446 }
447 else
448 return NULL;
449 }
450 if (!val2)
451 {
452 *change_p = 1;
453 free_widget_value_tree (val1);
454 return NULL;
455 }
456
457 change = NO_CHANGE;
458
459 if (safe_strcmp (val1->name, val2->name))
460 {
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);
466 }
467 if (safe_strcmp (val1->value, val2->value))
468 {
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);
474 }
475 if (safe_strcmp (val1->key, val2->key))
476 {
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);
482 }
483 if (! EQ (val1->help, val2->help))
484 {
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;
489 }
490 if (val1->enabled != val2->enabled)
491 {
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;
496 }
497 if (val1->button_type != val2->button_type)
498 {
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;
503 }
504 if (val1->selected != val2->selected)
505 {
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;
510 }
511 if (val1->call_data != val2->call_data)
512 {
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;
517 }
518
519 if (level > 0)
520 {
521 merged_contents =
522 merge_widget_value (val1->contents, val2->contents, level - 1,
523 change_p);
524
525 if (val1->contents && !merged_contents)
526 {
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.
530
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);
535 }
536 else if (merged_contents && merged_contents->change != NO_CHANGE)
537 {
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
546 }
547
548 val1->contents = merged_contents;
549 }
550
551 this_one_change = change;
552
553 merged_next = merge_widget_value (val1->next, val2->next, level, change_p);
554
555 if (val1->next && !merged_next)
556 {
557 EXPLAIN (val1->name, change, STRUCTURAL_CHANGE, "(following gone)",
558 0, 0);
559 change = max (change, STRUCTURAL_CHANGE);
560 }
561 else if (merged_next)
562 {
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);
567 }
568
569 val1->next = merged_next;
570
571 val1->this_one_change = this_one_change;
572 val1->change = change;
573
574 if (change > NO_CHANGE && val1->toolkit_data)
575 {
576 *change_p = 1;
577 if (val1->free_toolkit_data)
578 XtFree (val1->toolkit_data);
579 val1->toolkit_data = NULL;
580 }
581
582 return val1;
583 }
584
585 \f
586 /* modifying the widgets */
587 static Widget
588 name_to_widget (widget_instance *instance, char *name)
589 {
590 Widget widget = NULL;
591
592 if (!instance->widget)
593 return NULL;
594
595 if (!strcmp (XtName (instance->widget), name))
596 widget = instance->widget;
597 else
598 {
599 int length = strlen (name) + 2;
600 char* real_name = (char *) xmalloc (length);
601 real_name [0] = '*';
602 strcpy (real_name + 1, name);
603
604 widget = XtNameToWidget (instance->widget, real_name);
605
606 free (real_name);
607 }
608 return widget;
609 }
610
611 static void
612 set_one_value (widget_instance* instance, widget_value* val, Boolean deep_p)
613 {
614 Widget widget = name_to_widget (instance, val->name);
615
616 if (widget)
617 {
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
630 }
631 }
632
633 static void
634 update_one_widget_instance (widget_instance* instance, Boolean deep_p)
635 {
636 widget_value *val;
637
638 if (!instance->widget)
639 /* the widget was destroyed */
640 return;
641
642 for (val = instance->info->val; val; val = val->next)
643 if (val->change != NO_CHANGE)
644 set_one_value (instance, val, deep_p);
645 }
646
647 static void
648 update_all_widget_values (widget_info* info, Boolean deep_p)
649 {
650 widget_instance* instance;
651 widget_value* val;
652
653 for (instance = info->instances; instance; instance = instance->next)
654 update_one_widget_instance (instance, deep_p);
655
656 for (val = info->val; val; val = val->next)
657 val->change = NO_CHANGE;
658 }
659
660 int
661 lw_modify_all_widgets (LWLIB_ID id, widget_value* val, Boolean deep_p)
662 {
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;
671
672 if (!info)
673 return 0;
674
675 for (new_val = val; new_val; new_val = new_val->next)
676 {
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))
682 {
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;
695 }
696 if (!found)
697 {
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;
704 }
705 new_val->next = next_new_val;
706 }
707
708 update_all_widget_values (info, deep_p);
709 return change_p;
710 }
711
712 \f
713 /* creating the widgets */
714
715 static void
716 initialize_widget_instance (widget_instance *instance)
717 {
718 widget_value* val;
719
720 for (val = instance->info->val; val; val = val->next)
721 val->change = STRUCTURAL_CHANGE;
722
723 update_one_widget_instance (instance, True);
724
725 for (val = instance->info->val; val; val = val->next)
726 val->change = NO_CHANGE;
727 }
728
729
730 static widget_creation_function
731 find_in_table (char *type, widget_creation_entry *table)
732 {
733 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;
738 }
739
740 static Boolean
741 dialog_spec_p (char *name)
742 {
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;
747
748 switch (name [0])
749 {
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')
753 {
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;
764 }
765 else
766 return False;
767
768 default:
769 return False;
770 }
771 }
772
773 static void
774 instantiate_widget_instance (widget_instance *instance)
775 {
776 widget_creation_function function = NULL;
777
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
790
791 if (!function)
792 {
793 if (dialog_spec_p (instance->info->type))
794 {
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
806 }
807 }
808
809 if (!function)
810 {
811 printf ("No creation function for widget type %s\n",
812 instance->info->type);
813 abort ();
814 }
815
816 instance->widget = (*function) (instance);
817
818 if (!instance->widget)
819 abort ();
820
821 /* XtRealizeWidget (instance->widget);*/
822 }
823
824 void
825 lw_register_widget (type, name, id, val, pre_activate_cb,
826 selection_cb, post_activate_cb, highlight_cb)
827 char* type;
828 char* name;
829 LWLIB_ID id;
830 widget_value* val;
831 lw_callback pre_activate_cb;
832 lw_callback selection_cb;
833 lw_callback post_activate_cb;
834 lw_callback highlight_cb;
835 {
836 if (!get_widget_info (id, False))
837 allocate_widget_info (type, name, id, val, pre_activate_cb, selection_cb,
838 post_activate_cb, highlight_cb);
839 }
840
841 Widget
842 lw_get_widget (LWLIB_ID id, Widget parent, Boolean pop_up_p)
843 {
844 widget_instance* instance;
845
846 instance = find_instance (id, parent, pop_up_p);
847 return instance ? instance->widget : NULL;
848 }
849
850 Widget
851 lw_make_widget (LWLIB_ID id, Widget parent, Boolean pop_up_p)
852 {
853 widget_instance* instance;
854 widget_info* info;
855
856 instance = find_instance (id, parent, pop_up_p);
857 if (!instance)
858 {
859 info = get_widget_info (id, False);
860 if (!info)
861 return NULL;
862 instance = allocate_widget_instance (info, parent, pop_up_p);
863 initialize_widget_instance (instance);
864 }
865 if (!instance->widget)
866 abort ();
867 return instance->widget;
868 }
869
870 Widget
871 lw_create_widget (char* type, char* name, LWLIB_ID id, widget_value* val,
872 Widget parent, Boolean pop_up_p,
873 lw_callback pre_activate_cb, lw_callback selection_cb,
874 lw_callback post_activate_cb, lw_callback highlight_cb)
875 {
876 lw_register_widget (type, name, id, val, pre_activate_cb, selection_cb,
877 post_activate_cb, highlight_cb);
878 return lw_make_widget (id, parent, pop_up_p);
879 }
880
881 \f
882 /* destroying the widgets */
883 static void
884 destroy_one_instance (widget_instance *instance)
885 {
886 /* Remove the destroy callback on the widget; that callback will try to
887 dereference the instance object (to set its widget slot to 0, since the
888 widget is dead.) Since the instance is now dead, we don't have to worry
889 about the fact that its widget is dead too.
890
891 This happens in the Phase2Destroy of the widget, so this callback would
892 not have been run until arbitrarily long after the instance was freed.
893 */
894 if (instance->widget)
895 XtRemoveCallback (instance->widget, XtNdestroyCallback,
896 mark_widget_destroyed, (XtPointer)instance);
897
898 if (instance->widget)
899 {
900 /* The else are pretty tricky here, including the empty statement
901 at the end because it would be very bad to destroy a widget
902 twice. */
903 #if defined (USE_LUCID)
904 if (lw_lucid_widget_p (instance->widget))
905 xlw_destroy_instance (instance);
906 else
907 #endif
908 #if defined (USE_MOTIF)
909 if (lw_motif_widget_p (instance->widget))
910 xm_destroy_instance (instance);
911 else
912 #endif
913 #if defined (USE_XAW)
914 if (lw_xaw_widget_p (instance->widget))
915 xaw_destroy_instance (instance);
916 else
917 #endif
918 /* do not remove the empty statement */
919 ;
920 }
921
922 free_widget_instance (instance);
923 }
924
925 void
926 lw_destroy_widget (Widget w)
927 {
928 widget_instance* instance = get_widget_instance (w, True);
929
930 if (instance)
931 {
932 widget_info *info = instance->info;
933 /* instance has already been removed from the list; free it */
934 destroy_one_instance (instance);
935 /* if there are no instances left, free the info too */
936 if (!info->instances)
937 lw_destroy_all_widgets (info->id);
938 }
939 }
940
941 void
942 lw_destroy_all_widgets (LWLIB_ID id)
943 {
944 widget_info* info = get_widget_info (id, True);
945 widget_instance* instance;
946 widget_instance* next;
947
948 if (info)
949 {
950 for (instance = info->instances; instance; )
951 {
952 next = instance->next;
953 destroy_one_instance (instance);
954 instance = next;
955 }
956 free_widget_info (info);
957 }
958 }
959
960 void
961 lw_destroy_everything (void)
962 {
963 while (all_widget_info)
964 lw_destroy_all_widgets (all_widget_info->id);
965 }
966
967 void
968 lw_destroy_all_pop_ups (void)
969 {
970 widget_info* info;
971 widget_info* next;
972 widget_instance* instance;
973
974 for (info = all_widget_info; info; info = next)
975 {
976 next = info->next;
977 instance = info->instances;
978 if (instance && instance->pop_up_p)
979 lw_destroy_all_widgets (info->id);
980 }
981 }
982
983 #ifdef USE_MOTIF
984 extern Widget first_child (/* Widget */); /* garbage */
985 #endif
986
987 Widget
988 lw_raise_all_pop_up_widgets (void)
989 {
990 widget_info* info;
991 widget_instance* instance;
992 Widget result = NULL;
993
994 for (info = all_widget_info; info; info = info->next)
995 for (instance = info->instances; instance; instance = instance->next)
996 if (instance->pop_up_p)
997 {
998 Widget widget = instance->widget;
999 if (widget)
1000 {
1001 if (XtIsManaged (widget)
1002 #ifdef USE_MOTIF
1003 /* What a complete load of crap!!!!
1004 When a dialogShell is on the screen, it is not managed!
1005 */
1006 || (lw_motif_widget_p (instance->widget) &&
1007 XtIsManaged (first_child (widget)))
1008 #endif
1009 )
1010 {
1011 if (!result)
1012 result = widget;
1013 XMapRaised (XtDisplay (widget), XtWindow (widget));
1014 }
1015 }
1016 }
1017 return result;
1018 }
1019
1020 static void
1021 lw_pop_all_widgets (LWLIB_ID id, Boolean up)
1022 {
1023 widget_info* info = get_widget_info (id, False);
1024 widget_instance* instance;
1025
1026 if (info)
1027 for (instance = info->instances; instance; instance = instance->next)
1028 if (instance->pop_up_p && instance->widget)
1029 {
1030 #if defined (USE_LUCID)
1031 if (lw_lucid_widget_p (instance->widget))
1032 {
1033 XtRealizeWidget (instance->widget);
1034 xlw_pop_instance (instance, up);
1035 }
1036 #endif
1037 #if defined (USE_MOTIF)
1038 if (lw_motif_widget_p (instance->widget))
1039 {
1040 XtRealizeWidget (instance->widget);
1041 xm_pop_instance (instance, up);
1042 }
1043 #endif
1044 #if defined (USE_XAW)
1045 if (lw_xaw_widget_p (instance->widget))
1046 {
1047 XtRealizeWidget (XtParent (instance->widget));
1048 XtRealizeWidget (instance->widget);
1049 xaw_pop_instance (instance, up);
1050 }
1051 #endif
1052 }
1053 }
1054
1055 void
1056 lw_pop_up_all_widgets (LWLIB_ID id)
1057 {
1058 lw_pop_all_widgets (id, True);
1059 }
1060
1061 void
1062 lw_pop_down_all_widgets (LWLIB_ID id)
1063 {
1064 lw_pop_all_widgets (id, False);
1065 }
1066
1067 void
1068 lw_popup_menu (Widget widget, XEvent *event)
1069 {
1070 #if defined (USE_LUCID)
1071 if (lw_lucid_widget_p (widget))
1072 xlw_popup_menu (widget, event);
1073 #endif
1074 #if defined (USE_MOTIF)
1075 if (lw_motif_widget_p (widget))
1076 xm_popup_menu (widget, event);
1077 #endif
1078 #if defined (USE_XAW)
1079 if (lw_xaw_widget_p (widget))
1080 xaw_popup_menu (widget, event);
1081 #endif
1082 }
1083
1084 \f/* get the values back */
1085 static Boolean
1086 get_one_value (widget_instance *instance, widget_value *val)
1087 {
1088 Widget widget = name_to_widget (instance, val->name);
1089
1090 if (widget)
1091 {
1092 #if defined (USE_LUCID)
1093 if (lw_lucid_widget_p (instance->widget))
1094 xlw_update_one_value (instance, widget, val);
1095 #endif
1096 #if defined (USE_MOTIF)
1097 if (lw_motif_widget_p (instance->widget))
1098 xm_update_one_value (instance, widget, val);
1099 #endif
1100 #if defined (USE_XAW)
1101 if (lw_xaw_widget_p (instance->widget))
1102 xaw_update_one_value (instance, widget, val);
1103 #endif
1104 return True;
1105 }
1106 else
1107 return False;
1108 }
1109
1110 Boolean
1111 lw_get_some_values (LWLIB_ID id, widget_value *val_out)
1112 {
1113 widget_info* info = get_widget_info (id, False);
1114 widget_instance* instance;
1115 widget_value* val;
1116 Boolean result = False;
1117
1118 if (!info)
1119 return False;
1120
1121 instance = info->instances;
1122 if (!instance)
1123 return False;
1124
1125 for (val = val_out; val; val = val->next)
1126 if (get_one_value (instance, val))
1127 result = True;
1128
1129 return result;
1130 }
1131
1132 widget_value*
1133 lw_get_all_values (LWLIB_ID id)
1134 {
1135 widget_info* info = get_widget_info (id, False);
1136 widget_value* val = info->val;
1137 if (lw_get_some_values (id, val))
1138 return val;
1139 else
1140 return NULL;
1141 }
1142
1143 /* internal function used by the library dependent implementation to get the
1144 widget_value for a given widget in an instance */
1145 widget_value*
1146 lw_get_widget_value_for_widget (widget_instance *instance, Widget w)
1147 {
1148 char* name = XtName (w);
1149 widget_value* cur;
1150 for (cur = instance->info->val; cur; cur = cur->next)
1151 if (!strcmp (cur->name, name))
1152 return cur;
1153 return NULL;
1154 }
1155
1156 \f/* update other instances value when one thing changed */
1157
1158 /* To forbid recursive calls */
1159 static Boolean lwlib_updating;
1160
1161 /* This function can be used as a an XtCallback for the widgets that get
1162 modified to update other instances of the widgets. Closure should be the
1163 widget_instance. */
1164 void
1165 lw_internal_update_other_instances (Widget widget, XtPointer closure, XtPointer call_data)
1166 {
1167 widget_instance* instance = (widget_instance*)closure;
1168 char* name = XtName (widget);
1169 widget_info* info;
1170 widget_instance* cur;
1171 widget_value* val;
1172
1173 /* Avoid possibly infinite recursion. */
1174 if (lwlib_updating)
1175 return;
1176
1177 /* protect against the widget being destroyed */
1178 if (XtWidgetBeingDestroyedP (widget))
1179 return;
1180
1181 /* Return immediately if there are no other instances */
1182 info = instance->info;
1183 if (!info->instances->next)
1184 return;
1185
1186 lwlib_updating = True;
1187
1188 for (val = info->val; val && strcmp (val->name, name); val = val->next);
1189
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);
1194
1195 lwlib_updating = False;
1196 }
1197
1198
1199 \f/* get the id */
1200
1201 LWLIB_ID
1202 lw_get_widget_id (Widget w)
1203 {
1204 widget_instance* instance = get_widget_instance (w, False);
1205
1206 return instance ? instance->info->id : 0;
1207 }
1208
1209 \f/* set the keyboard focus */
1210 void
1211 lw_set_keyboard_focus (Widget parent, Widget w)
1212 {
1213 #if defined (USE_MOTIF)
1214 xm_set_keyboard_focus (parent, w);
1215 #else
1216 XtSetKeyboardFocus (parent, w);
1217 #endif
1218 }
1219
1220 \f/* Show busy */
1221 static void
1222 show_one_widget_busy (Widget w, Boolean flag)
1223 {
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;
1229
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);
1238 }
1239
1240 void
1241 lw_show_busy (Widget w, Boolean busy)
1242 {
1243 widget_instance* instance = get_widget_instance (w, False);
1244 widget_info* info;
1245 widget_instance* next;
1246
1247 if (instance)
1248 {
1249 info = instance->info;
1250 if (info->busy != busy)
1251 {
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;
1256 }
1257 }
1258 }
1259
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)
1264 {
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
1274 }
1275
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)
1280 {
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
1291 }
1292
1293 /* Motif hack to set the main window areas. */
1294 void
1295 lw_set_main_areas (Widget parent, Widget menubar, Widget work_area)
1296 {
1297 #if defined (USE_MOTIF)
1298 xm_set_main_areas (parent, menubar, work_area);
1299 #endif
1300 }
1301
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)
1306 {
1307 #if defined (USE_MOTIF)
1308 xm_manage_resizing (w, flag);
1309 #endif
1310 }
1311
1312
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. */
1317
1318 int
1319 lw_separator_p (char *label, enum menu_separator *type, int motif_p)
1320 {
1321 int separator_p = 0;
1322
1323 if (strlen (label) >= 3
1324 && memcmp (label, "--:", 3) == 0)
1325 {
1326 static struct separator_table
1327 {
1328 char *name;
1329 enum menu_separator type;
1330 }
1331 separator_names[] =
1332 {
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}
1348 };
1349
1350 int i;
1351
1352 label += 3;
1353 for (i = 0; separator_names[i].name; ++i)
1354 if (strcmp (label, separator_names[i].name) == 0)
1355 {
1356 separator_p = 1;
1357 *type = separator_names[i].type;
1358
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;
1364 }
1365 }
1366 else if (strlen (label) > 3
1367 && memcmp (label, "--", 2) == 0
1368 && label[2] != '-')
1369 {
1370 /* Alternative, more Emacs-style names. */
1371 static struct separator_table
1372 {
1373 char *name;
1374 enum menu_separator type;
1375 }
1376 separator_names[] =
1377 {
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}
1393 };
1394
1395 int i;
1396
1397 label += 2;
1398 for (i = 0; separator_names[i].name; ++i)
1399 if (strcmp (label, separator_names[i].name) == 0)
1400 {
1401 separator_p = 1;
1402 *type = separator_names[i].type;
1403
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;
1409 }
1410 }
1411 else
1412 {
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;
1419 }
1420
1421 return separator_p;
1422 }
1423
1424 /* arch-tag: 3d730f36-a441-4a71-9971-48ef3b5a4d9f
1425 (do not change this comment) */