More warning suppressions
[sxemacs] / src / ui / lwlib / lwlib-Xaw.c
1 /* The lwlib interface to Athena widgets.
2    Copyright (C) 1993, 1994 Free Software Foundation, Inc.
3
4 This file is part of the Lucid Widget Library.
5
6 The Lucid Widget Library is free software: you can redistribute it
7 and/or modify it under the terms of the GNU General Public License as
8 published by the Free Software Foundation, either version 3 of the
9 License, or (at your option) any later version.
10
11 The Lucid Widget Library is distributed in the hope that it will be
12 useful, but WITHOUT ANY WARRANTY; without even the implied warranty of
13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
14 General Public License for more details.
15
16 You should have received a copy of the GNU General Public License
17 along with this program.  If not, see <http://www.gnu.org/licenses/>. */
18
19 #include <config.h>
20 #include <stdio.h>
21
22 #ifdef STDC_HEADERS
23 #include <stdlib.h>
24 #endif
25
26 #include "lwlib-Xaw.h"
27
28 #include <X11/StringDefs.h>
29 #include <X11/IntrinsicP.h>
30 #include <X11/CoreP.h>
31 #include <X11/Shell.h>
32
33 #ifdef LWLIB_SCROLLBARS_ATHENA
34 #include ATHENA_Scrollbar_h_
35 #endif
36 #ifdef LWLIB_DIALOGS_ATHENA
37 #include ATHENA_Dialog_h_
38 #include ATHENA_Form_h_
39 #include ATHENA_Command_h_
40 #include ATHENA_Label_h_
41 #endif
42 #ifdef LWLIB_WIDGETS_ATHENA
43 #include ATHENA_Toggle_h_
44 #include "xlwradio.h"
45 #include "xlwcheckbox.h"
46 #include "xlwgauge.h"
47 #include ATHENA_AsciiText_h_
48 #endif
49 #include <X11/Xatom.h>
50
51 static void xaw_generic_callback(Widget, XtPointer, XtPointer);
52
53 Boolean lw_xaw_widget_p(Widget widget)
54 {
55         return (0
56 #ifdef LWLIB_SCROLLBARS_ATHENA
57                 || XtIsSubclass(widget, scrollbarWidgetClass)
58 #endif
59 #ifdef LWLIB_DIALOGS_ATHENA
60                 || XtIsSubclass(widget, dialogWidgetClass)
61 #endif
62 #ifdef LWLIB_WIDGETS_ATHENA
63                 || XtIsSubclass(widget, labelWidgetClass)
64                 || XtIsSubclass(widget, toggleWidgetClass)
65                 || XtIsSubclass(widget, gaugeWidgetClass)
66 #ifndef NEED_MOTIF
67                 || XtIsSubclass(widget, asciiTextWidgetClass)
68 #endif
69 #endif
70             );
71 }
72
73 #ifdef LWLIB_SCROLLBARS_ATHENA
74 static void
75 xaw_update_scrollbar(widget_instance * instance, Widget widget,
76                      widget_value * val)
77 {
78         if (val->scrollbar_data) {
79                 scrollbar_values *data = val->scrollbar_data;
80                 float widget_shown, widget_topOfThumb;
81                 float new_shown, new_topOfThumb;
82                 Arg al[10];
83
84                 /* First size and position the scrollbar widget. */
85                 XtSetArg(al[0], XtNx, data->scrollbar_x);
86                 XtSetArg(al[1], XtNy, data->scrollbar_y);
87                 XtSetArg(al[2], XtNwidth, data->scrollbar_width);
88                 XtSetArg(al[3], XtNheight, data->scrollbar_height);
89                 XtSetValues(widget, al, 4);
90
91                 /* Now size the scrollbar's slider. */
92                 XtSetArg(al[0], XtNtopOfThumb, &widget_topOfThumb);
93                 XtSetArg(al[1], XtNshown, &widget_shown);
94                 XtGetValues(widget, al, 2);
95
96                 new_shown = (double)data->slider_size /
97                     (double)(data->maximum - data->minimum);
98
99                 new_topOfThumb =
100                     (double)(data->slider_position -
101                              data->minimum) / (double)(data->maximum -
102                                                        data->minimum);
103
104                 if (new_shown > 1.0)
105                         new_shown = 1.0;
106                 else if (new_shown < 0)
107                         new_shown = 0;
108
109                 if (new_topOfThumb > 1.0)
110                         new_topOfThumb = 1.0;
111                 else if (new_topOfThumb < 0)
112                         new_topOfThumb = 0;
113
114                 if (new_shown != widget_shown
115                     || new_topOfThumb != widget_topOfThumb)
116                         XawScrollbarSetThumb(widget, new_topOfThumb, new_shown);
117         }
118 }
119 #endif                          /* LWLIB_SCROLLBARS_ATHENA */
120
121 void
122 xaw_update_one_widget(widget_instance * instance, Widget widget,
123                       widget_value * val, Boolean deep_p)
124 {
125         if (0) ;
126 #ifdef LWLIB_SCROLLBARS_ATHENA
127         else if (XtIsSubclass(widget, scrollbarWidgetClass)) {
128                 xaw_update_scrollbar(instance, widget, val);
129         }
130 #endif
131 #ifdef LWLIB_WIDGETS_ATHENA
132 #ifndef NEED_MOTIF
133         else if (XtIsSubclass(widget, asciiTextWidgetClass)) {
134         }
135 #endif
136 #endif
137 #ifdef LWLIB_DIALOGS_ATHENA
138         else if (XtIsSubclass(widget, dialogWidgetClass)) {
139                 Arg al[1];
140                 XtSetArg(al[0], XtNlabel, val->contents->value);
141                 XtSetValues(widget, al, 1);
142         }
143 #endif                          /* LWLIB_DIALOGS_ATHENA */
144 #ifdef LWLIB_WIDGETS_ATHENA
145         else if (XtClass(widget) == labelWidgetClass) {
146                 Arg al[1];
147                 XtSetArg(al[0], XtNlabel, val->value);
148                 XtSetValues(widget, al, 1);
149         }
150 #endif                          /* LWLIB_WIDGETS_ATHENA */
151 #if defined (LWLIB_DIALOGS_ATHENA) || defined (LWLIB_WIDGETS_ATHENA)
152         else if (XtIsSubclass(widget, commandWidgetClass)) {
153                 Dimension bw = 0;
154                 Arg al[3];
155                 XtSetArg(al[0], XtNborderWidth, &bw);
156                 XtGetValues(widget, al, 1);
157
158 #ifndef LWLIB_DIALOGS_ATHENA3D
159                 if (bw == 0)
160                         /* Don't let buttons end up with 0 borderwidth, that's ugly...
161                            Yeah, all this should really be done through app-defaults files
162                            or fallback resources, but that's a whole different can of worms
163                            that I don't feel like opening right now.  Making Athena widgets
164                            not look like shit is just entirely too much work.
165                          */
166                 {
167                         XtSetArg(al[0], XtNborderWidth, 1);
168                         XtSetValues(widget, al, 1);
169                 }
170 #endif                          /* ! LWLIB_DIALOGS_ATHENA3D */
171
172                 lw_remove_accelerator_spec(val->value);
173                 XtSetArg(al[0], XtNlabel, val->value);
174                 XtSetArg(al[1], XtNsensitive, val->enabled);
175                 /* Force centered button text.  See above. */
176                 XtSetArg(al[2], XtNjustify, XtJustifyCenter);
177                 XtSetValues(widget, al, 3);
178
179                 XtRemoveAllCallbacks(widget, XtNcallback);
180                 XtAddCallback(widget, XtNcallback, xaw_generic_callback,
181                               instance);
182 #ifdef LWLIB_WIDGETS_ATHENA
183                 /* set the selected state */
184                 if (XtIsSubclass(widget, toggleWidgetClass)) {
185                         XtSetArg(al[0], XtNstate, val->selected);
186                         XtSetValues(widget, al, 1);
187                 }
188 #endif                          /* LWLIB_WIDGETS_ATHENA */
189         }
190 #endif                          /* LWLIB_DIALOGS_ATHENA */
191         /* Lastly update our global arg values. */
192         if (val->args && val->args->nargs)
193                 XtSetValues(widget, val->args->args, val->args->nargs);
194 }
195
196 void
197 xaw_update_one_value(widget_instance * instance, Widget widget,
198                      widget_value * val)
199 {
200 #ifdef LWLIB_WIDGETS_ATHENA
201         widget_value *old_wv;
202
203         /* copy the call_data slot into the "return" widget_value */
204         for (old_wv = instance->info->val->contents; old_wv;
205              old_wv = old_wv->next)
206                 if (!strcmp(val->name, old_wv->name)) {
207                         val->call_data = old_wv->call_data;
208                         break;
209                 }
210
211         if (XtIsSubclass(widget, toggleWidgetClass)) {
212                 Arg al[1];
213                 XtSetArg(al[0], XtNstate, &val->selected);
214                 XtGetValues(widget, al, 1);
215                 val->edited = True;
216         }
217 #ifndef NEED_MOTIF
218         else if (XtIsSubclass(widget, asciiTextWidgetClass)) {
219                 Arg al[2];
220                 String buf = 0;
221                 XtSetArg(al[0], XtNstring, &buf);
222                 XtGetValues(widget, al, 1);
223
224                 if (val->value) {
225                         free(val->value);
226                         val->value = 0;
227                 }
228                 /* I don't think this causes a leak. */
229                 if (buf)
230                         val->value = strdup(buf);
231                 val->edited = True;
232         }
233 #endif
234 #endif                          /* LWLIB_WIDGETS_ATHENA */
235 }
236
237 void xaw_destroy_instance(widget_instance * instance)
238 {
239 #ifdef LWLIB_DIALOGS_ATHENA
240         if (XtIsSubclass(instance->widget, dialogWidgetClass))
241                 /* Need to destroy the Shell too. */
242                 XtDestroyWidget(XtParent(instance->widget));
243         else
244 #endif
245                 XtDestroyWidget(instance->widget);
246 }
247
248 void xaw_popup_menu(Widget widget, XEvent * event)
249 {
250         /* An Athena menubar has not been implemented. */
251         return;
252 }
253
254 void xaw_pop_instance(widget_instance * instance, Boolean up)
255 {
256         Widget widget = instance->widget;
257
258         if (up) {
259 #ifdef LWLIB_DIALOGS_ATHENA
260                 if (XtIsSubclass(widget, dialogWidgetClass)) {
261                         /* For dialogs, we need to call XtPopup on the parent instead
262                            of calling XtManageChild on the widget.
263                            Also we need to hack the shell's WM_PROTOCOLS to get it to
264                            understand what the close box is supposed to do!!
265                          */
266                         Display *dpy = XtDisplay(widget);
267                         Widget shell = XtParent(widget);
268                         Atom props[2];
269                         int i = 0;
270                         props[i++] =
271                             XInternAtom(dpy, "WM_DELETE_WINDOW", False);
272                         XChangeProperty(dpy, XtWindow(shell),
273                                         XInternAtom(dpy, "WM_PROTOCOLS", False),
274                                         XA_ATOM, 32, PropModeAppend,
275                                         (unsigned char *)props, i);
276
277                         /* Center the widget in its parent.  Why isn't this kind of crap
278                            done automatically?  I thought toolkits were supposed to make
279                            life easier?
280                          */
281                         {
282                                 unsigned int x, y, w, h;
283                                 Widget topmost = instance->parent;
284                                 w = shell->core.width;
285                                 h = shell->core.height;
286                                 while (topmost->core.parent &&
287                                        XtIsRealized(topmost->core.parent) &&
288                                        /* HAVE_SESSION adds an unmapped parent widget that
289                                           we should ignore here. */
290                                        topmost->core.parent->core.
291                                        mapped_when_managed)
292                                         topmost = topmost->core.parent;
293                                 if (topmost->core.width < w)
294                                         x = topmost->core.x;
295                                 else
296                                         x = topmost->core.x +
297                                             ((topmost->core.width - w) / 2);
298                                 if (topmost->core.height < h)
299                                         y = topmost->core.y;
300                                 else
301                                         y = topmost->core.y +
302                                             ((topmost->core.height - h) / 2);
303                                 XtMoveWidget(shell, x, y);
304                         }
305
306                         /* Finally, pop it up. */
307                         XtPopup(shell, XtGrabNonexclusive);
308                 } else
309 #endif                          /* LWLIB_DIALOGS_ATHENA */
310                         XtManageChild(widget);
311         } else {
312 #ifdef LWLIB_DIALOGS_ATHENA
313                 if (XtIsSubclass(widget, dialogWidgetClass))
314                         XtUnmanageChild(XtParent(widget));
315                 else
316 #endif
317                         XtUnmanageChild(widget);
318         }
319 }
320 \f
321 #ifdef LWLIB_DIALOGS_ATHENA
322 /* Dialog boxes */
323
324 static char overrideTrans[] = "<Message>WM_PROTOCOLS: lwlib_delete_dialog()";
325 static XtActionProc wm_delete_window(Widget shell, XtPointer closure,
326                                      XtPointer call_data);
327 static XtActionsRec xaw_actions[] = {
328         {"lwlib_delete_dialog", (XtActionProc) wm_delete_window}
329 };
330 static Boolean actions_initted = False;
331
332 static Widget
333 make_dialog(const char *name, Widget parent, Boolean pop_up_p,
334             const char *shell_title, const char *icon_name,
335             Boolean text_input_slot,
336             Boolean radio_box, Boolean list,
337             int left_buttons, int right_buttons)
338 {
339         Arg av[20];
340         int ac = 0;
341         int i, bc;
342         char button_name[255];
343         Widget shell;
344         Widget dialog;
345         Widget button;
346         XtTranslations override;
347
348         if (!pop_up_p)
349                 abort();        /* not implemented */
350         if (text_input_slot)
351                 abort();        /* not implemented */
352         if (radio_box)
353                 abort();        /* not implemented */
354         if (list)
355                 abort();        /* not implemented */
356
357         if (!actions_initted) {
358                 XtAppContext app = XtWidgetToApplicationContext(parent);
359                 XtAppAddActions(app, xaw_actions,
360                                 sizeof(xaw_actions) / sizeof(xaw_actions[0]));
361                 actions_initted = True;
362         }
363
364         override = XtParseTranslationTable(overrideTrans);
365
366         ac = 0;
367         XtSetArg(av[ac], XtNtitle, shell_title);
368         ac++;
369         XtSetArg(av[ac], XtNallowShellResize, True);
370         ac++;
371         XtSetArg(av[ac], XtNtransientFor, parent);
372         ac++;
373         shell = XtCreatePopupShell("dialog", transientShellWidgetClass,
374                                    parent, av, ac);
375         XtOverrideTranslations(shell, override);
376
377         ac = 0;
378         dialog = XtCreateManagedWidget(name, dialogWidgetClass, shell, av, ac);
379
380         bc = 0;
381         button = 0;
382         for (i = 0; i < left_buttons; i++) {
383                 int sz;
384                 ac = 0;
385                 XtSetArg(av[ac], XtNfromHoriz, button);
386                 ac++;
387                 XtSetArg(av[ac], XtNleft, XtChainLeft);
388                 ac++;
389                 XtSetArg(av[ac], XtNright, XtChainLeft);
390                 ac++;
391                 XtSetArg(av[ac], XtNtop, XtChainBottom);
392                 ac++;
393                 XtSetArg(av[ac], XtNbottom, XtChainBottom);
394                 ac++;
395                 XtSetArg(av[ac], XtNresizable, True);
396                 ac++;
397                 sz = snprintf(button_name, sizeof(button_name), "button%d", ++bc);
398                 assert(sz >= 0 && (size_t)sz < sizeof(button_name));
399                 button = XtCreateManagedWidget(button_name, commandWidgetClass,
400                                                dialog, av, ac);
401         }
402         if (right_buttons) {
403                 /* Create a separator
404
405                    I want the separator to take up the slack between the buttons on
406                    the right and the buttons on the left (that is I want the buttons
407                    after the separator to be packed against the right edge of the
408                    window) but I can't seem to make it do it.  
409                  */
410                 ac = 0;
411                 XtSetArg(av[ac], XtNfromHoriz, button);
412                 ac++;
413 /*  XtSetArg (av [ac], XtNfromVert, XtNameToWidget (dialog, "label")); ac++; */
414                 XtSetArg(av[ac], XtNleft, XtChainLeft);
415                 ac++;
416                 XtSetArg(av[ac], XtNright, XtChainRight);
417                 ac++;
418                 XtSetArg(av[ac], XtNtop, XtChainBottom);
419                 ac++;
420                 XtSetArg(av[ac], XtNbottom, XtChainBottom);
421                 ac++;
422                 XtSetArg(av[ac], XtNlabel, "");
423                 ac++;
424                 XtSetArg(av[ac], XtNwidth, 30);
425                 ac++;           /* #### aaack!! */
426                 XtSetArg(av[ac], XtNborderWidth, 0);
427                 ac++;
428                 XtSetArg(av[ac], XtNshapeStyle, XmuShapeRectangle);
429                 ac++;
430                 XtSetArg(av[ac], XtNresizable, False);
431                 ac++;
432                 XtSetArg(av[ac], XtNsensitive, False);
433                 ac++;
434                 button = XtCreateManagedWidget("separator",
435                                                /* labelWidgetClass, */
436                                                /* This has to be Command to fake out
437                                                   the Dialog widget... */
438                                                commandWidgetClass,
439                                                dialog, av, ac);
440         }
441         for (i = 0; i < right_buttons; i++) {
442                 int sz;
443                 ac = 0;
444                 XtSetArg(av[ac], XtNfromHoriz, button);
445                 ac++;
446                 XtSetArg(av[ac], XtNleft, XtChainRight);
447                 ac++;
448                 XtSetArg(av[ac], XtNright, XtChainRight);
449                 ac++;
450                 XtSetArg(av[ac], XtNtop, XtChainBottom);
451                 ac++;
452                 XtSetArg(av[ac], XtNbottom, XtChainBottom);
453                 ac++;
454                 XtSetArg(av[ac], XtNresizable, True);
455                 ac++;
456                 sz = snprintf(button_name, sizeof(button_name), "button%d", ++bc);
457                 assert(sz >= 0 && (size_t)sz < sizeof(button_name));
458                 button = XtCreateManagedWidget(button_name, commandWidgetClass,
459                                                dialog, av, ac);
460         }
461
462         return dialog;
463 }
464
465 Widget xaw_create_dialog(widget_instance * instance)
466 {
467         char *name = instance->info->type;
468         Widget parent = instance->parent;
469         Widget widget;
470         Boolean pop_up_p = instance->pop_up_p;
471         const char *shell_name = 0;
472         const char *icon_name = 0;
473         Boolean text_input_slot = False;
474         Boolean radio_box = False;
475         Boolean list = False;
476         int total_buttons;
477         int left_buttons = 0;
478         int right_buttons = 1;
479
480         switch (name[0]) {
481         case 'E':
482         case 'e':
483                 icon_name = "dbox-error";
484                 shell_name = "Error";
485                 break;
486
487         case 'I':
488         case 'i':
489                 icon_name = "dbox-info";
490                 shell_name = "Information";
491                 break;
492
493         case 'L':
494         case 'l':
495                 list = True;
496                 icon_name = "dbox-question";
497                 shell_name = "Prompt";
498                 break;
499
500         case 'P':
501         case 'p':
502                 text_input_slot = True;
503                 icon_name = "dbox-question";
504                 shell_name = "Prompt";
505                 break;
506
507         case 'Q':
508         case 'q':
509                 icon_name = "dbox-question";
510                 shell_name = "Question";
511                 break;
512         default:
513                 break;
514         }
515
516         total_buttons = name[1] - '0';
517
518         if (name[3] == 'T' || name[3] == 't') {
519                 text_input_slot = False;
520                 radio_box = True;
521         } else if (name[3])
522                 right_buttons = name[4] - '0';
523
524         left_buttons = total_buttons - right_buttons;
525
526         widget = make_dialog(name, parent, pop_up_p,
527                              shell_name, icon_name, text_input_slot, radio_box,
528                              list, left_buttons, right_buttons);
529
530         return widget;
531 }
532 #endif                          /* LWLIB_DIALOGS_ATHENA */
533
534 static void
535 xaw_generic_callback(Widget widget, XtPointer closure, XtPointer call_data)
536 {
537         widget_instance *instance = (widget_instance *) closure;
538         Widget instance_widget;
539         LWLIB_ID id;
540         XtPointer user_data;
541 #ifdef LWLIB_WIDGETS_ATHENA
542         /* We want the selected status to change only when we decide it
543            should change.  Yuck but correct. */
544         if (XtIsSubclass(widget, toggleWidgetClass)) {
545                 Boolean check;
546                 Arg al[1];
547
548                 XtSetArg(al[0], XtNstate, &check);
549                 XtGetValues(widget, al, 1);
550
551                 XtSetArg(al[0], XtNstate, !check);
552                 XtSetValues(widget, al, 1);
553         }
554 #endif                          /* LWLIB_WIDGETS_ATHENA */
555         lw_internal_update_other_instances(widget, closure, call_data);
556
557         if (!instance)
558                 return;
559         if (widget->core.being_destroyed)
560                 return;
561
562         instance_widget = instance->widget;
563         if (!instance_widget)
564                 return;
565
566         id = instance->info->id;
567
568 #if 0
569         user_data = NULL;
570         {
571                 Arg al[1];
572                 XtSetArg(al[0], XtNuserData, &user_data);
573                 XtGetValues(widget, al, 1);
574         }
575 #else
576         /* Damn!  Athena doesn't give us a way to hang our own data on the
577            buttons, so we have to go find it...  I guess this assumes that
578            all instances of a button have the same call data. 
579
580            ... Which is a totally bogus assumption --andyp */
581         {
582                 widget_value *val = instance->info->val;
583                 /* If the widget is a buffer/gutter widget then we already have
584                    the one we are looking for, so don't try and descend the widget
585                    tree. */
586                 if (val->contents) {
587                         char *name = XtName(widget);
588                         val = val->contents;
589                         while (val) {
590                                 if (val->name && !strcmp(val->name, name))
591                                         break;
592                                 val = val->next;
593                         }
594                         if (!val)
595                                 abort();
596                 }
597                 user_data = val->call_data;
598         }
599 #endif
600
601         if (instance->info->selection_cb)
602                 instance->info->selection_cb(widget, id, user_data);
603 }
604
605 #ifdef LWLIB_DIALOGS_ATHENA
606
607 static XtActionProc
608 wm_delete_window(Widget shell, XtPointer closure, XtPointer call_data)
609 {
610         LWLIB_ID id;
611         Widget *kids = 0;
612         Widget widget;
613         Arg al[1];
614         if (!XtIsSubclass(shell, shellWidgetClass))
615                 abort();
616         XtSetArg(al[0], XtNchildren, &kids);
617         XtGetValues(shell, al, 1);
618         if (!kids || !*kids)
619                 abort();
620         widget = kids[0];
621         if (!XtIsSubclass(widget, dialogWidgetClass))
622                 abort();
623         id = lw_get_widget_id(widget);
624         if (!id)
625                 abort();
626
627         {
628                 widget_info *info = lw_get_widget_info(id);
629                 if (!info)
630                         abort();
631                 if (info->selection_cb)
632                         info->selection_cb(widget, id, (XtPointer) - 1);
633         }
634
635         lw_destroy_all_widgets(id);
636         return NULL;
637 }
638
639 #endif                          /* LWLIB_DIALOGS_ATHENA */
640 \f
641 /* Scrollbars */
642
643 #ifdef LWLIB_SCROLLBARS_ATHENA
644 static void
645 xaw_scrollbar_scroll(Widget widget, XtPointer closure, XtPointer call_data)
646 {
647         widget_instance *instance = (widget_instance *) closure;
648         LWLIB_ID id;
649         scroll_event event_data;
650
651         if (!instance || widget->core.being_destroyed)
652                 return;
653
654         id = instance->info->id;
655         event_data.slider_value = (int)call_data;
656         event_data.time = 0;
657
658         if ((int)call_data > 0)
659                 /* event_data.action = SCROLLBAR_PAGE_DOWN; */
660                 event_data.action = SCROLLBAR_LINE_DOWN;
661         else
662                 /* event_data.action = SCROLLBAR_PAGE_UP; */
663                 event_data.action = SCROLLBAR_LINE_UP;
664
665         if (instance->info->pre_activate_cb)
666                 instance->info->pre_activate_cb(widget, id,
667                                                 (XtPointer) & event_data);
668 }
669
670 static void
671 xaw_scrollbar_jump(Widget widget, XtPointer closure, XtPointer call_data)
672 {
673         widget_instance *instance = (widget_instance *) closure;
674         LWLIB_ID id;
675         scroll_event event_data;
676         scrollbar_values *val =
677             (scrollbar_values *) instance->info->val->scrollbar_data;
678         float percent;
679
680         if (!instance || widget->core.being_destroyed)
681                 return;
682
683         id = instance->info->id;
684
685         percent = *(float *)call_data;
686         event_data.slider_value =
687             (int)(percent * (float)(val->maximum - val->minimum)) +
688             val->minimum;
689
690         event_data.time = 0;
691         event_data.action = SCROLLBAR_DRAG;
692
693         if (instance->info->pre_activate_cb)
694                 instance->info->pre_activate_cb(widget, id,
695                                                 (XtPointer) & event_data);
696 }
697
698 static Widget xaw_create_scrollbar(widget_instance * instance, int vertical)
699 {
700         Arg av[10];
701         int ac = 0;
702
703         static XtCallbackRec jumpCallbacks[2] =
704             { {xaw_scrollbar_jump, NULL}, {NULL, NULL} };
705
706         static XtCallbackRec scrollCallbacks[2] =
707             { {xaw_scrollbar_scroll, NULL}, {NULL, NULL} };
708
709         jumpCallbacks[0].closure = scrollCallbacks[0].closure =
710             (XtPointer) instance;
711
712         /* #### This is tacked onto the with and height and completely
713            screws our geometry management.  We should probably make the
714            top-level aware of this so that people could have a border but so
715            few people use the Athena scrollbar now that it really isn't
716            worth the effort, at least not at the moment. */
717         XtSetArg(av[ac], XtNborderWidth, 0);
718         ac++;
719         XtSetArg(av[ac], XtNorientation,
720                  vertical ? XtorientVertical : XtorientHorizontal);
721         ac++;
722         XtSetArg(av[ac], "jumpProc", jumpCallbacks);
723         ac++;
724         XtSetArg(av[ac], "scrollProc", scrollCallbacks);
725         ac++;
726
727         return XtCreateWidget(instance->info->name, scrollbarWidgetClass,
728                               instance->parent, av, ac);
729 }
730
731 static Widget xaw_create_vertical_scrollbar(widget_instance * instance)
732 {
733         return xaw_create_scrollbar(instance, 1);
734 }
735
736 static Widget xaw_create_horizontal_scrollbar(widget_instance * instance)
737 {
738         return xaw_create_scrollbar(instance, 0);
739 }
740 #endif                          /* LWLIB_SCROLLBARS_ATHENA */
741
742 #ifdef LWLIB_WIDGETS_ATHENA
743 /* glyph widgets */
744 static Widget xaw_create_button(widget_instance * instance)
745 {
746         Arg al[20];
747         int ac = 0;
748         Widget button = 0;
749         widget_value *val = instance->info->val;
750
751         XtSetArg(al[ac], XtNsensitive, val->enabled);
752         ac++;
753         XtSetArg(al[ac], XtNmappedWhenManaged, FALSE);
754         ac++;
755         XtSetArg(al[ac], XtNjustify, XtJustifyCenter);
756         ac++;
757         /* The highlight doesn't appear to be dynamically set which makes it
758            look ugly.  I think this may be a LessTif bug but for now we just
759            get rid of it. */
760         XtSetArg(al[ac], XtNhighlightThickness, (Dimension) 0);
761         ac++;
762
763         /* add any args the user supplied for creation time */
764         lw_add_value_args_to_args(val, al, &ac);
765
766         if (!val->call_data)
767                 button = XtCreateManagedWidget(val->name, labelWidgetClass,
768                                                instance->parent, al, ac);
769
770         else {
771                 if (val->type == TOGGLE_TYPE || val->type == RADIO_TYPE) {
772                         XtSetArg(al[ac], XtNstate, val->selected);
773                         ac++;
774                         button = XtCreateManagedWidget
775                             (val->name,
776                              val->type ==
777                              TOGGLE_TYPE ? checkboxWidgetClass :
778                              radioWidgetClass, instance->parent, al, ac);
779                 } else {
780                         button =
781                             XtCreateManagedWidget(val->name, commandWidgetClass,
782                                                   instance->parent, al, ac);
783                 }
784                 XtRemoveAllCallbacks(button, XtNcallback);
785                 XtAddCallback(button, XtNcallback, xaw_generic_callback,
786                               (XtPointer) instance);
787         }
788
789         XtManageChild(button);
790
791         return button;
792 }
793
794 static Widget xaw_create_label_field(widget_instance * instance)
795 {
796         return xaw_create_label(instance->parent, instance->info->val);
797 }
798
799 Widget xaw_create_label(Widget parent, widget_value * val)
800 {
801         Arg al[20];
802         int ac = 0;
803         Widget label = 0;
804
805         XtSetArg(al[ac], XtNsensitive, val->enabled);
806         ac++;
807         XtSetArg(al[ac], XtNmappedWhenManaged, FALSE);
808         ac++;
809         XtSetArg(al[ac], XtNjustify, XtJustifyCenter);
810         ac++;
811
812         /* add any args the user supplied for creation time */
813         lw_add_value_args_to_args(val, al, &ac);
814
815         label = XtCreateManagedWidget(val->name, labelWidgetClass,
816                                       parent, al, ac);
817
818         /* Do it again for arguments that have no effect until the widget is realized. */
819         ac = 0;
820         lw_add_value_args_to_args(val, al, &ac);
821         if (ac > 20)
822                 abort();        /* #### need assert macro in lwlib */
823         XtSetValues(label, al, ac);
824
825         return label;
826 }
827
828 static Widget xaw_create_progress(widget_instance * instance)
829 {
830         Arg al[20];
831         int ac = 0;
832         Widget scale = 0;
833         widget_value *val = instance->info->val;
834 #if 0                           /* This looks too awful, although more correct. */
835         if (!val->call_data) {
836                 XtSetArg(al[ac], XtNsensitive, False);
837                 ac++;
838         } else {
839                 XtSetArg(al[ac], XtNsensitive, val->enabled);
840                 ac++;
841         }
842 #else
843         XtSetArg(al[ac], XtNsensitive, True);
844         ac++;
845 #endif
846
847         XtSetArg(al[ac], XtNmappedWhenManaged, FALSE);
848         ac++;
849         XtSetArg(al[ac], XtNorientation, XtorientHorizontal);
850         ac++;
851         XtSetArg(al[ac], XtNhighlightThickness, (Dimension) 0);
852         ac++;
853         XtSetArg(al[ac], XtNntics, (Cardinal) 10);
854         ac++;
855
856         /* add any args the user supplied for creation time */
857         lw_add_value_args_to_args(val, al, &ac);
858
859         scale = XtCreateManagedWidget(val->name, gaugeWidgetClass,
860                                       instance->parent, al, ac);
861         /* add the callback */
862         if (val->call_data)
863                 XtAddCallback(scale, XtNgetValue, xaw_generic_callback,
864                               (XtPointer) instance);
865
866         XtManageChild(scale);
867
868         return scale;
869 }
870
871 #if defined(LWLIB_WIDGETS_ATHENA)
872 #define TEXT_BUFFER_SIZE 128
873 static Widget xaw_create_text_field(widget_instance * instance)
874 {
875         Arg al[20];
876         int ac = 0;
877         Widget text = 0;
878         widget_value *val = instance->info->val;
879
880         XtSetArg(al[ac], XtNsensitive, val->enabled);
881         ac++;
882         XtSetArg(al[ac], XtNmappedWhenManaged, FALSE);
883         ac++;
884         XtSetArg(al[ac], XtNhighlightThickness, (Dimension) 0);
885         ac++;
886         XtSetArg(al[ac], XtNtype, XawAsciiString);
887         ac++;
888         XtSetArg(al[ac], XtNeditType, XawtextEdit);
889         ac++;
890         XtSetArg(al[ac], XtNuseStringInPlace, False);
891         ac++;
892 #if 0
893         XtSetArg(al[ac], XtNlength, TEXT_BUFFER_SIZE);
894         ac++;
895 #endif
896         if (val->value) {
897                 XtSetArg(al[ac], XtNstring, val->value);
898                 ac++;
899         }
900
901         /* add any args the user supplied for creation time */
902         lw_add_value_args_to_args(val, al, &ac);
903
904         text = XtCreateManagedWidget(val->name, asciiTextWidgetClass,
905                                      instance->parent, al, ac);
906
907         /* add the callback */
908         if (val->call_data)
909                 XtAddCallback(text, XtNgetValue, xaw_generic_callback,
910                               (XtPointer) instance);
911
912         XtManageChild(text);
913
914         return text;
915 }
916 #endif
917
918 #endif                          /* LWLIB_WIDGETS_ATHENA */
919
920 const widget_creation_entry xaw_creation_table[] = {
921 #ifdef LWLIB_SCROLLBARS_ATHENA
922         {"vertical-scrollbar", xaw_create_vertical_scrollbar},
923         {"horizontal-scrollbar", xaw_create_horizontal_scrollbar},
924 #endif
925 #ifdef LWLIB_WIDGETS_ATHENA
926         {"button", xaw_create_button},
927         {"label", xaw_create_label_field},
928         {"text-field", xaw_create_text_field},
929         {"progress", xaw_create_progress},
930 #endif
931         {NULL, NULL}
932 };