#include "xmh.h"
#include "actions.h"
#include <X11/Xaw/Cardinals.h>
typedef struct _PopupStatus {
Widget popup;
struct _LastInput lastInput;
char* shell_command;
} PopupStatusRec, *PopupStatus;
static String XmhNconfirm = "confirm";
static String XmhNdialog = "dialog";
static String XmhNerror = "error";
static String XmhNnotice = "notice";
static String XmhNokay = "okay";
static String XmhNprompt = "prompt";
static String XmhNvalue = "value";
static void DeterminePopupPosition(
Position *x_ptr,
Position *y_ptr,
Widget *transFor_return)
{
if (lastInput.win != (Window) -1) {
if (transFor_return) {
Widget source;
source = XtWindowToWidget(XtDisplay(toplevel), lastInput.win);
while (source && !XtIsWMShell(source))
source = XtParent(source);
*transFor_return = source;
}
*x_ptr = lastInput.x;
*y_ptr = lastInput.y;
} else {
Widget source;
int i = 0;
Dimension width, height;
Arg args[2];
while (i < numScrns && !scrnList[i]->mapped)
i++;
source = ((i < numScrns) ? scrnList[i]->parent : toplevel);
XtSetArg(args[0], XtNwidth, &width);
XtSetArg(args[1], XtNheight, &height);
XtGetValues(source, args, TWO);
XtTranslateCoords(source, (Position) (width / 2),
(Position) (height / 2), x_ptr, y_ptr);
if (transFor_return) *transFor_return = source;
}
}
static Boolean PositionThePopup(
Widget popup,
Position x,
Position y)
{
Arg args[4];
String top_geom, pop_geom;
XtSetArg( args[0], XtNgeometry, &top_geom );
XtGetValues( toplevel, args, ONE );
XtSetArg( args[0], XtNgeometry, &pop_geom );
XtGetValues( popup, args, ONE );
if (pop_geom == NULL || pop_geom == top_geom) {
XtSetArg( args[0], XtNgeometry, (String) NULL);
XtSetArg( args[1], XtNx, x);
XtSetArg( args[2], XtNy, y);
XtSetArg( args[3], XtNwinGravity, SouthWestGravity);
XtSetValues( popup, args, FOUR);
return False;
}
return True;
}
static void CenterPopupPosition(
Widget widget,
Widget popup,
Position px,
Position py)
{
Position x, y;
Position nx, ny;
Arg args[3];
if (widget == NULL) return;
XtSetArg(args[0], XtNx, &x);
XtSetArg(args[1], XtNy, &y);
XtGetValues(popup, args, TWO);
if (x == px && y == py) {
nx = (GetWidth(widget) - GetWidth(popup)) / 2;
ny = (GetHeight(widget) - GetHeight(popup)) / 2;
if (nx < 0) nx = 0;
if (ny < 0) ny = 0;
XtTranslateCoords(widget, nx, ny, &x, &y);
XtSetArg(args[0], XtNx, x);
XtSetArg(args[1], XtNy, y);
XtSetArg(args[2], XtNwinGravity, CenterGravity);
XtSetValues(popup, args, THREE);
}
}
static void InsureVisibility(
Widget popup,
Widget popup_child,
Position x,
Position y,
Boolean centerX,
Boolean centerY)
{
Position root_x, root_y;
Dimension width, height, border;
Arg args[3];
XtSetArg( args[0], XtNwidth, &width );
XtSetArg( args[1], XtNheight, &height );
XtSetArg( args[2], XtNborderWidth, &border );
XtGetValues( popup, args, THREE );
XtTranslateCoords(popup_child, (Position)0, (Position)0, &root_x, &root_y);
if (centerX) root_x -= width/2 + border;
if (centerY) root_y -= height/2 + border;
if (root_x < 0) root_x = 0;
if (root_y < 0) root_y = 0;
border <<= 1;
if ((int)(root_x + width + border) > WidthOfScreen(XtScreen(toplevel))) {
root_x = WidthOfScreen(XtScreen(toplevel)) - width - border;
}
if ((int)(root_y + height + border) > HeightOfScreen(XtScreen(toplevel))) {
root_y = HeightOfScreen(XtScreen(toplevel)) - height - border;
}
if (root_x != x || root_y != y) {
XtSetArg( args[0], XtNx, root_x );
XtSetArg( args[1], XtNy, root_y );
XtSetValues( popup, args, TWO );
}
}
void DestroyPopup(
Widget widget,
XtPointer client_data,
XtPointer call_data)
{
Widget popup = (Widget) client_data;
XtPopdown(popup);
XtDestroyWidget(popup);
}
void WMDeletePopup(
Widget popup,
XEvent* event)
{
String shellName;
String buttonName;
Widget button;
shellName = XtName(popup);
if (strcmp(shellName, XmhNconfirm) == 0)
buttonName = "*no";
else if (strcmp(shellName, XmhNprompt) == 0)
buttonName = "*cancel";
else if (strcmp(shellName, XmhNnotice) == 0)
buttonName = "*confirm";
else if (strcmp(shellName, XmhNerror) == 0)
buttonName = "*OK";
else
return;
button = XtNameToWidget(popup, buttonName);
if (! button) return;
XtCallActionProc(button, "set", event, (String*)NULL, ZERO);
XtCallActionProc(button, "notify", event, (String*)NULL, ZERO);
XtCallActionProc(button, "unset", event, (String*)NULL, ZERO);
}
static void TheUsual(
Widget popup)
{
XtInstallAllAccelerators(popup, popup);
XtAugmentTranslations(popup, app_resources.wm_protocols_translations);
XtRealizeWidget(popup);
XDefineCursor(XtDisplay(popup), XtWindow(popup), app_resources.cursor);
(void) XSetWMProtocols(XtDisplay(popup), XtWindow(popup),
protocolList, XtNumber(protocolList));
}
void XmhPromptOkayAction(
Widget w,
XEvent *event,
String *params,
Cardinal *num_params)
{
XtCallCallbacks(XtNameToWidget(XtParent(w), XmhNokay), XtNcallback,
(XtPointer)XtParent(w));
}
void PopupPrompt(
Widget transientFor,
String question,
XtCallbackProc okayCallback)
{
Widget popup;
Widget dialog;
Widget value;
Position x, y;
Boolean positioned;
Arg args[3];
static XtTranslations PromptTextTranslations = NULL;
DeterminePopupPosition(&x, &y, (Widget*)NULL);
XtSetArg(args[0], XtNallowShellResize, True);
XtSetArg(args[1], XtNinput, True);
XtSetArg(args[2], XtNtransientFor, transientFor);
popup = XtCreatePopupShell(XmhNprompt, transientShellWidgetClass, toplevel,
args, THREE);
positioned = PositionThePopup(popup, x, y);
XtSetArg(args[0], XtNlabel, question);
XtSetArg(args[1], XtNvalue, "");
dialog = XtCreateManagedWidget(XmhNdialog, dialogWidgetClass, popup, args,
TWO);
XtSetArg(args[0], XtNresizable, True);
XtSetValues( XtNameToWidget(dialog, "label"), args, ONE);
value = XtNameToWidget(dialog, XmhNvalue);
XtSetValues( value, args, ONE);
if (! PromptTextTranslations)
PromptTextTranslations = XtParseTranslationTable
("<Key>Return: XmhPromptOkayAction()\n\
Ctrl<Key>R: no-op(RingBell)\n\
Ctrl<Key>S: no-op(RingBell)\n");
XtOverrideTranslations(value, PromptTextTranslations);
XawDialogAddButton(dialog, XmhNokay, okayCallback, (XtPointer) dialog);
XawDialogAddButton(dialog, "cancel", DestroyPopup, (XtPointer) popup);
TheUsual(popup);
InsureVisibility(popup, dialog, x, y, !positioned, False);
XtPopup(popup, XtGrabNone);
}
static void FreePopupStatus(
Widget w,
XtPointer closure,
XtPointer call_data)
{
PopupStatus popup = (PopupStatus)closure;
XtPopdown(popup->popup);
XtDestroyWidget(popup->popup);
if (popup->shell_command)
XtFree(popup->shell_command);
XtFree((char *) closure);
}
void PopupNotice(
String message,
XtCallbackProc callback,
XtPointer closure)
{
PopupStatus popup_status = (PopupStatus)closure;
Widget transientFor;
Widget dialog;
Widget value;
Position x, y;
Arg args[3];
char command[65], label[128];
if (popup_status == (PopupStatus)NULL) {
popup_status = XtNew(PopupStatusRec);
popup_status->lastInput = lastInput;
popup_status->shell_command = (char*)NULL;
}
if (! popup_status->shell_command) {
if (sscanf( message, "%64s", command ) != 1)
(void) strcpy( command, "system" );
else {
int l = strlen(command);
if (l && command[--l] == ':')
command[l] = '\0';
}
(void) sprintf( label, "%.64s command returned:", command );
} else {
int len = strlen(popup_status->shell_command);
(void) sprintf(label, "%.88s %s\nshell command returned:",
popup_status->shell_command,
((len > 88) ? "[truncated]" : ""));
}
DeterminePopupPosition(&x, &y, &transientFor);
XtSetArg( args[0], XtNallowShellResize, True );
XtSetArg( args[1], XtNinput, True );
XtSetArg( args[2], XtNtransientFor, transientFor);
popup_status->popup = XtCreatePopupShell(XmhNnotice,
transientShellWidgetClass, toplevel, args, THREE);
PositionThePopup(popup_status->popup, x, y);
XtSetArg( args[0], XtNlabel, label );
XtSetArg( args[1], XtNvalue, message );
dialog = XtCreateManagedWidget(XmhNdialog, dialogWidgetClass,
popup_status->popup, args, TWO);
value = XtNameToWidget(dialog, XmhNvalue);
XtSetArg( args[0], XtNeditType, XawtextRead);
XtSetArg( args[1], XtNdisplayCaret, False);
XtSetValues( value, args, TWO);
XtOverrideTranslations(value, NoTextSearchAndReplace);
XawDialogAddButton( dialog, XmhNconfirm,
((callback != (XtCallbackProc) NULL)
? callback : (XtCallbackProc) FreePopupStatus),
(XtPointer) popup_status
);
TheUsual(popup_status->popup);
InsureVisibility(popup_status->popup, dialog, x, y, False, False);
XtPopup(popup_status->popup, XtGrabNone);
}
void PopupConfirm(
Widget center_widget,
String question,
XtCallbackList affirm_callbacks,
XtCallbackList negate_callbacks)
{
Widget popup;
Widget dialog;
Widget button;
Widget transientFor;
Position x, y;
Arg args[3];
static XtCallbackRec callbacks[] = {
{DestroyPopup, (XtPointer) NULL},
{(XtCallbackProc) NULL, (XtPointer) NULL}
};
DeterminePopupPosition(&x, &y, &transientFor);
XtSetArg(args[0], XtNinput, True);
XtSetArg(args[1], XtNallowShellResize, True);
XtSetArg(args[2], XtNtransientFor, transientFor);
popup = XtCreatePopupShell(XmhNconfirm, transientShellWidgetClass,
toplevel, args, THREE);
PositionThePopup(popup, x, y);
XtSetArg(args[0], XtNlabel, question);
dialog = XtCreateManagedWidget(XmhNdialog, dialogWidgetClass, popup, args,
ONE);
callbacks[0].closure = (XtPointer) popup;
XtSetArg(args[0], XtNcallback, callbacks);
button = XtCreateManagedWidget("yes", commandWidgetClass, dialog,
args, ONE);
if (affirm_callbacks)
XtAddCallbacks(button, XtNcallback, affirm_callbacks);
button = XtCreateManagedWidget("no", commandWidgetClass, dialog,
args, ZERO);
XtAddCallback(button, XtNcallback, DestroyPopup, (XtPointer) popup);
if (negate_callbacks)
XtAddCallbacks(button, XtNcallback, negate_callbacks);
TheUsual(popup);
CenterPopupPosition(center_widget ? center_widget : transientFor,
popup, x, y);
InsureVisibility(popup, dialog, x, y, False, False);
XtPopup(popup, XtGrabNone);
}
void PopupError(
Widget widget,
String message)
{
Widget transFor, error_popup, dialog;
Position x, y;
Boolean positioned;
Arg args[3];
static XtCallbackRec callbacks[] = {
{DestroyPopup, (XtPointer) NULL},
{(XtCallbackProc) NULL, (XtPointer) NULL}
};
transFor = widget;
DeterminePopupPosition(&x, &y, transFor ? (Widget*)NULL : &transFor);
XtSetArg(args[0], XtNallowShellResize, True);
XtSetArg(args[1], XtNinput, True);
XtSetArg(args[2], XtNtransientFor, transFor);
error_popup = XtCreatePopupShell(XmhNerror, transientShellWidgetClass,
toplevel, args, THREE);
positioned = PositionThePopup(error_popup, x, y);
XtSetArg(args[0], XtNlabel, message);
dialog = XtCreateManagedWidget(XmhNdialog, dialogWidgetClass, error_popup,
args, ONE);
callbacks[0].closure = (XtPointer) error_popup;
XtSetArg(args[0], XtNcallback, callbacks);
XawDialogAddButton(dialog, "OK", DestroyPopup, (XtPointer) error_popup);
TheUsual(error_popup);
InsureVisibility(error_popup, dialog, x, y, !positioned, !positioned);
XtPopup(error_popup, XtGrabNone);
}
void PopupWarningHandler(
String name,
String type,
String class,
String msg,
String *params,
Cardinal *num)
{
char *ptr;
int i;
String par[10];
char message[500];
char buffer[500];
static Boolean allowPopup = True;
XtGetErrorDatabaseText(name, type, class, msg, buffer, 500);
if (params && num && *num) {
i = (*num <= 10) ? *num : 10;
memmove( (char*)par, (char*)params, i * sizeof(String));
bzero( &par[i], (10-i) * sizeof(String));
if (*num > 10)
par[9] = "(truncated)";
(void) sprintf(message, buffer, par[0], par[1], par[2], par[3],
par[4], par[5], par[6], par[7], par[8], par[9]);
ptr = message;
} else {
ptr = buffer;
}
if (allowPopup) {
allowPopup = False;
PopupError((Widget)NULL, ptr);
allowPopup = True;
} else {
fprintf(stderr, ptr);
}
}