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