Mark variables set but unused.
[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 = NULL;
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 && 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                 }
595                 if (val)
596                         user_data = val->call_data;
597                 else
598                         abort();
599         }
600 #endif
601
602         if (instance->info->selection_cb && user_data)
603                 instance->info->selection_cb(widget, id, user_data);
604 }
605
606 #ifdef LWLIB_DIALOGS_ATHENA
607
608 static XtActionProc
609 wm_delete_window(Widget shell, XtPointer closure, XtPointer call_data)
610 {
611         LWLIB_ID id;
612         Widget *kids = 0;
613         Widget widget;
614         Arg al[1];
615         if (!XtIsSubclass(shell, shellWidgetClass))
616                 abort();
617         XtSetArg(al[0], XtNchildren, &kids);
618         XtGetValues(shell, al, 1);
619         if (!kids || !*kids)
620                 abort();
621         else {
622                 widget = kids[0];
623                 if (!XtIsSubclass(widget, dialogWidgetClass))
624                         abort();
625                 id = lw_get_widget_id(widget);
626                 if (!id)
627                         abort();
628                 else {
629                         widget_info *info = lw_get_widget_info(id);
630                         if (!info)
631                                 abort();
632                         else if (info->selection_cb)
633                                 info->selection_cb(widget, id, (XtPointer) - 1);
634                 }
635
636                 lw_destroy_all_widgets(id);
637         }
638         return NULL;
639 }
640
641 #endif                          /* LWLIB_DIALOGS_ATHENA */
642 \f
643 /* Scrollbars */
644
645 #ifdef LWLIB_SCROLLBARS_ATHENA
646 static void
647 xaw_scrollbar_scroll(Widget widget, XtPointer closure, XtPointer call_data)
648 {
649         widget_instance *instance = (widget_instance *) closure;
650         LWLIB_ID id;
651         scroll_event event_data;
652
653         if (!instance || widget->core.being_destroyed)
654                 return;
655
656         id = instance->info->id;
657         event_data.slider_value = (int)call_data;
658         event_data.time = 0;
659
660         if ((int)call_data > 0)
661                 /* event_data.action = SCROLLBAR_PAGE_DOWN; */
662                 event_data.action = SCROLLBAR_LINE_DOWN;
663         else
664                 /* event_data.action = SCROLLBAR_PAGE_UP; */
665                 event_data.action = SCROLLBAR_LINE_UP;
666
667         if (instance->info->pre_activate_cb)
668                 instance->info->pre_activate_cb(widget, id,
669                                                 (XtPointer) & event_data);
670 }
671
672 static void
673 xaw_scrollbar_jump(Widget widget, XtPointer closure, XtPointer call_data)
674 {
675         widget_instance *instance = (widget_instance *) closure;
676         LWLIB_ID id;
677         scroll_event event_data;
678         scrollbar_values *val =
679             (scrollbar_values *) instance->info->val->scrollbar_data;
680         float percent;
681
682         if (!instance || widget->core.being_destroyed)
683                 return;
684
685         id = instance->info->id;
686
687         percent = *(float *)call_data;
688         event_data.slider_value =
689             (int)(percent * (float)(val->maximum - val->minimum)) +
690             val->minimum;
691
692         event_data.time = 0;
693         event_data.action = SCROLLBAR_DRAG;
694
695         if (instance->info->pre_activate_cb)
696                 instance->info->pre_activate_cb(widget, id,
697                                                 (XtPointer) & event_data);
698 }
699
700 static Widget xaw_create_scrollbar(widget_instance * instance, int vertical)
701 {
702         Arg av[10];
703         int ac = 0;
704
705         static XtCallbackRec jumpCallbacks[2] =
706             { {xaw_scrollbar_jump, NULL}, {NULL, NULL} };
707
708         static XtCallbackRec scrollCallbacks[2] =
709             { {xaw_scrollbar_scroll, NULL}, {NULL, NULL} };
710
711         jumpCallbacks[0].closure = scrollCallbacks[0].closure =
712             (XtPointer) instance;
713
714         /* #### This is tacked onto the with and height and completely
715            screws our geometry management.  We should probably make the
716            top-level aware of this so that people could have a border but so
717            few people use the Athena scrollbar now that it really isn't
718            worth the effort, at least not at the moment. */
719         XtSetArg(av[ac], XtNborderWidth, 0);
720         ac++;
721         XtSetArg(av[ac], XtNorientation,
722                  vertical ? XtorientVertical : XtorientHorizontal);
723         ac++;
724         XtSetArg(av[ac], "jumpProc", jumpCallbacks);
725         ac++;
726         XtSetArg(av[ac], "scrollProc", scrollCallbacks);
727         ac++;
728
729         return XtCreateWidget(instance->info->name, scrollbarWidgetClass,
730                               instance->parent, av, ac);
731 }
732
733 static Widget xaw_create_vertical_scrollbar(widget_instance * instance)
734 {
735         return xaw_create_scrollbar(instance, 1);
736 }
737
738 static Widget xaw_create_horizontal_scrollbar(widget_instance * instance)
739 {
740         return xaw_create_scrollbar(instance, 0);
741 }
742 #endif                          /* LWLIB_SCROLLBARS_ATHENA */
743
744 #ifdef LWLIB_WIDGETS_ATHENA
745 /* glyph widgets */
746 static Widget xaw_create_button(widget_instance * instance)
747 {
748         Arg al[20];
749         int ac = 0;
750         Widget button = 0;
751         widget_value *val = instance->info->val;
752
753         XtSetArg(al[ac], XtNsensitive, val->enabled);
754         ac++;
755         XtSetArg(al[ac], XtNmappedWhenManaged, FALSE);
756         ac++;
757         XtSetArg(al[ac], XtNjustify, XtJustifyCenter);
758         ac++;
759         /* The highlight doesn't appear to be dynamically set which makes it
760            look ugly.  I think this may be a LessTif bug but for now we just
761            get rid of it. */
762         XtSetArg(al[ac], XtNhighlightThickness, (Dimension) 0);
763         ac++;
764
765         /* add any args the user supplied for creation time */
766         lw_add_value_args_to_args(val, al, &ac);
767
768         if (!val->call_data)
769                 button = XtCreateManagedWidget(val->name, labelWidgetClass,
770                                                instance->parent, al, ac);
771
772         else {
773                 if (val->type == TOGGLE_TYPE || val->type == RADIO_TYPE) {
774                         XtSetArg(al[ac], XtNstate, val->selected);
775                         ac++;
776                         button = XtCreateManagedWidget
777                             (val->name,
778                              val->type ==
779                              TOGGLE_TYPE ? checkboxWidgetClass :
780                              radioWidgetClass, instance->parent, al, ac);
781                 } else {
782                         button =
783                             XtCreateManagedWidget(val->name, commandWidgetClass,
784                                                   instance->parent, al, ac);
785                 }
786                 XtRemoveAllCallbacks(button, XtNcallback);
787                 XtAddCallback(button, XtNcallback, xaw_generic_callback,
788                               (XtPointer) instance);
789         }
790
791         XtManageChild(button);
792
793         return button;
794 }
795
796 static Widget xaw_create_label_field(widget_instance * instance)
797 {
798         return xaw_create_label(instance->parent, instance->info->val);
799 }
800
801 Widget xaw_create_label(Widget parent, widget_value * val)
802 {
803         Arg al[20];
804         int ac = 0;
805         Widget label = 0;
806
807         XtSetArg(al[ac], XtNsensitive, val->enabled);
808         ac++;
809         XtSetArg(al[ac], XtNmappedWhenManaged, FALSE);
810         ac++;
811         XtSetArg(al[ac], XtNjustify, XtJustifyCenter);
812         ac++;
813
814         /* add any args the user supplied for creation time */
815         lw_add_value_args_to_args(val, al, &ac);
816
817         label = XtCreateManagedWidget(val->name, labelWidgetClass,
818                                       parent, al, ac);
819
820         /* Do it again for arguments that have no effect until the widget is realized. */
821         ac = 0;
822         lw_add_value_args_to_args(val, al, &ac);
823         if (ac > 20)
824                 abort();        /* #### need assert macro in lwlib */
825         XtSetValues(label, al, ac);
826
827         return label;
828 }
829
830 static Widget xaw_create_progress(widget_instance * instance)
831 {
832         Arg al[20];
833         int ac = 0;
834         Widget scale = 0;
835         widget_value *val = instance->info->val;
836 #if 0                           /* This looks too awful, although more correct. */
837         if (!val->call_data) {
838                 XtSetArg(al[ac], XtNsensitive, False);
839                 ac++;
840         } else {
841                 XtSetArg(al[ac], XtNsensitive, val->enabled);
842                 ac++;
843         }
844 #else
845         XtSetArg(al[ac], XtNsensitive, True);
846         ac++;
847 #endif
848
849         XtSetArg(al[ac], XtNmappedWhenManaged, FALSE);
850         ac++;
851         XtSetArg(al[ac], XtNorientation, XtorientHorizontal);
852         ac++;
853         XtSetArg(al[ac], XtNhighlightThickness, (Dimension) 0);
854         ac++;
855         XtSetArg(al[ac], XtNntics, (Cardinal) 10);
856         ac++;
857
858         /* add any args the user supplied for creation time */
859         lw_add_value_args_to_args(val, al, &ac);
860
861         scale = XtCreateManagedWidget(val->name, gaugeWidgetClass,
862                                       instance->parent, al, ac);
863         /* add the callback */
864         if (val->call_data)
865                 XtAddCallback(scale, XtNgetValue, xaw_generic_callback,
866                               (XtPointer) instance);
867
868         XtManageChild(scale);
869
870         return scale;
871 }
872
873 #if defined(LWLIB_WIDGETS_ATHENA)
874 #define TEXT_BUFFER_SIZE 128
875 static Widget xaw_create_text_field(widget_instance * instance)
876 {
877         Arg al[20];
878         int ac = 0;
879         Widget text = 0;
880         widget_value *val = instance->info->val;
881
882         XtSetArg(al[ac], XtNsensitive, val->enabled);
883         ac++;
884         XtSetArg(al[ac], XtNmappedWhenManaged, FALSE);
885         ac++;
886         XtSetArg(al[ac], XtNhighlightThickness, (Dimension) 0);
887         ac++;
888         XtSetArg(al[ac], XtNtype, XawAsciiString);
889         ac++;
890         XtSetArg(al[ac], XtNeditType, XawtextEdit);
891         ac++;
892         XtSetArg(al[ac], XtNuseStringInPlace, False);
893         ac++;
894 #if 0
895         XtSetArg(al[ac], XtNlength, TEXT_BUFFER_SIZE);
896         ac++;
897 #endif
898         if (val->value) {
899                 XtSetArg(al[ac], XtNstring, val->value);
900                 ac++;
901         }
902
903         /* add any args the user supplied for creation time */
904         lw_add_value_args_to_args(val, al, &ac);
905
906         text = XtCreateManagedWidget(val->name, asciiTextWidgetClass,
907                                      instance->parent, al, ac);
908
909         /* add the callback */
910         if (val->call_data)
911                 XtAddCallback(text, XtNgetValue, xaw_generic_callback,
912                               (XtPointer) instance);
913
914         XtManageChild(text);
915
916         return text;
917 }
918 #endif
919
920 #endif                          /* LWLIB_WIDGETS_ATHENA */
921
922 const widget_creation_entry xaw_creation_table[] = {
923 #ifdef LWLIB_SCROLLBARS_ATHENA
924         {"vertical-scrollbar", xaw_create_vertical_scrollbar},
925         {"horizontal-scrollbar", xaw_create_horizontal_scrollbar},
926 #endif
927 #ifdef LWLIB_WIDGETS_ATHENA
928         {"button", xaw_create_button},
929         {"label", xaw_create_label_field},
930         {"text-field", xaw_create_text_field},
931         {"progress", xaw_create_progress},
932 #endif
933         {NULL, NULL}
934 };