(redisplay_internal): Renamed from redisplay.
[bpt/emacs.git] / lwlib / lwlib.c
CommitLineData
07bf635f
RS
1/* A general interface to the widgets of different toolkits.
2 Copyright (C) 1992, 1993 Lucid, Inc.
3
4This file is part of the Lucid Widget Library.
5
6The Lucid Widget Library is free software; you can redistribute it and/or
7modify it under the terms of the GNU General Public License as published by
8the Free Software Foundation; either version 2, or (at your option)
9any later version.
10
11The Lucid Widget Library is distributed in the hope that it will be useful,
12but WITHOUT ANY WARRANTY; without even the implied warranty of
13MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14GNU General Public License for more details.
15
16You should have received a copy of the GNU General Public License
17along with GNU Emacs; see the file COPYING. If not, write to
3b7ad313
EN
18the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
19Boston, MA 02111-1307, USA. */
07bf635f
RS
20
21#ifdef NeXT
22#undef __STRICT_BSD__ /* ick */
23#endif
24
07bf635f 25#include <sys/types.h>
07bf635f 26#include <stdio.h>
5f61736f 27#include <ctype.h>
e7818b5a 28#include "lwlib-int.h"
07bf635f 29#include "lwlib-utils.h"
01492d1b 30#include <X11/StringDefs.h>
07bf635f 31
c7d71315
RS
32#ifdef __osf__
33#include <string.h>
34#include <stdlib.h>
35extern long *xmalloc();
36#endif
37
07bf635f
RS
38#if defined (USE_LUCID)
39#include "lwlib-Xlw.h"
40#endif
41#if defined (USE_MOTIF)
42#include "lwlib-Xm.h"
ce5a08a1
FP
43#else /* not USE_MOTIF */
44#if defined (USE_LUCID)
45#define USE_XAW
46#endif /* not USE_MOTIF && USE_LUCID */
07bf635f
RS
47#endif
48#if defined (USE_OLIT)
49#include "lwlib-Xol.h"
50#endif
9331cca8
FP
51#if defined (USE_XAW)
52#include "lwlib-Xaw.h"
53#endif
07bf635f
RS
54
55#if !defined (USE_LUCID) && !defined (USE_MOTIF) && !defined (USE_OLIT)
56ERROR! 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)
60ERROR! no more than one of USE_MOTIF and USE_OLIT may be defined.
61#endif
62
2af91681
PR
63#ifndef max
64#define max(x, y) ((x) > (y) ? (x) : (y))
65#endif
66
07bf635f
RS
67/* List of all widgets managed by the library. */
68static widget_info*
69all_widget_info = NULL;
70
99dcca2f
KH
71#ifdef USE_MOTIF
72char *lwlib_toolkit_type = "motif";
73#else
74char *lwlib_toolkit_type = "lucid";
75#endif
07bf635f
RS
76\f/* Forward declarations */
77static void
7ef3956a 78instantiate_widget_instance (/* widget_instance* instance */);
07bf635f 79
f60044f5
RS
80lwlib_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
91lwlib_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}
07bf635f 101\f/* utility functions for widget_instance and widget_info */
bb2ee72b 102char *
5f61736f
RS
103safe_strdup (s)
104 char *s;
07bf635f
RS
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
5f61736f
RS
115/* Like strcmp but ignore differences in case. */
116
117static int
ed9c1473 118my_strcasecmp (s1, s2)
5f61736f
RS
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
07bf635f 136static void
5f61736f
RS
137safe_free_str (s)
138 char *s;
07bf635f
RS
139{
140 if (s) free (s);
141}
142
143static widget_value *widget_value_free_list = 0;
0b96f00b 144static int malloc_cpt = 0;
07bf635f
RS
145
146widget_value *
147malloc_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));
0b96f00b 159 malloc_cpt++;
07bf635f 160 }
f60044f5 161 lwlib_memset (wv, 0, sizeof (widget_value));
07bf635f
RS
162 return wv;
163}
164
7ef3956a 165/* this is analogous to free(). It frees only what was allocated
07bf635f
RS
166 by malloc_widget_value(), and no substructures.
167 */
168void
169free_widget_value (wv)
170 widget_value *wv;
171{
172 if (wv->free_list)
173 abort ();
0b96f00b 174
d2a5919f 175 if (malloc_cpt > 25)
0b96f00b
FP
176 {
177 /* When the number of already allocated cells is too big,
178 We free it. */
0b96f00b 179 free (wv);
d2a5919f 180 malloc_cpt--;
0b96f00b
FP
181 }
182 else
183 {
184 wv->free_list = widget_value_free_list;
185 widget_value_free_list = wv;
186 }
07bf635f
RS
187}
188
189static void
5f61736f
RS
190free_widget_value_tree (wv)
191 widget_value *wv;
07bf635f
RS
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 {
53e28d2a 204 XtFree (wv->toolkit_data);
07bf635f
RS
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
221static widget_value *
5f61736f
RS
222copy_widget_value_tree (val, change)
223 widget_value* val;
224 change_type change;
07bf635f
RS
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
249static widget_info *
5f61736f
RS
250allocate_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;
07bf635f
RS
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
276static void
5f61736f
RS
277free_widget_info (info)
278 widget_info* info;
07bf635f
RS
279{
280 safe_free_str (info->type);
281 safe_free_str (info->name);
282 free_widget_value_tree (info->val);
f60044f5 283 lwlib_memset ((void*)info, 0xDEADBEEF, sizeof (widget_info));
07bf635f
RS
284 free (info);
285}
286
287static void
5f61736f
RS
288mark_widget_destroyed (widget, closure, call_data)
289 Widget widget;
290 XtPointer closure;
291 XtPointer call_data;
07bf635f
RS
292{
293 widget_instance* instance = (widget_instance*)closure;
294
295 /* be very conservative */
296 if (instance->widget == widget)
297 instance->widget = NULL;
298}
299
300static widget_instance *
5f61736f
RS
301allocate_widget_instance (info, parent, pop_up_p)
302 widget_info* info;
303 Widget parent;
304 Boolean pop_up_p;
07bf635f
RS
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
7ef3956a 314 instantiate_widget_instance (instance);
07bf635f
RS
315
316 XtAddCallback (instance->widget, XtNdestroyCallback,
317 mark_widget_destroyed, (XtPointer)instance);
318 return instance;
319}
320
321static void
5f61736f
RS
322free_widget_instance (instance)
323 widget_instance* instance;
07bf635f 324{
f60044f5 325 lwlib_memset ((void*)instance, 0xDEADBEEF, sizeof (widget_instance));
07bf635f
RS
326 free (instance);
327}
328
329static widget_info *
5f61736f
RS
330get_widget_info (id, remove_p)
331 LWLIB_ID id;
332 Boolean remove_p;
07bf635f
RS
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
9331cca8
FP
353/* Internal function used by the library dependent implementation to get the
354 widget_value for a given widget in an instance */
355widget_info *
e14e13a4
FP
356lw_get_widget_info (id)
357 LWLIB_ID id;
9331cca8
FP
358{
359 return get_widget_info (id, 0);
360}
361
07bf635f 362static widget_instance *
5f61736f
RS
363get_widget_instance (widget, remove_p)
364 Widget widget;
365 Boolean remove_p;
07bf635f
RS
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
388static widget_instance*
5f61736f
RS
389find_instance (id, parent, pop_up_p)
390 LWLIB_ID id;
391 Widget parent;
392 Boolean pop_up_p;
07bf635f
RS
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 */
407static Boolean
5f61736f
RS
408safe_strcmp (s1, s2)
409 char* s1;
410 char* s2;
07bf635f
RS
411{
412 if (!!s1 ^ !!s2) return True;
413 return (s1 && s2) ? strcmp (s1, s2) : s1 ? False : !!s2;
414}
415
07bf635f
RS
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
436static widget_value *
5f61736f
RS
437merge_widget_value (val1, val2, level)
438 widget_value* val1;
439 widget_value* val2;
440 int level;
07bf635f
RS
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 {
7ef3956a
RS
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)",
07bf635f 520 0, 0);
7ef3956a 521 change = max (change, STRUCTURAL_CHANGE);
07bf635f
RS
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)
53e28d2a 556 XtFree (val1->toolkit_data);
07bf635f
RS
557 val1->toolkit_data = NULL;
558 }
559
560 return val1;
561}
562
563\f
564/* modifying the widgets */
565static Widget
5f61736f
RS
566name_to_widget (instance, name)
567 widget_instance* instance;
568 char* name;
07bf635f
RS
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;
f60044f5 580 char* real_name = (char *) xmalloc (length);
07bf635f
RS
581 real_name [0] = '*';
582 strcpy (real_name + 1, name);
583
584 widget = XtNameToWidget (instance->widget, real_name);
f60044f5
RS
585
586 free (real_name);
07bf635f
RS
587 }
588 return widget;
589}
590
591static void
5f61736f
RS
592set_one_value (instance, val, deep_p)
593 widget_instance* instance;
594 widget_value* val;
595 Boolean deep_p;
07bf635f
RS
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);
9331cca8
FP
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);
07bf635f
RS
616#endif
617 }
618}
619
620static void
5f61736f
RS
621update_one_widget_instance (instance, deep_p)
622 widget_instance* instance;
623 Boolean deep_p;
07bf635f
RS
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
636static void
5f61736f
RS
637update_all_widget_values (info, deep_p)
638 widget_info* info;
639 Boolean deep_p;
07bf635f
RS
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
651void
5f61736f
RS
652lw_modify_all_widgets (id, val, deep_p)
653 LWLIB_ID id;
654 widget_value* val;
655 Boolean deep_p;
07bf635f
RS
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
705static void
5f61736f
RS
706initialize_widget_instance (instance)
707 widget_instance* instance;
07bf635f
RS
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
721static widget_creation_function
5f61736f
RS
722find_in_table (type, table)
723 char* type;
724 widget_creation_entry* table;
07bf635f
RS
725{
726 widget_creation_entry* cur;
727 for (cur = table; cur->type; cur++)
ed9c1473 728 if (!my_strcasecmp (type, cur->type))
07bf635f
RS
729 return cur->function;
730 return NULL;
731}
732
733static Boolean
5f61736f
RS
734dialog_spec_p (name)
735 char* name;
07bf635f
RS
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
767static void
7ef3956a 768instantiate_widget_instance (instance)
5f61736f 769 widget_instance* instance;
07bf635f
RS
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
9331cca8
FP
785#if defined (USE_XAW)
786 if (!function)
787 function = find_in_table (instance->info->type, xaw_creation_table);
788#endif
07bf635f
RS
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
9331cca8
FP
801#if defined (USE_XAW)
802 if (!function)
803 function = xaw_create_dialog;
804#endif
07bf635f
RS
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
826void
5f61736f
RS
827lw_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;
07bf635f
RS
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
841Widget
5f61736f
RS
842lw_get_widget (id, parent, pop_up_p)
843 LWLIB_ID id;
844 Widget parent;
845 Boolean pop_up_p;
07bf635f
RS
846{
847 widget_instance* instance;
848
849 instance = find_instance (id, parent, pop_up_p);
850 return instance ? instance->widget : NULL;
851}
852
853Widget
5f61736f
RS
854lw_make_widget (id, parent, pop_up_p)
855 LWLIB_ID id;
856 Widget parent;
857 Boolean pop_up_p;
07bf635f
RS
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
876Widget
5f61736f
RS
877lw_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;
07bf635f
RS
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 */
895static void
5f61736f
RS
896destroy_one_instance (instance)
897 widget_instance* instance;
07bf635f
RS
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
9331cca8
FP
930#endif
931#if defined (USE_XAW)
932 if (lw_xaw_widget_p (instance->widget))
933 xaw_destroy_instance (instance);
934 else
07bf635f
RS
935#endif
936 /* do not remove the empty statement */
937 ;
938 }
939
940 free_widget_instance (instance);
941}
942
943void
5f61736f
RS
944lw_destroy_widget (w)
945 Widget w;
07bf635f
RS
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
960void
5f61736f
RS
961lw_destroy_all_widgets (id)
962 LWLIB_ID id;
07bf635f
RS
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
980void
981lw_destroy_everything ()
982{
983 while (all_widget_info)
984 lw_destroy_all_widgets (all_widget_info->id);
985}
986
987void
988lw_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
9e3fe459 1004extern Widget first_child (/* Widget */); /* garbage */
07bf635f
RS
1005#endif
1006
1007Widget
1008lw_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
1040static void
5f61736f
RS
1041lw_pop_all_widgets (id, up)
1042 LWLIB_ID id;
1043 Boolean up;
07bf635f
RS
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 {
07bf635f
RS
1052#if defined (USE_LUCID)
1053 if (lw_lucid_widget_p (instance->widget))
9331cca8
FP
1054 {
1055 XtRealizeWidget (instance->widget);
1056 xlw_pop_instance (instance, up);
1057 }
07bf635f
RS
1058#endif
1059#if defined (USE_MOTIF)
1060 if (lw_motif_widget_p (instance->widget))
9331cca8
FP
1061 {
1062 XtRealizeWidget (instance->widget);
1063 xm_pop_instance (instance, up);
1064 }
07bf635f
RS
1065#endif
1066#if defined (USE_OLIT)
1067 if (lw_olit_widget_p (instance->widget))
9331cca8
FP
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 }
07bf635f
RS
1080#endif
1081 }
1082}
1083
1084void
5f61736f
RS
1085lw_pop_up_all_widgets (id)
1086 LWLIB_ID id;
07bf635f
RS
1087{
1088 lw_pop_all_widgets (id, True);
1089}
1090
1091void
5f61736f
RS
1092lw_pop_down_all_widgets (id)
1093 LWLIB_ID id;
07bf635f
RS
1094{
1095 lw_pop_all_widgets (id, False);
1096}
1097
1098void
5b3b31d6 1099lw_popup_menu (widget, event)
5f61736f 1100 Widget widget;
5b3b31d6 1101 XEvent *event;
07bf635f
RS
1102{
1103#if defined (USE_LUCID)
1104 if (lw_lucid_widget_p (widget))
5b3b31d6 1105 xlw_popup_menu (widget, event);
07bf635f
RS
1106#endif
1107#if defined (USE_MOTIF)
1108 if (lw_motif_widget_p (widget))
5b3b31d6 1109 xm_popup_menu (widget, event);
07bf635f
RS
1110#endif
1111#if defined (USE_OLIT)
1112 if (lw_olit_widget_p (widget))
5b3b31d6 1113 xol_popup_menu (widget, event);
07bf635f 1114#endif
9331cca8
FP
1115#if defined (USE_XAW)
1116 if (lw_xaw_widget_p (widget))
5b3b31d6 1117 xaw_popup_menu (widget, event);
9331cca8 1118#endif
07bf635f
RS
1119}
1120
1121\f/* get the values back */
1122static Boolean
5f61736f
RS
1123get_one_value (instance, val)
1124 widget_instance* instance;
1125 widget_value* val;
07bf635f
RS
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);
9331cca8
FP
1142#endif
1143#if defined (USE_XAW)
1144 if (lw_xaw_widget_p (instance->widget))
1145 xaw_update_one_value (instance, widget, val);
07bf635f
RS
1146#endif
1147 return True;
1148 }
1149 else
1150 return False;
1151}
1152
1153Boolean
5f61736f
RS
1154lw_get_some_values (id, val_out)
1155 LWLIB_ID id;
1156 widget_value* val_out;
07bf635f
RS
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
1177widget_value*
5f61736f
RS
1178lw_get_all_values (id)
1179 LWLIB_ID id;
07bf635f
RS
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 */
1191widget_value*
5f61736f
RS
1192lw_get_widget_value_for_widget (instance, w)
1193 widget_instance* instance;
1194 Widget w;
07bf635f
RS
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 */
bd2c5b53
KH
1205
1206/* To forbid recursive calls */
1207static Boolean lwlib_updating;
1208
07bf635f
RS
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. */
1212void
5f61736f
RS
1213lw_internal_update_other_instances (widget, closure, call_data)
1214 Widget widget;
1215 XtPointer closure;
1216 XtPointer call_data;
07bf635f 1217{
07bf635f
RS
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
bd2c5b53
KH
1224 /* Avoid possibly infinite recursion. */
1225 if (lwlib_updating)
07bf635f
RS
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
bd2c5b53 1237 lwlib_updating = True;
07bf635f
RS
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
bd2c5b53 1246 lwlib_updating = False;
07bf635f
RS
1247}
1248
1249
1250\f/* get the id */
1251
1252LWLIB_ID
5f61736f
RS
1253lw_get_widget_id (w)
1254 Widget w;
07bf635f
RS
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 */
1262void
5f61736f
RS
1263lw_set_keyboard_focus (parent, w)
1264 Widget parent;
1265 Widget w;
07bf635f
RS
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 */
1275static void
5f61736f
RS
1276show_one_widget_busy (w, flag)
1277 Widget w;
1278 Boolean flag;
07bf635f
RS
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
1296void
5f61736f
RS
1297lw_show_busy (w, busy)
1298 Widget w;
1299 Boolean busy;
07bf635f
RS
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}
2af91681
PR
1317
1318/* This hack exists because Lucid/Athena need to execute the strange
1319 function below to support geometry management. */
1320void
1321lw_refigure_widget (w, doit)
1322 Widget w;
1323 Boolean doit;
1324{
e1241f09 1325#if defined (USE_XAW)
2af91681
PR
1326 XawPanedSetRefigureMode (w, doit);
1327#endif
1328#if defined (USE_MOTIF)
1329 if (doit)
2af91681 1330 XtManageChild (w);
a61155bc
RS
1331 else
1332 XtUnmanageChild (w);
2af91681
PR
1333#endif
1334}
1335
1336/* Toolkit independent way of determining if an event window is in the
1337 menubar. */
1338Boolean
1339lw_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 && XtWindowToWidget (XtDisplay (menubar_widget), win)
1349 && (XtParent (XtWindowToWidget (XtDisplay (menubar_widget), win))
1350 == menubar_widget);
1351#endif
1352}
1353
1354/* Motif hack to set the main window areas. */
1355void
1356lw_set_main_areas (parent, menubar, work_area)
1357 Widget parent;
1358 Widget menubar;
1359 Widget work_area;
1360{
1361#if defined (USE_MOTIF)
6618806e 1362 xm_set_main_areas (parent, menubar, work_area);
2af91681
PR
1363#endif
1364}
1365
1366/* Manage resizing for Motif. This disables resizing when the menubar
1367 is about to be modified. */
1368void
1369lw_allow_resizing (w, flag)
1370 Widget w;
1371 Boolean flag;
1372{
1373#if defined (USE_MOTIF)
f78c5177 1374 xm_manage_resizing (w, flag);
2af91681
PR
1375#endif
1376}