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