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