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