Misc coverity fixes (lost CID)
[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                 ac = 0;
384                 XtSetArg(av[ac], XtNfromHoriz, button);
385                 ac++;
386                 XtSetArg(av[ac], XtNleft, XtChainLeft);
387                 ac++;
388                 XtSetArg(av[ac], XtNright, XtChainLeft);
389                 ac++;
390                 XtSetArg(av[ac], XtNtop, XtChainBottom);
391                 ac++;
392                 XtSetArg(av[ac], XtNbottom, XtChainBottom);
393                 ac++;
394                 XtSetArg(av[ac], XtNresizable, True);
395                 ac++;
396                 sprintf(button_name, "button%d", ++bc);
397                 button = XtCreateManagedWidget(button_name, commandWidgetClass,
398                                                dialog, av, ac);
399         }
400         if (right_buttons) {
401                 /* Create a separator
402
403                    I want the separator to take up the slack between the buttons on
404                    the right and the buttons on the left (that is I want the buttons
405                    after the separator to be packed against the right edge of the
406                    window) but I can't seem to make it do it.  
407                  */
408                 ac = 0;
409                 XtSetArg(av[ac], XtNfromHoriz, button);
410                 ac++;
411 /*  XtSetArg (av [ac], XtNfromVert, XtNameToWidget (dialog, "label")); ac++; */
412                 XtSetArg(av[ac], XtNleft, XtChainLeft);
413                 ac++;
414                 XtSetArg(av[ac], XtNright, XtChainRight);
415                 ac++;
416                 XtSetArg(av[ac], XtNtop, XtChainBottom);
417                 ac++;
418                 XtSetArg(av[ac], XtNbottom, XtChainBottom);
419                 ac++;
420                 XtSetArg(av[ac], XtNlabel, "");
421                 ac++;
422                 XtSetArg(av[ac], XtNwidth, 30);
423                 ac++;           /* #### aaack!! */
424                 XtSetArg(av[ac], XtNborderWidth, 0);
425                 ac++;
426                 XtSetArg(av[ac], XtNshapeStyle, XmuShapeRectangle);
427                 ac++;
428                 XtSetArg(av[ac], XtNresizable, False);
429                 ac++;
430                 XtSetArg(av[ac], XtNsensitive, False);
431                 ac++;
432                 button = XtCreateManagedWidget("separator",
433                                                /* labelWidgetClass, */
434                                                /* This has to be Command to fake out
435                                                   the Dialog widget... */
436                                                commandWidgetClass,
437                                                dialog, av, ac);
438         }
439         for (i = 0; i < right_buttons; i++) {
440                 ac = 0;
441                 XtSetArg(av[ac], XtNfromHoriz, button);
442                 ac++;
443                 XtSetArg(av[ac], XtNleft, XtChainRight);
444                 ac++;
445                 XtSetArg(av[ac], XtNright, XtChainRight);
446                 ac++;
447                 XtSetArg(av[ac], XtNtop, XtChainBottom);
448                 ac++;
449                 XtSetArg(av[ac], XtNbottom, XtChainBottom);
450                 ac++;
451                 XtSetArg(av[ac], XtNresizable, True);
452                 ac++;
453                 sprintf(button_name, "button%d", ++bc);
454                 button = XtCreateManagedWidget(button_name, commandWidgetClass,
455                                                dialog, av, ac);
456         }
457
458         return dialog;
459 }
460
461 Widget xaw_create_dialog(widget_instance * instance)
462 {
463         char *name = instance->info->type;
464         Widget parent = instance->parent;
465         Widget widget;
466         Boolean pop_up_p = instance->pop_up_p;
467         const char *shell_name = 0;
468         const char *icon_name = 0;
469         Boolean text_input_slot = False;
470         Boolean radio_box = False;
471         Boolean list = False;
472         int total_buttons;
473         int left_buttons = 0;
474         int right_buttons = 1;
475
476         switch (name[0]) {
477         case 'E':
478         case 'e':
479                 icon_name = "dbox-error";
480                 shell_name = "Error";
481                 break;
482
483         case 'I':
484         case 'i':
485                 icon_name = "dbox-info";
486                 shell_name = "Information";
487                 break;
488
489         case 'L':
490         case 'l':
491                 list = True;
492                 icon_name = "dbox-question";
493                 shell_name = "Prompt";
494                 break;
495
496         case 'P':
497         case 'p':
498                 text_input_slot = True;
499                 icon_name = "dbox-question";
500                 shell_name = "Prompt";
501                 break;
502
503         case 'Q':
504         case 'q':
505                 icon_name = "dbox-question";
506                 shell_name = "Question";
507                 break;
508         default:
509                 break;
510         }
511
512         total_buttons = name[1] - '0';
513
514         if (name[3] == 'T' || name[3] == 't') {
515                 text_input_slot = False;
516                 radio_box = True;
517         } else if (name[3])
518                 right_buttons = name[4] - '0';
519
520         left_buttons = total_buttons - right_buttons;
521
522         widget = make_dialog(name, parent, pop_up_p,
523                              shell_name, icon_name, text_input_slot, radio_box,
524                              list, left_buttons, right_buttons);
525
526         return widget;
527 }
528 #endif                          /* LWLIB_DIALOGS_ATHENA */
529
530 static void
531 xaw_generic_callback(Widget widget, XtPointer closure, XtPointer call_data)
532 {
533         widget_instance *instance = (widget_instance *) closure;
534         Widget instance_widget;
535         LWLIB_ID id;
536         XtPointer user_data;
537 #ifdef LWLIB_WIDGETS_ATHENA
538         /* We want the selected status to change only when we decide it
539            should change.  Yuck but correct. */
540         if (XtIsSubclass(widget, toggleWidgetClass)) {
541                 Boolean check;
542                 Arg al[1];
543
544                 XtSetArg(al[0], XtNstate, &check);
545                 XtGetValues(widget, al, 1);
546
547                 XtSetArg(al[0], XtNstate, !check);
548                 XtSetValues(widget, al, 1);
549         }
550 #endif                          /* LWLIB_WIDGETS_ATHENA */
551         lw_internal_update_other_instances(widget, closure, call_data);
552
553         if (!instance)
554                 return;
555         if (widget->core.being_destroyed)
556                 return;
557
558         instance_widget = instance->widget;
559         if (!instance_widget)
560                 return;
561
562         id = instance->info->id;
563
564 #if 0
565         user_data = NULL;
566         {
567                 Arg al[1];
568                 XtSetArg(al[0], XtNuserData, &user_data);
569                 XtGetValues(widget, al, 1);
570         }
571 #else
572         /* Damn!  Athena doesn't give us a way to hang our own data on the
573            buttons, so we have to go find it...  I guess this assumes that
574            all instances of a button have the same call data. 
575
576            ... Which is a totally bogus assumption --andyp */
577         {
578                 widget_value *val = instance->info->val;
579                 /* If the widget is a buffer/gutter widget then we already have
580                    the one we are looking for, so don't try and descend the widget
581                    tree. */
582                 if (val->contents) {
583                         char *name = XtName(widget);
584                         val = val->contents;
585                         while (val) {
586                                 if (val->name && !strcmp(val->name, name))
587                                         break;
588                                 val = val->next;
589                         }
590                         if (!val)
591                                 abort();
592                 }
593                 user_data = val->call_data;
594         }
595 #endif
596
597         if (instance->info->selection_cb)
598                 instance->info->selection_cb(widget, id, user_data);
599 }
600
601 #ifdef LWLIB_DIALOGS_ATHENA
602
603 static XtActionProc
604 wm_delete_window(Widget shell, XtPointer closure, XtPointer call_data)
605 {
606         LWLIB_ID id;
607         Widget *kids = 0;
608         Widget widget;
609         Arg al[1];
610         if (!XtIsSubclass(shell, shellWidgetClass))
611                 abort();
612         XtSetArg(al[0], XtNchildren, &kids);
613         XtGetValues(shell, al, 1);
614         if (!kids || !*kids)
615                 abort();
616         widget = kids[0];
617         if (!XtIsSubclass(widget, dialogWidgetClass))
618                 abort();
619         id = lw_get_widget_id(widget);
620         if (!id)
621                 abort();
622
623         {
624                 widget_info *info = lw_get_widget_info(id);
625                 if (!info)
626                         abort();
627                 if (info->selection_cb)
628                         info->selection_cb(widget, id, (XtPointer) - 1);
629         }
630
631         lw_destroy_all_widgets(id);
632         return NULL;
633 }
634
635 #endif                          /* LWLIB_DIALOGS_ATHENA */
636 \f
637 /* Scrollbars */
638
639 #ifdef LWLIB_SCROLLBARS_ATHENA
640 static void
641 xaw_scrollbar_scroll(Widget widget, XtPointer closure, XtPointer call_data)
642 {
643         widget_instance *instance = (widget_instance *) closure;
644         LWLIB_ID id;
645         scroll_event event_data;
646
647         if (!instance || widget->core.being_destroyed)
648                 return;
649
650         id = instance->info->id;
651         event_data.slider_value = (int)call_data;
652         event_data.time = 0;
653
654         if ((int)call_data > 0)
655                 /* event_data.action = SCROLLBAR_PAGE_DOWN; */
656                 event_data.action = SCROLLBAR_LINE_DOWN;
657         else
658                 /* event_data.action = SCROLLBAR_PAGE_UP; */
659                 event_data.action = SCROLLBAR_LINE_UP;
660
661         if (instance->info->pre_activate_cb)
662                 instance->info->pre_activate_cb(widget, id,
663                                                 (XtPointer) & event_data);
664 }
665
666 static void
667 xaw_scrollbar_jump(Widget widget, XtPointer closure, XtPointer call_data)
668 {
669         widget_instance *instance = (widget_instance *) closure;
670         LWLIB_ID id;
671         scroll_event event_data;
672         scrollbar_values *val =
673             (scrollbar_values *) instance->info->val->scrollbar_data;
674         float percent;
675
676         if (!instance || widget->core.being_destroyed)
677                 return;
678
679         id = instance->info->id;
680
681         percent = *(float *)call_data;
682         event_data.slider_value =
683             (int)(percent * (float)(val->maximum - val->minimum)) +
684             val->minimum;
685
686         event_data.time = 0;
687         event_data.action = SCROLLBAR_DRAG;
688
689         if (instance->info->pre_activate_cb)
690                 instance->info->pre_activate_cb(widget, id,
691                                                 (XtPointer) & event_data);
692 }
693
694 static Widget xaw_create_scrollbar(widget_instance * instance, int vertical)
695 {
696         Arg av[10];
697         int ac = 0;
698
699         static XtCallbackRec jumpCallbacks[2] =
700             { {xaw_scrollbar_jump, NULL}, {NULL, NULL} };
701
702         static XtCallbackRec scrollCallbacks[2] =
703             { {xaw_scrollbar_scroll, NULL}, {NULL, NULL} };
704
705         jumpCallbacks[0].closure = scrollCallbacks[0].closure =
706             (XtPointer) instance;
707
708         /* #### This is tacked onto the with and height and completely
709            screws our geometry management.  We should probably make the
710            top-level aware of this so that people could have a border but so
711            few people use the Athena scrollbar now that it really isn't
712            worth the effort, at least not at the moment. */
713         XtSetArg(av[ac], XtNborderWidth, 0);
714         ac++;
715         XtSetArg(av[ac], XtNorientation,
716                  vertical ? XtorientVertical : XtorientHorizontal);
717         ac++;
718         XtSetArg(av[ac], "jumpProc", jumpCallbacks);
719         ac++;
720         XtSetArg(av[ac], "scrollProc", scrollCallbacks);
721         ac++;
722
723         return XtCreateWidget(instance->info->name, scrollbarWidgetClass,
724                               instance->parent, av, ac);
725 }
726
727 static Widget xaw_create_vertical_scrollbar(widget_instance * instance)
728 {
729         return xaw_create_scrollbar(instance, 1);
730 }
731
732 static Widget xaw_create_horizontal_scrollbar(widget_instance * instance)
733 {
734         return xaw_create_scrollbar(instance, 0);
735 }
736 #endif                          /* LWLIB_SCROLLBARS_ATHENA */
737
738 #ifdef LWLIB_WIDGETS_ATHENA
739 /* glyph widgets */
740 static Widget xaw_create_button(widget_instance * instance)
741 {
742         Arg al[20];
743         int ac = 0;
744         Widget button = 0;
745         widget_value *val = instance->info->val;
746
747         XtSetArg(al[ac], XtNsensitive, val->enabled);
748         ac++;
749         XtSetArg(al[ac], XtNmappedWhenManaged, FALSE);
750         ac++;
751         XtSetArg(al[ac], XtNjustify, XtJustifyCenter);
752         ac++;
753         /* The highlight doesn't appear to be dynamically set which makes it
754            look ugly.  I think this may be a LessTif bug but for now we just
755            get rid of it. */
756         XtSetArg(al[ac], XtNhighlightThickness, (Dimension) 0);
757         ac++;
758
759         /* add any args the user supplied for creation time */
760         lw_add_value_args_to_args(val, al, &ac);
761
762         if (!val->call_data)
763                 button = XtCreateManagedWidget(val->name, labelWidgetClass,
764                                                instance->parent, al, ac);
765
766         else {
767                 if (val->type == TOGGLE_TYPE || val->type == RADIO_TYPE) {
768                         XtSetArg(al[ac], XtNstate, val->selected);
769                         ac++;
770                         button = XtCreateManagedWidget
771                             (val->name,
772                              val->type ==
773                              TOGGLE_TYPE ? checkboxWidgetClass :
774                              radioWidgetClass, instance->parent, al, ac);
775                 } else {
776                         button =
777                             XtCreateManagedWidget(val->name, commandWidgetClass,
778                                                   instance->parent, al, ac);
779                 }
780                 XtRemoveAllCallbacks(button, XtNcallback);
781                 XtAddCallback(button, XtNcallback, xaw_generic_callback,
782                               (XtPointer) instance);
783         }
784
785         XtManageChild(button);
786
787         return button;
788 }
789
790 static Widget xaw_create_label_field(widget_instance * instance)
791 {
792         return xaw_create_label(instance->parent, instance->info->val);
793 }
794
795 Widget xaw_create_label(Widget parent, widget_value * val)
796 {
797         Arg al[20];
798         int ac = 0;
799         Widget label = 0;
800
801         XtSetArg(al[ac], XtNsensitive, val->enabled);
802         ac++;
803         XtSetArg(al[ac], XtNmappedWhenManaged, FALSE);
804         ac++;
805         XtSetArg(al[ac], XtNjustify, XtJustifyCenter);
806         ac++;
807
808         /* add any args the user supplied for creation time */
809         lw_add_value_args_to_args(val, al, &ac);
810
811         label = XtCreateManagedWidget(val->name, labelWidgetClass,
812                                       parent, al, ac);
813
814         /* Do it again for arguments that have no effect until the widget is realized. */
815         ac = 0;
816         lw_add_value_args_to_args(val, al, &ac);
817         if (ac > 20)
818                 abort();        /* #### need assert macro in lwlib */
819         XtSetValues(label, al, ac);
820
821         return label;
822 }
823
824 static Widget xaw_create_progress(widget_instance * instance)
825 {
826         Arg al[20];
827         int ac = 0;
828         Widget scale = 0;
829         widget_value *val = instance->info->val;
830 #if 0                           /* This looks too awful, although more correct. */
831         if (!val->call_data) {
832                 XtSetArg(al[ac], XtNsensitive, False);
833                 ac++;
834         } else {
835                 XtSetArg(al[ac], XtNsensitive, val->enabled);
836                 ac++;
837         }
838 #else
839         XtSetArg(al[ac], XtNsensitive, True);
840         ac++;
841 #endif
842
843         XtSetArg(al[ac], XtNmappedWhenManaged, FALSE);
844         ac++;
845         XtSetArg(al[ac], XtNorientation, XtorientHorizontal);
846         ac++;
847         XtSetArg(al[ac], XtNhighlightThickness, (Dimension) 0);
848         ac++;
849         XtSetArg(al[ac], XtNntics, (Cardinal) 10);
850         ac++;
851
852         /* add any args the user supplied for creation time */
853         lw_add_value_args_to_args(val, al, &ac);
854
855         scale = XtCreateManagedWidget(val->name, gaugeWidgetClass,
856                                       instance->parent, al, ac);
857         /* add the callback */
858         if (val->call_data)
859                 XtAddCallback(scale, XtNgetValue, xaw_generic_callback,
860                               (XtPointer) instance);
861
862         XtManageChild(scale);
863
864         return scale;
865 }
866
867 #if defined(LWLIB_WIDGETS_ATHENA)
868 #define TEXT_BUFFER_SIZE 128
869 static Widget xaw_create_text_field(widget_instance * instance)
870 {
871         Arg al[20];
872         int ac = 0;
873         Widget text = 0;
874         widget_value *val = instance->info->val;
875
876         XtSetArg(al[ac], XtNsensitive, val->enabled);
877         ac++;
878         XtSetArg(al[ac], XtNmappedWhenManaged, FALSE);
879         ac++;
880         XtSetArg(al[ac], XtNhighlightThickness, (Dimension) 0);
881         ac++;
882         XtSetArg(al[ac], XtNtype, XawAsciiString);
883         ac++;
884         XtSetArg(al[ac], XtNeditType, XawtextEdit);
885         ac++;
886         XtSetArg(al[ac], XtNuseStringInPlace, False);
887         ac++;
888 #if 0
889         XtSetArg(al[ac], XtNlength, TEXT_BUFFER_SIZE);
890         ac++;
891 #endif
892         if (val->value) {
893                 XtSetArg(al[ac], XtNstring, val->value);
894                 ac++;
895         }
896
897         /* add any args the user supplied for creation time */
898         lw_add_value_args_to_args(val, al, &ac);
899
900         text = XtCreateManagedWidget(val->name, asciiTextWidgetClass,
901                                      instance->parent, al, ac);
902
903         /* add the callback */
904         if (val->call_data)
905                 XtAddCallback(text, XtNgetValue, xaw_generic_callback,
906                               (XtPointer) instance);
907
908         XtManageChild(text);
909
910         return text;
911 }
912 #endif
913
914 #endif                          /* LWLIB_WIDGETS_ATHENA */
915
916 const widget_creation_entry xaw_creation_table[] = {
917 #ifdef LWLIB_SCROLLBARS_ATHENA
918         {"vertical-scrollbar", xaw_create_vertical_scrollbar},
919         {"horizontal-scrollbar", xaw_create_horizontal_scrollbar},
920 #endif
921 #ifdef LWLIB_WIDGETS_ATHENA
922         {"button", xaw_create_button},
923         {"label", xaw_create_label_field},
924         {"text-field", xaw_create_text_field},
925         {"progress", xaw_create_progress},
926 #endif
927         {NULL, NULL}
928 };