#include <X11/Intrinsic.h>
#include <X11/StringDefs.h>
#include <stdio.h>
#include <stdlib.h>
#include <X11/Shell.h>
#include <X11/Xaw/Form.h>
#include <X11/Xaw/AsciiText.h>
#include <X11/Xaw/Command.h>
#include <X11/Xaw/Label.h>
#include <X11/Xaw/Scrollbar.h>
#include "xmessage.h"
typedef struct _ButtonRecord {
char *name;
int exitstatus;
Boolean print_value;
Widget widget;
} ButtonRecord;
static void
unquote_pairs (ButtonRecord *br, int n)
{
int i;
for (i = 0; i < n; i++) {
char *dst, *src;
int quoted = 0;
for (src = dst = br->name; *src; src++) {
if (quoted) {
*dst++ = *src;
quoted = 0;
} else if (src[0] == '\\') {
quoted = 1;
} else {
*dst++ = *src;
}
}
*dst = '\0';
}
return;
}
static int
parse_name_and_exit_code_list (char *buttonlist, ButtonRecord **brptr)
{
char *cp;
int shouldfind = 0, npairs = 0;
int default_exitcode = 100;
int quoted = 0;
ButtonRecord *br;
int len;
char *copy;
if (!buttonlist) return 0;
if (buttonlist[0]) shouldfind++;
for (cp = buttonlist; *cp; cp++) {
if (quoted == 1) quoted = 0;
else if (*cp == '\\') quoted = 1;
else if (*cp == ',') shouldfind++;
}
len = (cp - buttonlist);
br = (ButtonRecord *) malloc (sizeof(ButtonRecord) * shouldfind);
if (!br) return -1;
cp = malloc (len + 1);
if (!cp) {
(void) free ((char *) br);
return -1;
}
copy = cp;
strcpy (copy, buttonlist);
while (*cp) {
char *start, *colon, *comma;
int exitcode;
start = cp;
colon = comma = NULL;
exitcode = ++default_exitcode;
quoted = 0;
for (; *cp; cp++) {
if (quoted) quoted = 0;
else if (*cp == '\\') quoted = 1;
else if (*cp == ':') colon = cp;
else if (*cp == ',') {
comma = cp;
break;
}
}
if (comma) *comma = '\0';
if (colon) {
exitcode = atoi (colon+1);
*colon = '\0';
}
if (npairs >= shouldfind) {
fprintf (stderr,
"%s: internal error, found extra pairs (should be %d)\n",
ProgramName, shouldfind);
(void) free ((char *) br);
(void) free (copy);
return -1;
}
br[npairs].name = start;
br[npairs].exitstatus = exitcode;
npairs++;
if (comma) cp++;
}
if (npairs != shouldfind) {
fprintf (stderr, "%s: internal error found %d instead of %d pairs\n",
ProgramName, npairs, shouldfind);
(void) free ((char *) br);
(void) free (copy);
return -1;
}
unquote_pairs (br, npairs);
*brptr = br;
return npairs;
}
static void
handle_button (Widget w, XtPointer closure, XtPointer client_data)
{
ButtonRecord *br = (ButtonRecord *) closure;
if (br->print_value)
puts (br->name);
exit (br->exitstatus);
}
Widget
make_queryform(Widget parent,
char *msgstr,
int msglen,
char *button_list,
Boolean print_value,
char *default_button,
Dimension max_width,
Dimension max_height)
{
ButtonRecord *br;
int npairs, i;
Widget form, text, prev;
Arg args[10];
Cardinal n, thisn;
char *shell_geom;
int x, y, geom_flags;
unsigned int shell_w, shell_h;
npairs = parse_name_and_exit_code_list (button_list, &br);
form = XtCreateManagedWidget ("form", formWidgetClass, parent, NULL, 0);
text = XtVaCreateManagedWidget
("message", asciiTextWidgetClass, form,
XtNleft, XtChainLeft,
XtNright, XtChainRight,
XtNtop, XtChainTop,
XtNbottom, XtChainBottom,
XtNdisplayCaret, False,
XtNlength, msglen,
XtNstring, msgstr,
NULL);
XtVaGetValues(parent, XtNgeometry, &shell_geom, NULL);
geom_flags = XParseGeometry(shell_geom, &x, &y, &shell_w, &shell_h);
if (!(geom_flags & WidthValue && geom_flags & HeightValue)) {
Dimension width, height, height_addons = 0;
Dimension scroll_size, border_width;
Widget label, scroll;
Position left, right, top, bottom;
char *tmp;
XtVaGetValues(text, XtNtopMargin, &top, XtNbottomMargin, &bottom,
XtNleftMargin, &left, XtNrightMargin, &right, NULL);
label = XtVaCreateWidget("message", labelWidgetClass, form,
XtNlabel, msgstr,
XtNinternalWidth, (left+right+1)/2,
XtNinternalHeight, (top+bottom+1)/2,
NULL);
XtVaGetValues(label, XtNwidth, &width, XtNheight, &height, NULL);
XtDestroyWidget(label);
if (max_width == 0)
max_width = .7 * WidthOfScreen(XtScreen(text));
if (max_height == 0)
max_height = .7 * HeightOfScreen(XtScreen(text));
if (width > max_width) {
width = max_width;
scroll = XtVaCreateWidget("hScrollbar", scrollbarWidgetClass, text,
XtNorientation, XtorientHorizontal,
NULL);
XtVaGetValues(scroll, XtNheight, &scroll_size,
XtNborderWidth, &border_width, NULL);
XtDestroyWidget(scroll);
height_addons = scroll_size + border_width;
}
tmp = msgstr;
while (tmp != NULL && *tmp) {
++tmp;
++height;
tmp = strchr(tmp, '\n');
}
if (height > max_height) {
height = max_height;
scroll = XtVaCreateWidget("vScrollbar", scrollbarWidgetClass, text,
XtNorientation, XtorientVertical, NULL);
XtVaGetValues(scroll, XtNwidth, &scroll_size,
XtNborderWidth, &border_width, NULL);
XtDestroyWidget(scroll);
width += scroll_size + border_width;
}
height += height_addons;
XtVaSetValues(text, XtNwidth, width, XtNheight, height, NULL);
}
n = 0;
XtSetArg (args[n], XtNleft, XtChainLeft); n++;
XtSetArg (args[n], XtNright, XtChainLeft); n++;
XtSetArg (args[n], XtNtop, XtChainBottom); n++;
XtSetArg (args[n], XtNbottom, XtChainBottom); n++;
XtSetArg (args[n], XtNfromVert, text); n++;
XtSetArg (args[n], XtNvertDistance, 5); n++;
prev = NULL;
for (i = 0; i < npairs; i++) {
thisn = n;
XtSetArg (args[thisn], XtNfromHoriz, prev); thisn++;
prev = XtCreateManagedWidget (br[i].name, commandWidgetClass,
form, args, thisn);
br[i].widget = prev;
br[i].print_value = print_value;
XtAddCallback (prev, XtNcallback, handle_button, (XtPointer) &br[i]);
if (default_button && !strcmp(default_button, br[i].name)) {
Dimension border;
default_exitstatus = br[i].exitstatus;
XtVaGetValues(br[i].widget, XtNborderWidth, &border, NULL);
border *= 2;
XtVaSetValues(br[i].widget, XtNborderWidth, border, NULL);
}
}
return form;
}