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