Files
nethack/win/X11/winmisc.c
nethack.allison 742e1e8c90 3.3.2 to 3.4.0
2002-02-04 16:11:00 +00:00

911 lines
24 KiB
C

/* SCCS Id: @(#)winmisc.c 3.4 2000/05/21 */
/* Copyright (c) Dean Luick, 1992 */
/* NetHack may be freely redistributed. See license for details. */
/*
* Misc. popup windows: player selection and extended commands.
*
* + Global functions: player_selection() and get_ext_cmd().
*/
#ifndef SYSV
#define PRESERVE_NO_SYSV /* X11 include files may define SYSV */
#endif
#include <X11/Intrinsic.h>
#include <X11/StringDefs.h>
#include <X11/Shell.h>
#include <X11/Xaw/Command.h>
#include <X11/Xaw/Form.h>
#include <X11/Xaw/Label.h>
#include <X11/Xaw/Cardinals.h>
#include <X11/Xos.h> /* for index() */
#include <X11/Xatom.h>
#ifdef PRESERVE_NO_SYSV
# ifdef SYSV
# undef SYSV
# endif
# undef PRESERVE_NO_SYSV
#endif
#include "hack.h"
#include "func_tab.h"
#include "winX.h"
static Widget extended_command_popup;
static Widget extended_command_form;
static Widget *extended_commands = 0;
static int extended_command_selected; /* index of the selected command; */
static int ps_selected; /* index of selected role */
#define PS_RANDOM (-50)
#define PS_QUIT (-75)
static const char ps_randchars[] = "*@";
static const char ps_quitchars[] = "\033qQ";
#define EC_NCHARS 32
static boolean ec_active = FALSE;
static int ec_nchars = 0;
static char ec_chars[EC_NCHARS];
static Time ec_time;
static const char extended_command_translations[] =
"#override\n\
<Key>: ec_key()";
static const char player_select_translations[] =
"#override\n\
<Key>: ps_key()";
static const char race_select_translations[] =
"#override\n\
<Key>: race_key()";
static const char gend_select_translations[] =
"#override\n\
<Key>: gend_key()";
static const char algn_select_translations[] =
"#override\n\
<Key>: algn_key()";
static void NDECL(ec_dismiss);
static Widget FDECL(make_menu, (const char *,const char *,const char *,
const char *,XtCallbackProc,
const char *,XtCallbackProc,
int,const char **, Widget **,
XtCallbackProc,Widget *));
static void NDECL(init_extended_commands_popup);
static void FDECL(ps_quit, (Widget,XtPointer,XtPointer));
static void FDECL(ps_random, (Widget,XtPointer,XtPointer));
static void FDECL(ps_select, (Widget,XtPointer,XtPointer));
/* Player Selection -------------------------------------------------------- */
/* ARGSUSED */
static void
ps_quit(w, client_data, call_data)
Widget w;
XtPointer client_data, call_data;
{
ps_selected = PS_QUIT;
exit_x_event = TRUE; /* leave event loop */
}
/* ARGSUSED */
static void
ps_random(w, client_data, call_data)
Widget w;
XtPointer client_data, call_data;
{
ps_selected = PS_RANDOM;
exit_x_event = TRUE; /* leave event loop */
}
/* ARGSUSED */
static void
ps_select(w, client_data, call_data)
Widget w;
XtPointer client_data, call_data;
{
ps_selected = (int) client_data;
exit_x_event = TRUE; /* leave event loop */
}
/* ARGSUSED */
void
ps_key(w, event, params, num_params)
Widget w;
XEvent *event;
String *params;
Cardinal *num_params;
{
char ch, *mark;
char rolechars[QBUFSZ];
int i;
(void)memset(rolechars, '\0', sizeof rolechars); /* for index() */
for (i = 0; roles[i].name.m; ++i) {
ch = lowc(*roles[i].name.m);
/* if (flags.female && roles[i].name.f) ch = lowc(*roles[i].name.f); */
/* this supports at most two roles with the same first letter */
if (index(rolechars, ch)) ch = highc(ch);
rolechars[i] = ch;
}
ch = key_event_to_char((XKeyEvent *) event);
if (ch == '\0') { /* don't accept nul char/modifier event */
/* don't beep */
return;
}
mark = index(rolechars, ch);
if (!mark) mark = index(rolechars, lowc(ch));
if (!mark) mark = index(rolechars, highc(ch));
if (!mark) {
if (index(ps_randchars, ch))
ps_selected = PS_RANDOM;
else if (index(ps_quitchars, ch))
ps_selected = PS_QUIT;
else {
X11_nhbell(); /* no such class */
return;
}
} else
ps_selected = (int)(mark - rolechars);
exit_x_event = TRUE;
}
/* ARGSUSED */
void
race_key(w, event, params, num_params)
Widget w;
XEvent *event;
String *params;
Cardinal *num_params;
{
char ch, *mark;
char racechars[QBUFSZ];
int i;
(void)memset(racechars, '\0', sizeof racechars); /* for index() */
for (i = 0; races[i].noun; ++i) {
ch = lowc(*races[i].noun);
/* this supports at most two races with the same first letter */
if (index(racechars, ch)) ch = highc(ch);
racechars[i] = ch;
}
ch = key_event_to_char((XKeyEvent *) event);
if (ch == '\0') { /* don't accept nul char/modifier event */
/* don't beep */
return;
}
mark = index(racechars, ch);
if (!mark) mark = index(racechars, lowc(ch));
if (!mark) mark = index(racechars, highc(ch));
if (!mark) {
if (index(ps_randchars, ch))
ps_selected = PS_RANDOM;
else if (index(ps_quitchars, ch))
ps_selected = PS_QUIT;
else {
X11_nhbell(); /* no such race */
return;
}
} else
ps_selected = (int)(mark - racechars);
exit_x_event = TRUE;
}
/* ARGSUSED */
void
gend_key(w, event, params, num_params)
Widget w;
XEvent *event;
String *params;
Cardinal *num_params;
{
char ch, *mark;
static char gendchars[] = "mf";
ch = key_event_to_char((XKeyEvent *) event);
if (ch == '\0') { /* don't accept nul char/modifier event */
/* don't beep */
return;
}
mark = index(gendchars, ch);
if (!mark) mark = index(gendchars, lowc(ch));
if (!mark) {
if (index(ps_randchars, ch))
ps_selected = PS_RANDOM;
else if (index(ps_quitchars, ch))
ps_selected = PS_QUIT;
else {
X11_nhbell(); /* no such gender */
return;
}
} else
ps_selected = (int)(mark - gendchars);
exit_x_event = TRUE;
}
/* ARGSUSED */
void
algn_key(w, event, params, num_params)
Widget w;
XEvent *event;
String *params;
Cardinal *num_params;
{
char ch, *mark;
static char algnchars[] = "LNC";
ch = key_event_to_char((XKeyEvent *) event);
if (ch == '\0') { /* don't accept nul char/modifier event */
/* don't beep */
return;
}
mark = index(algnchars, ch);
if (!mark) mark = index(algnchars, highc(ch));
if (!mark) {
if (index(ps_randchars, ch))
ps_selected = PS_RANDOM;
else if (index(ps_quitchars, ch))
ps_selected = PS_QUIT;
else {
X11_nhbell(); /* no such alignment */
return;
}
} else
ps_selected = (int)(mark - algnchars);
exit_x_event = TRUE;
}
/* Global functions ========================================================= */
void
X11_player_selection()
{
int num_roles, num_races, num_gends, num_algns,
i, availcount, availindex;
Widget popup, player_form;
const char **choices;
char qbuf[QBUFSZ], plbuf[QBUFSZ];
/* avoid unnecessary prompts further down */
rigid_role_checks();
(void) root_plselection_prompt(plbuf, QBUFSZ - 1,
flags.initrole, flags.initrace, flags.initgend, flags.initalign);
while (flags.initrole < 0) {
if (flags.initrole == ROLE_RANDOM || flags.randomall) {
flags.initrole = pick_role(flags.initrace,
flags.initgend, flags.initalign, PICK_RANDOM);
break;
}
/* select a role */
for (num_roles = 0; roles[num_roles].name.m; ++num_roles) continue;
choices = (const char **)alloc(sizeof(char *) * num_roles);
for (;;) {
availcount = 0;
for (i = 0; i < num_roles; i++) {
choices[i] = 0;
if (ok_role(i, flags.initrace,
flags.initgend, flags.initalign)) {
choices[i] = roles[i].name.m;
if (flags.initgend >= 0 && flags.female && roles[i].name.f)
choices[i] = roles[i].name.f;
++availcount;
}
}
if (availcount > 0) break;
else if (flags.initalign >= 0) flags.initalign = -1; /* reset */
else if (flags.initgend >= 0) flags.initgend = -1;
else if (flags.initrace >= 0) flags.initrace = -1;
else panic("no available ROLE+race+gender+alignment combinations");
}
Sprintf(qbuf, "Choose your %s Role", s_suffix(plbuf));
popup = make_menu("player_selection", qbuf,
player_select_translations,
"quit", ps_quit,
"random", ps_random,
num_roles, choices, (Widget **)0, ps_select, &player_form);
ps_selected = -1;
positionpopup(popup, FALSE);
nh_XtPopup(popup, (int)XtGrabExclusive, player_form);
/* The callbacks will enable the event loop exit. */
(void) x_event(EXIT_ON_EXIT);
nh_XtPopdown(popup);
XtDestroyWidget(popup);
free((genericptr_t)choices), choices = 0;
if (ps_selected == PS_QUIT) {
clearlocks();
X11_exit_nhwindows((char *)0);
terminate(0);
} else if (ps_selected == PS_RANDOM) {
flags.initrole = ROLE_RANDOM;
} else if (ps_selected < 0 || ps_selected >= num_roles) {
panic("player_selection: bad role select value %d\n", ps_selected);
} else {
flags.initrole = ps_selected;
}
}
(void) root_plselection_prompt(plbuf, QBUFSZ - 1,
flags.initrole, flags.initrace, flags.initgend, flags.initalign);
while (!validrace(flags.initrole, flags.initrace)) {
if (flags.initrace == ROLE_RANDOM || flags.randomall) {
flags.initrace = pick_race(flags.initrole,
flags.initgend, flags.initalign, PICK_RANDOM);
break;
}
/* select a race */
for (num_races = 0; races[num_races].noun; ++num_races) continue;
choices = (const char **)alloc(sizeof(char *) * num_races);
for (;;) {
availcount = availindex = 0;
for (i = 0; i < num_races; i++) {
choices[i] = 0;
if (ok_race(flags.initrole, i,
flags.initgend, flags.initalign)) {
choices[i] = races[i].noun;
++availcount;
availindex = i; /* used iff only one */
}
}
if (availcount > 0) break;
else if (flags.initalign >= 0) flags.initalign = -1; /* reset */
else if (flags.initgend >= 0) flags.initgend = -1;
else panic("no available role+RACE+gender+alignment combinations");
}
if (availcount == 1) {
flags.initrace = availindex;
free((genericptr_t)choices), choices = 0;
} else {
Sprintf(qbuf, "Pick your %s race", s_suffix(plbuf));
popup = make_menu("race_selection", qbuf,
race_select_translations,
"quit", ps_quit,
"random", ps_random,
num_races, choices, (Widget **)0,
ps_select, &player_form);
ps_selected = -1;
positionpopup(popup, FALSE);
nh_XtPopup(popup, (int)XtGrabExclusive, player_form);
/* The callbacks will enable the event loop exit. */
(void) x_event(EXIT_ON_EXIT);
nh_XtPopdown(popup);
XtDestroyWidget(popup);
free((genericptr_t)choices), choices = 0;
if (ps_selected == PS_QUIT) {
clearlocks();
X11_exit_nhwindows((char *)0);
terminate(0);
} else if (ps_selected == PS_RANDOM) {
flags.initrace = ROLE_RANDOM;
} else if (ps_selected < 0 || ps_selected >= num_races) {
panic("player_selection: bad race select value %d\n", ps_selected);
} else {
flags.initrace = ps_selected;
}
} /* more than one race choice available */
}
(void) root_plselection_prompt(plbuf, QBUFSZ - 1,
flags.initrole, flags.initrace, flags.initgend, flags.initalign);
while (!validgend(flags.initrole, flags.initrace, flags.initgend)) {
if (flags.initgend == ROLE_RANDOM || flags.randomall) {
flags.initgend = pick_gend(flags.initrole, flags.initrace,
flags.initalign, PICK_RANDOM);
break;
}
/* select a gender */
num_gends = 2; /* genders[2] isn't allowed */
choices = (const char **)alloc(sizeof(char *) * num_gends);
for (;;) {
availcount = availindex = 0;
for (i = 0; i < num_gends; i++) {
choices[i] = 0;
if (ok_gend(flags.initrole, flags.initrace,
i, flags.initalign)) {
choices[i] = genders[i].adj;
++availcount;
availindex = i; /* used iff only one */
}
}
if (availcount > 0) break;
else if (flags.initalign >= 0) flags.initalign = -1; /* reset */
else panic("no available role+race+GENDER+alignment combinations");
}
if (availcount == 1) {
flags.initgend = availindex;
free((genericptr_t)choices), choices = 0;
} else {
Sprintf(qbuf, "Your %s gender?", s_suffix(plbuf));
popup = make_menu("gender_selection", qbuf,
gend_select_translations,
"quit", ps_quit,
"random", ps_random,
num_gends, choices, (Widget **)0,
ps_select, &player_form);
ps_selected = -1;
positionpopup(popup, FALSE);
nh_XtPopup(popup, (int)XtGrabExclusive, player_form);
/* The callbacks will enable the event loop exit. */
(void) x_event(EXIT_ON_EXIT);
nh_XtPopdown(popup);
XtDestroyWidget(popup);
free((genericptr_t)choices), choices = 0;
if (ps_selected == PS_QUIT) {
clearlocks();
X11_exit_nhwindows((char *)0);
terminate(0);
} else if (ps_selected == PS_RANDOM) {
flags.initgend = ROLE_RANDOM;
} else if (ps_selected < 0 || ps_selected >= num_gends) {
panic("player_selection: bad gender select value %d\n", ps_selected);
} else {
flags.initgend = ps_selected;
}
} /* more than one gender choice available */
}
(void) root_plselection_prompt(plbuf, QBUFSZ - 1,
flags.initrole, flags.initrace, flags.initgend, flags.initalign);
while (!validalign(flags.initrole, flags.initrace, flags.initalign)) {
if (flags.initalign == ROLE_RANDOM || flags.randomall) {
flags.initalign = pick_align(flags.initrole, flags.initrace,
flags.initgend, PICK_RANDOM);
break;
}
/* select an alignment */
num_algns = 3; /* aligns[3] isn't allowed */
choices = (const char **)alloc(sizeof(char *) * num_algns);
for (;;) {
availcount = availindex = 0;
for (i = 0; i < num_algns; i++) {
choices[i] = 0;
if (ok_align(flags.initrole, flags.initrace,
flags.initgend, i)) {
choices[i] = aligns[i].adj;
++availcount;
availindex = i; /* used iff only one */
}
}
if (availcount > 0) break;
else panic("no available role+race+gender+ALIGNMENT combinations");
}
if (availcount == 1) {
flags.initalign = availindex;
free((genericptr_t)choices), choices = 0;
} else {
Sprintf(qbuf, "Your %s alignment?", s_suffix(plbuf));
popup = make_menu("alignment_selection", qbuf,
algn_select_translations,
"quit", ps_quit,
"random", ps_random,
num_algns, choices, (Widget **)0,
ps_select, &player_form);
ps_selected = -1;
positionpopup(popup, FALSE);
nh_XtPopup(popup, (int)XtGrabExclusive, player_form);
/* The callbacks will enable the event loop exit. */
(void) x_event(EXIT_ON_EXIT);
nh_XtPopdown(popup);
XtDestroyWidget(popup);
free((genericptr_t)choices), choices = 0;
if (ps_selected == PS_QUIT) {
clearlocks();
X11_exit_nhwindows((char *)0);
terminate(0);
} else if (ps_selected == PS_RANDOM) {
flags.initalign = ROLE_RANDOM;
} else if (ps_selected < 0 || ps_selected >= num_algns) {
panic("player_selection: bad alignment select value %d\n", ps_selected);
} else {
flags.initalign = ps_selected;
}
} /* more than one alignment choice available */
}
}
int
X11_get_ext_cmd()
{
static Boolean initialized = False;
if (!initialized) {
init_extended_commands_popup();
initialized = True;
}
extended_command_selected = -1; /* reset selected value */
positionpopup(extended_command_popup, FALSE); /* center on cursor */
nh_XtPopup(extended_command_popup, (int)XtGrabExclusive,
extended_command_form);
/* The callbacks will enable the event loop exit. */
(void) x_event(EXIT_ON_EXIT);
return extended_command_selected;
}
/* End global functions ===================================================== */
/* Extended Command -------------------------------------------------------- */
/* ARGSUSED */
static void
extend_select(w, client_data, call_data)
Widget w;
XtPointer client_data, call_data;
{
int selected = (int) client_data;
if (extended_command_selected != selected) {
/* visibly deselect old one */
if (extended_command_selected >= 0)
swap_fg_bg(extended_commands[extended_command_selected]);
/* select new one */
swap_fg_bg(extended_commands[selected]);
extended_command_selected = selected;
}
nh_XtPopdown(extended_command_popup);
/* reset colors while popped down */
swap_fg_bg(extended_commands[extended_command_selected]);
ec_active = FALSE;
exit_x_event = TRUE; /* leave event loop */
}
/* ARGSUSED */
static void
extend_dismiss(w, client_data, call_data)
Widget w;
XtPointer client_data, call_data;
{
ec_dismiss();
}
/* ARGSUSED */
static void
extend_help(w, client_data, call_data)
Widget w;
XtPointer client_data, call_data;
{
/* We might need to make it known that we already have one listed. */
(void) doextlist();
}
/* ARGSUSED */
void
ec_delete(w, event, params, num_params)
Widget w;
XEvent *event;
String *params;
Cardinal *num_params;
{
ec_dismiss();
}
static void
ec_dismiss()
{
/* unselect while still visible */
if (extended_command_selected >= 0)
swap_fg_bg(extended_commands[extended_command_selected]);
extended_command_selected = -1; /* dismiss */
nh_XtPopdown(extended_command_popup);
ec_active = FALSE;
exit_x_event = TRUE; /* leave event loop */
}
/* ARGSUSED */
void
ec_key(w, event, params, num_params)
Widget w;
XEvent *event;
String *params;
Cardinal *num_params;
{
char ch;
int i;
XKeyEvent *xkey = (XKeyEvent *) event;
ch = key_event_to_char(xkey);
if (ch == '\0') { /* don't accept nul char/modifier event */
/* don't beep */
return;
} else if (index("\033\n\r", ch)) {
if (ch == '\033') {
/* unselect while still visible */
if (extended_command_selected >= 0)
swap_fg_bg(extended_commands[extended_command_selected]);
extended_command_selected = -1; /* dismiss */
}
nh_XtPopdown(extended_command_popup);
/* unselect while invisible */
if (extended_command_selected >= 0)
swap_fg_bg(extended_commands[extended_command_selected]);
exit_x_event = TRUE; /* leave event loop */
ec_active = FALSE;
return;
}
/* too much time has elapsed */
if ((xkey->time - ec_time) > 500)
ec_active = FALSE;
if (!ec_active) {
ec_nchars = 0;
ec_active = TRUE;
}
ec_time = xkey->time;
ec_chars[ec_nchars++] = ch;
if (ec_nchars >= EC_NCHARS)
ec_nchars = EC_NCHARS-1; /* don't overflow */
for (i = 0; extcmdlist[i].ef_txt; i++) {
if (extcmdlist[i].ef_txt[0] == '?') continue;
if (!strncmp(ec_chars, extcmdlist[i].ef_txt, ec_nchars)) {
if (extended_command_selected != i) {
/* I should use set() and unset() actions, but how do */
/* I send the an action to the widget? */
if (extended_command_selected >= 0)
swap_fg_bg(extended_commands[extended_command_selected]);
extended_command_selected = i;
swap_fg_bg(extended_commands[extended_command_selected]);
}
break;
}
}
}
/*
* Use our own home-brewed version menu because simpleMenu is designed to
* be used from a menubox.
*/
static void
init_extended_commands_popup()
{
int i, num_commands;
const char **command_list;
/* count commands */
for (num_commands = 0; extcmdlist[num_commands].ef_txt; num_commands++)
; /* do nothing */
/* If the last entry is "help", don't use it. */
if (strcmp(extcmdlist[num_commands-1].ef_txt, "?") == 0)
--num_commands;
command_list =
(const char **) alloc((unsigned)num_commands * sizeof(char *));
for (i = 0; i < num_commands; i++)
command_list[i] = extcmdlist[i].ef_txt;
extended_command_popup = make_menu("extended_commands",
"Extended Commands",
extended_command_translations,
"dismiss", extend_dismiss,
"help", extend_help,
num_commands, command_list, &extended_commands,
extend_select, &extended_command_form);
free((char *)command_list);
}
/* ------------------------------------------------------------------------- */
/*
* Create a popup widget of the following form:
*
* popup_label
* ----------- ------------
* |left_name| |right_name|
* ----------- ------------
* ------------------------
* | name1 |
* ------------------------
* ------------------------
* | name2 |
* ------------------------
* .
* .
* ------------------------
* | nameN |
* ------------------------
*/
static Widget
make_menu(popup_name, popup_label, popup_translations,
left_name, left_callback,
right_name, right_callback,
num_names, widget_names, command_widgets, name_callback, formp)
const char *popup_name;
const char *popup_label;
const char *popup_translations;
const char *left_name;
XtCallbackProc left_callback;
const char *right_name;
XtCallbackProc right_callback;
int num_names;
const char **widget_names; /* return array of command widgets */
Widget **command_widgets;
XtCallbackProc name_callback;
Widget *formp; /* return */
{
Widget popup, form, label, above, left, right;
Widget *commands, *curr;
int i;
Arg args[8];
Cardinal num_args;
Dimension width, max_width;
int distance, skip;
commands = (Widget *) alloc((unsigned)num_names * sizeof(Widget));
num_args = 0;
XtSetArg(args[num_args], XtNallowShellResize, True); num_args++;
popup = XtCreatePopupShell(popup_name,
transientShellWidgetClass,
toplevel, args, num_args);
XtOverrideTranslations(popup,
XtParseTranslationTable("<Message>WM_PROTOCOLS: ec_delete()"));
num_args = 0;
XtSetArg(args[num_args], XtNtranslations,
XtParseTranslationTable(popup_translations)); num_args++;
*formp = form = XtCreateManagedWidget("menuform",
formWidgetClass,
popup,
args, num_args);
/* Get the default distance between objects in the form widget. */
num_args = 0;
XtSetArg(args[num_args], XtNdefaultDistance, &distance); num_args++;
XtGetValues(form, args, num_args);
/*
* Create the label.
*/
num_args = 0;
XtSetArg(args[num_args], XtNborderWidth, 0); num_args++;
label = XtCreateManagedWidget(popup_label,
labelWidgetClass,
form,
args, num_args);
/*
* Create the left button.
*/
num_args = 0;
XtSetArg(args[num_args], XtNfromVert, label); num_args++;
/*
XtSetArg(args[num_args], XtNshapeStyle,
XmuShapeRoundedRectangle); num_args++;
*/
left = XtCreateManagedWidget(left_name,
commandWidgetClass,
form,
args, num_args);
XtAddCallback(left, XtNcallback, left_callback, (XtPointer) 0);
skip = 3*distance; /* triple the spacing */
if(!skip) skip = 3;
/*
* Create right button.
*/
num_args = 0;
XtSetArg(args[num_args], XtNfromHoriz, left); num_args++;
XtSetArg(args[num_args], XtNfromVert, label); num_args++;
/*
XtSetArg(args[num_args], XtNshapeStyle,
XmuShapeRoundedRectangle); num_args++;
*/
right = XtCreateManagedWidget(right_name,
commandWidgetClass,
form,
args, num_args);
XtAddCallback(right, XtNcallback, right_callback, (XtPointer) 0);
XtInstallAccelerators(form, left);
XtInstallAccelerators(form, right);
/*
* Create and place the command widgets.
*/
for (i = 0, above = left, curr = commands; i < num_names; i++) {
if (!widget_names[i]) continue;
num_args = 0;
XtSetArg(args[num_args], XtNfromVert, above); num_args++;
if (above == left) {
/* if first, we are farther apart */
XtSetArg(args[num_args], XtNvertDistance, skip); num_args++;
}
*curr = XtCreateManagedWidget(widget_names[i],
commandWidgetClass,
form,
args, num_args);
XtAddCallback(*curr, XtNcallback, name_callback, (XtPointer) i);
above = *curr++;
}
/*
* Now find the largest width. Start with the width dismiss + help
* buttons, since they are adjacent.
*/
XtSetArg(args[0], XtNwidth, &max_width);
XtGetValues(left, args, ONE);
XtSetArg(args[0], XtNwidth, &width);
XtGetValues(right, args, ONE);
max_width = max_width + width + distance;
/* Next, the title. */
XtSetArg(args[0], XtNwidth, &width);
XtGetValues(label, args, ONE);
if (width > max_width) max_width = width;
/* Finally, the commands. */
for (i = 0, curr = commands; i < num_names; i++) {
if (!widget_names[i]) continue;
XtSetArg(args[0], XtNwidth, &width);
XtGetValues(*curr, args, ONE);
if (width > max_width) max_width = width;
curr++;
}
/*
* Finally, set all of the single line widgets to the largest width.
*/
XtSetArg(args[0], XtNwidth, max_width);
XtSetValues(label, args, ONE);
for (i = 0, curr = commands; i < num_names; i++) {
if (!widget_names[i]) continue;
XtSetArg(args[0], XtNwidth, max_width);
XtSetValues(*curr, args, ONE);
curr++;
}
if (command_widgets)
*command_widgets = commands;
else
free((char *) commands);
XtRealizeWidget(popup);
XSetWMProtocols(XtDisplay(popup), XtWindow(popup), &wm_delete_window, 1);
return popup;
}