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